Update ooo320-m1
[ooovba.git] / connectivity / source / commontools / RowFunctionParser.cxx
blobfe814821e5bdb518f99326766321a3addb253e53
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: RowFunctionParser.cxx,v $
10 * $Revision: 1.3 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_connectivity.hxx"
34 // Makes parser a static resource,
35 // we're synchronized externally.
36 // But watch out, the parser might have
37 // state not visible to this code!
38 #define BOOST_SPIRIT_SINGLE_GRAMMAR_INSTANCE
39 #if defined(VERBOSE) && defined(DBG_UTIL)
40 #include <typeinfo>
41 #define BOOST_SPIRIT_DEBUG
42 #endif
43 #include <boost/spirit/include/classic_core.hpp>
44 #include "RowFunctionParser.hxx"
45 #include <rtl/ustring.hxx>
46 #include <tools/fract.hxx>
50 #if (OSL_DEBUG_LEVEL > 0)
51 #include <iostream>
52 #endif
53 #include <functional>
54 #include <algorithm>
55 #include <stack>
57 namespace connectivity
59 using namespace com::sun::star;
61 namespace
63 //////////////////////
64 //////////////////////
65 // EXPRESSION NODES
66 //////////////////////
67 //////////////////////
68 class ConstantValueExpression : public ExpressionNode
70 ORowSetValueDecoratorRef maValue;
72 public:
74 ConstantValueExpression( ORowSetValueDecoratorRef rValue ) :
75 maValue( rValue )
78 virtual ORowSetValueDecoratorRef evaluate(const ODatabaseMetaDataResultSet::ORow& /*_aRow*/ ) const
80 return maValue;
82 virtual void fill(const ODatabaseMetaDataResultSet::ORow& /*_aRow*/ ) const
85 virtual ExpressionFunct getType() const
87 return FUNC_CONST;
89 virtual ODatabaseMetaDataResultSet::ORow fillNode( std::vector< RowEquation >& /*rEquations*/, ExpressionNode* /* pOptionalArg */, sal_uInt32 /* nFlags */ )
91 ODatabaseMetaDataResultSet::ORow aRet;
92 return aRet;
97 /** ExpressionNode implementation for unary
98 function over two ExpressionNodes
100 class BinaryFunctionExpression : public ExpressionNode
102 const ExpressionFunct meFunct;
103 ExpressionNodeSharedPtr mpFirstArg;
104 ExpressionNodeSharedPtr mpSecondArg;
106 public:
108 BinaryFunctionExpression( const ExpressionFunct eFunct, const ExpressionNodeSharedPtr& rFirstArg, const ExpressionNodeSharedPtr& rSecondArg ) :
109 meFunct( eFunct ),
110 mpFirstArg( rFirstArg ),
111 mpSecondArg( rSecondArg )
114 virtual ORowSetValueDecoratorRef evaluate(const ODatabaseMetaDataResultSet::ORow& _aRow ) const
116 ORowSetValueDecoratorRef aRet;
117 switch(meFunct)
119 case ENUM_FUNC_EQUATION:
120 aRet = new ORowSetValueDecorator(sal_Bool(mpFirstArg->evaluate(_aRow )->getValue() == mpSecondArg->evaluate(_aRow )->getValue()) );
121 break;
122 case ENUM_FUNC_AND:
123 aRet = new ORowSetValueDecorator( sal_Bool(mpFirstArg->evaluate(_aRow )->getValue().getBool() && mpSecondArg->evaluate(_aRow )->getValue().getBool()) );
124 break;
125 case ENUM_FUNC_OR:
126 aRet = new ORowSetValueDecorator( sal_Bool(mpFirstArg->evaluate(_aRow )->getValue().getBool() || mpSecondArg->evaluate(_aRow )->getValue().getBool()) );
127 break;
128 default:
129 break;
131 return aRet;
133 virtual void fill(const ODatabaseMetaDataResultSet::ORow& _aRow ) const
135 switch(meFunct)
137 case ENUM_FUNC_EQUATION:
138 (*mpFirstArg->evaluate(_aRow )) = mpSecondArg->evaluate(_aRow )->getValue();
139 break;
140 default:
141 break;
144 virtual ExpressionFunct getType() const
146 return meFunct;
148 virtual ODatabaseMetaDataResultSet::ORow fillNode( std::vector< RowEquation >& /*rEquations*/, ExpressionNode* /*pOptionalArg*/, sal_uInt32 /*nFlags*/ )
150 ODatabaseMetaDataResultSet::ORow aRet;
151 return aRet;
156 ////////////////////////
157 ////////////////////////
158 // FUNCTION PARSER
159 ////////////////////////
160 ////////////////////////
162 typedef const sal_Char* StringIteratorT;
164 struct ParserContext
166 typedef ::std::stack< ExpressionNodeSharedPtr > OperandStack;
168 // stores a stack of not-yet-evaluated operands. This is used
169 // by the operators (i.e. '+', '*', 'sin' etc.) to pop their
170 // arguments from. If all arguments to an operator are constant,
171 // the operator pushes a precalculated result on the stack, and
172 // a composite ExpressionNode otherwise.
173 OperandStack maOperandStack;
176 typedef ::boost::shared_ptr< ParserContext > ParserContextSharedPtr;
178 /** Generate apriori constant value
181 class ConstantFunctor
183 ParserContextSharedPtr mpContext;
185 public:
187 ConstantFunctor( const ParserContextSharedPtr& rContext ) :
188 mpContext( rContext )
191 void operator()( StringIteratorT rFirst,StringIteratorT rSecond) const
193 rtl::OUString sVal( rFirst, rSecond - rFirst, RTL_TEXTENCODING_UTF8 );
194 mpContext->maOperandStack.push( ExpressionNodeSharedPtr( new ConstantValueExpression( new ORowSetValueDecorator( sVal ) ) ) );
198 /** Generate parse-dependent-but-then-constant value
200 class IntConstantFunctor
202 ParserContextSharedPtr mpContext;
204 public:
205 IntConstantFunctor( const ParserContextSharedPtr& rContext ) :
206 mpContext( rContext )
209 void operator()( sal_Int32 n ) const
211 mpContext->maOperandStack.push( ExpressionNodeSharedPtr( new ConstantValueExpression( new ORowSetValueDecorator( n ) ) ) );
213 void operator()( StringIteratorT rFirst,StringIteratorT rSecond) const
215 rtl::OUString sVal( rFirst, rSecond - rFirst, RTL_TEXTENCODING_UTF8 );
216 (void)sVal;
220 /** Implements a binary function over two ExpressionNodes
222 @tpl Generator
223 Generator functor, to generate an ExpressionNode of
224 appropriate type
227 class BinaryFunctionFunctor
229 const ExpressionFunct meFunct;
230 ParserContextSharedPtr mpContext;
232 public:
234 BinaryFunctionFunctor( const ExpressionFunct eFunct, const ParserContextSharedPtr& rContext ) :
235 meFunct( eFunct ),
236 mpContext( rContext )
240 void operator()( StringIteratorT, StringIteratorT ) const
242 ParserContext::OperandStack& rNodeStack( mpContext->maOperandStack );
244 if( rNodeStack.size() < 2 )
245 throw ParseError( "Not enough arguments for binary operator" );
247 // retrieve arguments
248 ExpressionNodeSharedPtr pSecondArg( rNodeStack.top() );
249 rNodeStack.pop();
250 ExpressionNodeSharedPtr pFirstArg( rNodeStack.top() );
251 rNodeStack.pop();
253 // create combined ExpressionNode
254 ExpressionNodeSharedPtr pNode = ExpressionNodeSharedPtr( new BinaryFunctionExpression( meFunct, pFirstArg, pSecondArg ) );
255 // check for constness
256 rNodeStack.push( pNode );
259 /** ExpressionNode implementation for unary
260 function over one ExpressionNode
262 class UnaryFunctionExpression : public ExpressionNode
264 const ExpressionFunct meFunct;
265 ExpressionNodeSharedPtr mpArg;
267 public:
268 UnaryFunctionExpression( const ExpressionFunct eFunct, const ExpressionNodeSharedPtr& rArg ) :
269 meFunct( eFunct ),
270 mpArg( rArg )
273 virtual ORowSetValueDecoratorRef evaluate(const ODatabaseMetaDataResultSet::ORow& _aRow ) const
275 return _aRow[mpArg->evaluate(_aRow )->getValue().getInt32()];
277 virtual void fill(const ODatabaseMetaDataResultSet::ORow& /*_aRow*/ ) const
280 virtual ExpressionFunct getType() const
282 return meFunct;
284 virtual ODatabaseMetaDataResultSet::ORow fillNode( std::vector< RowEquation >& /*rEquations*/, ExpressionNode* /* pOptionalArg */, sal_uInt32 /* nFlags */ )
286 ODatabaseMetaDataResultSet::ORow aRet;
287 return aRet;
291 class UnaryFunctionFunctor
293 const ExpressionFunct meFunct;
294 ParserContextSharedPtr mpContext;
296 public :
298 UnaryFunctionFunctor( const ExpressionFunct eFunct, const ParserContextSharedPtr& rContext ) :
299 meFunct( eFunct ),
300 mpContext( rContext )
303 void operator()( StringIteratorT, StringIteratorT ) const
306 ParserContext::OperandStack& rNodeStack( mpContext->maOperandStack );
308 if( rNodeStack.size() < 1 )
309 throw ParseError( "Not enough arguments for unary operator" );
311 // retrieve arguments
312 ExpressionNodeSharedPtr pArg( rNodeStack.top() );
313 rNodeStack.pop();
315 rNodeStack.push( ExpressionNodeSharedPtr( new UnaryFunctionExpression( meFunct, pArg ) ) );
319 /* This class implements the following grammar (more or
320 less literally written down below, only slightly
321 obfuscated by the parser actions):
323 basic_expression =
324 number |
325 '(' additive_expression ')'
327 unary_expression =
328 basic_expression
330 multiplicative_expression =
331 unary_expression ( ( '*' unary_expression )* |
332 ( '/' unary_expression )* )
334 additive_expression =
335 multiplicative_expression ( ( '+' multiplicative_expression )* |
336 ( '-' multiplicative_expression )* )
339 class ExpressionGrammar : public ::boost::spirit::grammar< ExpressionGrammar >
341 public:
342 /** Create an arithmetic expression grammar
344 @param rParserContext
345 Contains context info for the parser
347 ExpressionGrammar( const ParserContextSharedPtr& rParserContext ) :
348 mpParserContext( rParserContext )
352 template< typename ScannerT > class definition
354 public:
355 // grammar definition
356 definition( const ExpressionGrammar& self )
358 using ::boost::spirit::str_p;
359 using ::boost::spirit::space_p;
360 using ::boost::spirit::range_p;
361 using ::boost::spirit::lexeme_d;
362 using ::boost::spirit::real_parser;
363 using ::boost::spirit::chseq_p;
364 using ::boost::spirit::ch_p;
365 using ::boost::spirit::int_p;
366 using ::boost::spirit::as_lower_d;
367 using ::boost::spirit::strlit;
368 using ::boost::spirit::inhibit_case;
371 typedef inhibit_case<strlit<> > token_t;
372 token_t COLUMN = as_lower_d[ "column" ];
373 token_t OR_ = as_lower_d[ "or" ];
374 token_t AND_ = as_lower_d[ "and" ];
376 integer =
377 int_p
378 [IntConstantFunctor(self.getContext())];
380 argument =
381 integer
382 | lexeme_d[ +( range_p('a','z') | range_p('A','Z') | range_p('0','9') ) ]
383 [ ConstantFunctor(self.getContext()) ]
386 unaryFunction =
387 (COLUMN >> '(' >> integer >> ')' )
388 [ UnaryFunctionFunctor( UNARY_FUNC_COLUMN, self.getContext()) ]
391 assignment =
392 unaryFunction >> ch_p('=') >> argument
393 [ BinaryFunctionFunctor( ENUM_FUNC_EQUATION, self.getContext()) ]
396 andExpression =
397 assignment
398 | ( '(' >> orExpression >> ')' )
399 | ( assignment >> AND_ >> assignment ) [ BinaryFunctionFunctor( ENUM_FUNC_AND, self.getContext()) ]
402 orExpression =
403 andExpression
404 | ( orExpression >> OR_ >> andExpression ) [ BinaryFunctionFunctor( ENUM_FUNC_OR, self.getContext()) ]
407 basicExpression =
408 orExpression
411 BOOST_SPIRIT_DEBUG_RULE(basicExpression);
412 BOOST_SPIRIT_DEBUG_RULE(unaryFunction);
413 BOOST_SPIRIT_DEBUG_RULE(assignment);
414 BOOST_SPIRIT_DEBUG_RULE(argument);
415 BOOST_SPIRIT_DEBUG_RULE(integer);
416 BOOST_SPIRIT_DEBUG_RULE(orExpression);
417 BOOST_SPIRIT_DEBUG_RULE(andExpression);
420 const ::boost::spirit::rule< ScannerT >& start() const
422 return basicExpression;
425 private:
426 // the constituents of the Spirit arithmetic expression grammar.
427 // For the sake of readability, without 'ma' prefix.
428 ::boost::spirit::rule< ScannerT > basicExpression;
429 ::boost::spirit::rule< ScannerT > unaryFunction;
430 ::boost::spirit::rule< ScannerT > assignment;
431 ::boost::spirit::rule< ScannerT > integer,argument;
432 ::boost::spirit::rule< ScannerT > orExpression,andExpression;
435 const ParserContextSharedPtr& getContext() const
437 return mpParserContext;
440 private:
441 ParserContextSharedPtr mpParserContext; // might get modified during parsing
444 #ifdef BOOST_SPIRIT_SINGLE_GRAMMAR_INSTANCE
445 const ParserContextSharedPtr& getParserContext()
447 static ParserContextSharedPtr lcl_parserContext( new ParserContext() );
449 // clear node stack (since we reuse the static object, that's
450 // the whole point here)
451 while( !lcl_parserContext->maOperandStack.empty() )
452 lcl_parserContext->maOperandStack.pop();
454 return lcl_parserContext;
456 #endif
459 ExpressionNodeSharedPtr FunctionParser::parseFunction( const ::rtl::OUString& _sFunction)
461 // TODO(Q1): Check if a combination of the RTL_UNICODETOTEXT_FLAGS_*
462 // gives better conversion robustness here (we might want to map space
463 // etc. to ASCII space here)
464 const ::rtl::OString& rAsciiFunction(
465 rtl::OUStringToOString( _sFunction, RTL_TEXTENCODING_ASCII_US ) );
467 StringIteratorT aStart( rAsciiFunction.getStr() );
468 StringIteratorT aEnd( rAsciiFunction.getStr()+rAsciiFunction.getLength() );
470 ParserContextSharedPtr pContext;
472 #ifdef BOOST_SPIRIT_SINGLE_GRAMMAR_INSTANCE
473 // static parser context, because the actual
474 // Spirit parser is also a static object
475 pContext = getParserContext();
476 #else
477 pContext.reset( new ParserContext() );
478 #endif
480 ExpressionGrammar aExpressionGrammer( pContext );
482 const ::boost::spirit::parse_info<StringIteratorT> aParseInfo(
483 ::boost::spirit::parse( aStart,
484 aEnd,
485 aExpressionGrammer,
486 ::boost::spirit::space_p ) );
488 OSL_DEBUG_ONLY(::std::cout.flush()); // needed to keep stdout and cout in sync
490 // input fully congested by the parser?
491 if( !aParseInfo.full )
492 throw ParseError( "RowFunctionParser::parseFunction(): string not fully parseable" );
494 // parser's state stack now must contain exactly _one_ ExpressionNode,
495 // which represents our formula.
496 if( pContext->maOperandStack.size() != 1 )
497 throw ParseError( "RowFunctionParser::parseFunction(): incomplete or empty expression" );
499 return pContext->maOperandStack.top();