Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*
3 : : * This file is part of the LibreOffice project.
4 : : *
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/.
8 : : *
9 : : * This file incorporates work covered by the following license notice:
10 : : *
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 .
18 : : */
19 : :
20 : :
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>
34 : :
35 : :
36 : :
37 : : #if (OSL_DEBUG_LEVEL > 0)
38 : : #include <iostream>
39 : : #endif
40 : : #include <functional>
41 : : #include <algorithm>
42 : : #include <stack>
43 : :
44 : : namespace connectivity
45 : : {
46 : : using namespace com::sun::star;
47 : :
48 : : namespace
49 : : {
50 : : //////////////////////
51 : : //////////////////////
52 : : // EXPRESSION NODES
53 : : //////////////////////
54 : : //////////////////////
55 [ # # ][ # # ]: 0 : class ConstantValueExpression : public ExpressionNode
56 : : {
57 : : ORowSetValueDecoratorRef maValue;
58 : :
59 : : public:
60 : :
61 : 0 : ConstantValueExpression( ORowSetValueDecoratorRef rValue ) :
62 [ # # ]: 0 : maValue( rValue )
63 : : {
64 : 0 : }
65 : 0 : virtual ORowSetValueDecoratorRef evaluate(const ODatabaseMetaDataResultSet::ORow& /*_aRow*/ ) const
66 : : {
67 : 0 : return maValue;
68 : : }
69 : 0 : virtual void fill(const ODatabaseMetaDataResultSet::ORow& /*_aRow*/ ) const
70 : : {
71 : 0 : }
72 : 0 : virtual ExpressionFunct getType() const
73 : : {
74 : 0 : return FUNC_CONST;
75 : : }
76 : 0 : virtual ODatabaseMetaDataResultSet::ORow fillNode( std::vector< RowEquation >& /*rEquations*/, ExpressionNode* /* pOptionalArg */, sal_uInt32 /* nFlags */ )
77 : : {
78 : 0 : ODatabaseMetaDataResultSet::ORow aRet;
79 : 0 : return aRet;
80 : : }
81 : : };
82 : :
83 : :
84 : : /** ExpressionNode implementation for unary
85 : : function over two ExpressionNodes
86 : : */
87 [ # # ][ # # ]: 0 : class BinaryFunctionExpression : public ExpressionNode
[ # # ]
88 : : {
89 : : const ExpressionFunct meFunct;
90 : : ExpressionNodeSharedPtr mpFirstArg;
91 : : ExpressionNodeSharedPtr mpSecondArg;
92 : :
93 : : public:
94 : :
95 : 0 : BinaryFunctionExpression( const ExpressionFunct eFunct, const ExpressionNodeSharedPtr& rFirstArg, const ExpressionNodeSharedPtr& rSecondArg ) :
96 : : meFunct( eFunct ),
97 : : mpFirstArg( rFirstArg ),
98 [ # # ][ # # ]: 0 : mpSecondArg( rSecondArg )
99 : : {
100 : 0 : }
101 : 0 : virtual ORowSetValueDecoratorRef evaluate(const ODatabaseMetaDataResultSet::ORow& _aRow ) const
102 : : {
103 : 0 : ORowSetValueDecoratorRef aRet;
104 [ # # # # ]: 0 : switch(meFunct)
105 : : {
106 : : case ENUM_FUNC_EQUATION:
107 [ # # ][ # # ]: 0 : aRet = new ORowSetValueDecorator(sal_Bool(mpFirstArg->evaluate(_aRow )->getValue() == mpSecondArg->evaluate(_aRow )->getValue()) );
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
108 : 0 : break;
109 : : case ENUM_FUNC_AND:
110 [ # # ][ # # ]: 0 : aRet = new ORowSetValueDecorator( sal_Bool(mpFirstArg->evaluate(_aRow )->getValue().getBool() && mpSecondArg->evaluate(_aRow )->getValue().getBool()) );
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
[ # # # # ]
111 : 0 : break;
112 : : case ENUM_FUNC_OR:
113 [ # # ][ # # ]: 0 : aRet = new ORowSetValueDecorator( sal_Bool(mpFirstArg->evaluate(_aRow )->getValue().getBool() || mpSecondArg->evaluate(_aRow )->getValue().getBool()) );
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
[ # # # # ]
114 : 0 : break;
115 : : default:
116 : 0 : break;
117 : : }
118 : 0 : return aRet;
119 : : }
120 : 0 : virtual void fill(const ODatabaseMetaDataResultSet::ORow& _aRow ) const
121 : : {
122 [ # # ]: 0 : switch(meFunct)
123 : : {
124 : : case ENUM_FUNC_EQUATION:
125 [ # # ][ # # ]: 0 : (*mpFirstArg->evaluate(_aRow )) = mpSecondArg->evaluate(_aRow )->getValue();
[ # # ]
126 : 0 : break;
127 : : default:
128 : 0 : break;
129 : : }
130 : 0 : }
131 : 0 : virtual ExpressionFunct getType() const
132 : : {
133 : 0 : return meFunct;
134 : : }
135 : 0 : virtual ODatabaseMetaDataResultSet::ORow fillNode( std::vector< RowEquation >& /*rEquations*/, ExpressionNode* /*pOptionalArg*/, sal_uInt32 /*nFlags*/ )
136 : : {
137 : 0 : ODatabaseMetaDataResultSet::ORow aRet;
138 : 0 : return aRet;
139 : : }
140 : : };
141 : :
142 : :
143 : : ////////////////////////
144 : : ////////////////////////
145 : : // FUNCTION PARSER
146 : : ////////////////////////
147 : : ////////////////////////
148 : :
149 : : typedef const sal_Char* StringIteratorT;
150 : :
151 [ # # ]: 0 : struct ParserContext
152 : : {
153 : : typedef ::std::stack< ExpressionNodeSharedPtr > OperandStack;
154 : :
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;
161 : : };
162 : :
163 : : typedef ::boost::shared_ptr< ParserContext > ParserContextSharedPtr;
164 : :
165 : : /** Generate apriori constant value
166 : : */
167 : :
168 : 0 : class ConstantFunctor
169 : : {
170 : : ParserContextSharedPtr mpContext;
171 : :
172 : : public:
173 : :
174 : 0 : ConstantFunctor( const ParserContextSharedPtr& rContext ) :
175 : 0 : mpContext( rContext )
176 : : {
177 : 0 : }
178 : 0 : void operator()( StringIteratorT rFirst,StringIteratorT rSecond) const
179 : : {
180 [ # # ]: 0 : rtl::OUString sVal( rFirst, rSecond - rFirst, RTL_TEXTENCODING_UTF8 );
181 [ # # ][ # # ]: 0 : mpContext->maOperandStack.push( ExpressionNodeSharedPtr( new ConstantValueExpression( new ORowSetValueDecorator( sVal ) ) ) );
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
182 : 0 : }
183 : : };
184 : :
185 : : /** Generate parse-dependent-but-then-constant value
186 : : */
187 : 0 : class IntConstantFunctor
188 : : {
189 : : ParserContextSharedPtr mpContext;
190 : :
191 : : public:
192 : 0 : IntConstantFunctor( const ParserContextSharedPtr& rContext ) :
193 : 0 : mpContext( rContext )
194 : : {
195 : 0 : }
196 : 0 : void operator()( sal_Int32 n ) const
197 : : {
198 [ # # ][ # # ]: 0 : mpContext->maOperandStack.push( ExpressionNodeSharedPtr( new ConstantValueExpression( new ORowSetValueDecorator( n ) ) ) );
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
199 : 0 : }
200 : : void operator()( StringIteratorT rFirst,StringIteratorT rSecond) const
201 : : {
202 : : rtl::OUString sVal( rFirst, rSecond - rFirst, RTL_TEXTENCODING_UTF8 );
203 : : (void)sVal;
204 : : }
205 : : };
206 : :
207 : : /** Implements a binary function over two ExpressionNodes
208 : :
209 : : @tpl Generator
210 : : Generator functor, to generate an ExpressionNode of
211 : : appropriate type
212 : :
213 : : */
214 : 0 : class BinaryFunctionFunctor
215 : : {
216 : : const ExpressionFunct meFunct;
217 : : ParserContextSharedPtr mpContext;
218 : :
219 : : public:
220 : :
221 : 0 : BinaryFunctionFunctor( const ExpressionFunct eFunct, const ParserContextSharedPtr& rContext ) :
222 : : meFunct( eFunct ),
223 : 0 : mpContext( rContext )
224 : : {
225 : 0 : }
226 : :
227 : 0 : void operator()( StringIteratorT, StringIteratorT ) const
228 : : {
229 : 0 : ParserContext::OperandStack& rNodeStack( mpContext->maOperandStack );
230 : :
231 [ # # ]: 0 : if( rNodeStack.size() < 2 )
232 : 0 : throw ParseError( "Not enough arguments for binary operator" );
233 : :
234 : : // retrieve arguments
235 [ # # ][ # # ]: 0 : ExpressionNodeSharedPtr pSecondArg( rNodeStack.top() );
236 [ # # ]: 0 : rNodeStack.pop();
237 [ # # ][ # # ]: 0 : ExpressionNodeSharedPtr pFirstArg( rNodeStack.top() );
238 [ # # ]: 0 : rNodeStack.pop();
239 : :
240 : : // create combined ExpressionNode
241 [ # # ][ # # ]: 0 : ExpressionNodeSharedPtr pNode = ExpressionNodeSharedPtr( new BinaryFunctionExpression( meFunct, pFirstArg, pSecondArg ) );
[ # # ]
242 : : // check for constness
243 [ # # ][ # # ]: 0 : rNodeStack.push( pNode );
[ # # ][ # # ]
244 : 0 : }
245 : : };
246 : : /** ExpressionNode implementation for unary
247 : : function over one ExpressionNode
248 : : */
249 [ # # ][ # # ]: 0 : class UnaryFunctionExpression : public ExpressionNode
250 : : {
251 : : const ExpressionFunct meFunct;
252 : : ExpressionNodeSharedPtr mpArg;
253 : :
254 : : public:
255 : 0 : UnaryFunctionExpression( const ExpressionFunct eFunct, const ExpressionNodeSharedPtr& rArg ) :
256 : : meFunct( eFunct ),
257 [ # # ]: 0 : mpArg( rArg )
258 : : {
259 : 0 : }
260 : 0 : virtual ORowSetValueDecoratorRef evaluate(const ODatabaseMetaDataResultSet::ORow& _aRow ) const
261 : : {
262 [ # # ][ # # ]: 0 : return _aRow[mpArg->evaluate(_aRow )->getValue().getInt32()];
263 : : }
264 : 0 : virtual void fill(const ODatabaseMetaDataResultSet::ORow& /*_aRow*/ ) const
265 : : {
266 : 0 : }
267 : 0 : virtual ExpressionFunct getType() const
268 : : {
269 : 0 : return meFunct;
270 : : }
271 : 0 : virtual ODatabaseMetaDataResultSet::ORow fillNode( std::vector< RowEquation >& /*rEquations*/, ExpressionNode* /* pOptionalArg */, sal_uInt32 /* nFlags */ )
272 : : {
273 : 0 : ODatabaseMetaDataResultSet::ORow aRet;
274 : 0 : return aRet;
275 : : }
276 : : };
277 : :
278 : 0 : class UnaryFunctionFunctor
279 : : {
280 : : const ExpressionFunct meFunct;
281 : : ParserContextSharedPtr mpContext;
282 : :
283 : : public :
284 : :
285 : 0 : UnaryFunctionFunctor( const ExpressionFunct eFunct, const ParserContextSharedPtr& rContext ) :
286 : : meFunct( eFunct ),
287 : 0 : mpContext( rContext )
288 : : {
289 : 0 : }
290 : 0 : void operator()( StringIteratorT, StringIteratorT ) const
291 : : {
292 : :
293 : 0 : ParserContext::OperandStack& rNodeStack( mpContext->maOperandStack );
294 : :
295 [ # # ]: 0 : if( rNodeStack.size() < 1 )
296 : 0 : throw ParseError( "Not enough arguments for unary operator" );
297 : :
298 : : // retrieve arguments
299 [ # # ][ # # ]: 0 : ExpressionNodeSharedPtr pArg( rNodeStack.top() );
300 [ # # ]: 0 : rNodeStack.pop();
301 : :
302 [ # # ][ # # ]: 0 : rNodeStack.push( ExpressionNodeSharedPtr( new UnaryFunctionExpression( meFunct, pArg ) ) );
[ # # ][ # # ]
[ # # ][ # # ]
303 : 0 : }
304 : : };
305 : :
306 : : /* This class implements the following grammar (more or
307 : : less literally written down below, only slightly
308 : : obfuscated by the parser actions):
309 : :
310 : : basic_expression =
311 : : number |
312 : : '(' additive_expression ')'
313 : :
314 : : unary_expression =
315 : : basic_expression
316 : :
317 : : multiplicative_expression =
318 : : unary_expression ( ( '*' unary_expression )* |
319 : : ( '/' unary_expression )* )
320 : :
321 : : additive_expression =
322 : : multiplicative_expression ( ( '+' multiplicative_expression )* |
323 : : ( '-' multiplicative_expression )* )
324 : :
325 : : */
326 [ # # ]: 0 : class ExpressionGrammar : public ::boost::spirit::grammar< ExpressionGrammar >
327 : : {
328 : : public:
329 : : /** Create an arithmetic expression grammar
330 : :
331 : : @param rParserContext
332 : : Contains context info for the parser
333 : : */
334 : 0 : ExpressionGrammar( const ParserContextSharedPtr& rParserContext ) :
335 [ # # ]: 0 : mpParserContext( rParserContext )
336 : : {
337 : 0 : }
338 : :
339 [ # # ][ # # ]: 0 : template< typename ScannerT > class definition
[ # # ][ # # ]
[ # # ][ # # ]
340 : : {
341 : : public:
342 : : // grammar definition
343 : 0 : definition( const ExpressionGrammar& self )
344 [ # # ][ # # ]: 0 : {
[ # # ][ # # ]
[ # # ][ # # ]
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;
356 : :
357 : :
358 : : typedef inhibit_case<strlit<> > token_t;
359 [ # # ]: 0 : token_t COLUMN = as_lower_d[ "column" ];
360 [ # # ]: 0 : token_t OR_ = as_lower_d[ "or" ];
361 [ # # ]: 0 : token_t AND_ = as_lower_d[ "and" ];
362 : :
363 [ # # ][ # # ]: 0 : integer =
[ # # ][ # # ]
[ # # ]
364 : : int_p
365 : : [IntConstantFunctor(self.getContext())];
366 : :
367 [ # # ][ # # ]: 0 : argument =
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
368 : : integer
369 : : | lexeme_d[ +( range_p('a','z') | range_p('A','Z') | range_p('0','9') ) ]
370 : : [ ConstantFunctor(self.getContext()) ]
371 : : ;
372 : :
373 [ # # ][ # # ]: 0 : unaryFunction =
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
374 : : (COLUMN >> '(' >> integer >> ')' )
375 : : [ UnaryFunctionFunctor( UNARY_FUNC_COLUMN, self.getContext()) ]
376 : : ;
377 : :
378 [ # # ][ # # ]: 0 : assignment =
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
379 : : unaryFunction >> ch_p('=') >> argument
380 : : [ BinaryFunctionFunctor( ENUM_FUNC_EQUATION, self.getContext()) ]
381 : : ;
382 : :
383 [ # # ][ # # ]: 0 : andExpression =
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
384 : : assignment
385 : : | ( '(' >> orExpression >> ')' )
386 : : | ( assignment >> AND_ >> assignment ) [ BinaryFunctionFunctor( ENUM_FUNC_AND, self.getContext()) ]
387 : : ;
388 : :
389 [ # # ][ # # ]: 0 : orExpression =
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
390 : : andExpression
391 : : | ( orExpression >> OR_ >> andExpression ) [ BinaryFunctionFunctor( ENUM_FUNC_OR, self.getContext()) ]
392 : : ;
393 : :
394 [ # # ]: 0 : basicExpression =
395 : : orExpression
396 : : ;
397 : :
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);
405 : 0 : }
406 : :
407 : 0 : const ::boost::spirit::rule< ScannerT >& start() const
408 : : {
409 : 0 : return basicExpression;
410 : : }
411 : :
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;
420 : : };
421 : :
422 : 0 : const ParserContextSharedPtr& getContext() const
423 : : {
424 : 0 : return mpParserContext;
425 : : }
426 : :
427 : : private:
428 : : ParserContextSharedPtr mpParserContext; // might get modified during parsing
429 : : };
430 : :
431 : : #ifdef BOOST_SPIRIT_SINGLE_GRAMMAR_INSTANCE
432 : 0 : const ParserContextSharedPtr& getParserContext()
433 : : {
434 [ # # ][ # # ]: 0 : static ParserContextSharedPtr lcl_parserContext( new ParserContext() );
[ # # ][ # # ]
[ # # ][ # # ]
435 : :
436 : : // clear node stack (since we reuse the static object, that's
437 : : // the whole point here)
438 [ # # ]: 0 : while( !lcl_parserContext->maOperandStack.empty() )
439 : 0 : lcl_parserContext->maOperandStack.pop();
440 : :
441 : 0 : return lcl_parserContext;
442 : : }
443 : : #endif
444 : : }
445 : :
446 : 0 : ExpressionNodeSharedPtr FunctionParser::parseFunction( const ::rtl::OUString& _sFunction)
447 : : {
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 ::rtl::OString& rAsciiFunction(
452 [ # # ]: 0 : rtl::OUStringToOString( _sFunction, RTL_TEXTENCODING_ASCII_US ) );
453 : :
454 : 0 : StringIteratorT aStart( rAsciiFunction.getStr() );
455 : 0 : StringIteratorT aEnd( rAsciiFunction.getStr()+rAsciiFunction.getLength() );
456 : :
457 [ # # ]: 0 : ParserContextSharedPtr pContext;
458 : :
459 : : #ifdef BOOST_SPIRIT_SINGLE_GRAMMAR_INSTANCE
460 : : // static parser context, because the actual
461 : : // Spirit parser is also a static object
462 [ # # ][ # # ]: 0 : pContext = getParserContext();
463 : : #else
464 : : pContext.reset( new ParserContext() );
465 : : #endif
466 : :
467 [ # # ]: 0 : ExpressionGrammar aExpressionGrammer( pContext );
468 : :
469 : : const ::boost::spirit::parse_info<StringIteratorT> aParseInfo(
470 : : ::boost::spirit::parse( aStart,
471 : : aEnd,
472 : : aExpressionGrammer,
473 [ # # ]: 0 : ::boost::spirit::space_p ) );
474 : :
475 : : OSL_DEBUG_ONLY(::std::cout.flush()); // needed to keep stdout and cout in sync
476 : :
477 : : // input fully congested by the parser?
478 [ # # ]: 0 : if( !aParseInfo.full )
479 : 0 : throw ParseError( "RowFunctionParser::parseFunction(): string not fully parseable" );
480 : :
481 : : // parser's state stack now must contain exactly _one_ ExpressionNode,
482 : : // which represents our formula.
483 [ # # ]: 0 : if( pContext->maOperandStack.size() != 1 )
484 : 0 : throw ParseError( "RowFunctionParser::parseFunction(): incomplete or empty expression" );
485 : :
486 [ # # ][ # # ]: 0 : return pContext->maOperandStack.top();
[ # # ][ # # ]
487 : : }
488 [ + - ][ + - ]: 168 : }
489 : :
490 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|