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