LibreOffice Module connectivity (master) 1
RowFunctionParser.cxx
Go to the documentation of this file.
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
27#if OSL_DEBUG_LEVEL >= 2 && defined(DBG_UTIL)
28#include <typeinfo>
29#define BOOST_SPIRIT_DEBUG
30#endif
31#include <boost/spirit/include/classic_core.hpp>
32#include <RowFunctionParser.hxx>
33#include <rtl/ustring.hxx>
34
35
36#if (OSL_DEBUG_LEVEL > 0)
37#include <iostream>
38#endif
39#include <algorithm>
40#include <stack>
41#include <utility>
42
43namespace connectivity
44{
45using namespace com::sun::star;
46
47namespace
48{
49
50
51// EXPRESSION NODES
52
53
54class ConstantValueExpression : public ExpressionNode
55{
57
58public:
59
60 explicit ConstantValueExpression( ORowSetValueDecoratorRef aValue ) :
61 maValue(std::move( aValue ))
62 {
63 }
64 virtual ORowSetValueDecoratorRef evaluate(const ODatabaseMetaDataResultSet::ORow& /*_aRow*/ ) const override
65 {
66 return maValue;
67 }
68 virtual void fill(const ODatabaseMetaDataResultSet::ORow& /*_aRow*/ ) const override
69 {
70 }
71};
72
73
77class BinaryFunctionExpression : public ExpressionNode
78{
80 std::shared_ptr<ExpressionNode> mpFirstArg;
81 std::shared_ptr<ExpressionNode> mpSecondArg;
82
83public:
84
85 BinaryFunctionExpression( const ExpressionFunct eFunct, std::shared_ptr<ExpressionNode> xFirstArg, std::shared_ptr<ExpressionNode> xSecondArg ) :
86 meFunct( eFunct ),
87 mpFirstArg(std::move( xFirstArg )),
88 mpSecondArg(std::move( xSecondArg ))
89 {
90 }
91 virtual ORowSetValueDecoratorRef evaluate(const ODatabaseMetaDataResultSet::ORow& _aRow ) const override
92 {
94 switch(meFunct)
95 {
97 aRet = new ORowSetValueDecorator( ORowSetValue(mpFirstArg->evaluate(_aRow )->getValue() == mpSecondArg->evaluate(_aRow )->getValue()) );
98 break;
100 aRet = new ORowSetValueDecorator( ORowSetValue(mpFirstArg->evaluate(_aRow )->getValue().getBool() && mpSecondArg->evaluate(_aRow )->getValue().getBool()) );
101 break;
103 aRet = new ORowSetValueDecorator( ORowSetValue(mpFirstArg->evaluate(_aRow )->getValue().getBool() || mpSecondArg->evaluate(_aRow )->getValue().getBool()) );
104 break;
105 default:
106 break;
107 }
108 return aRet;
109 }
110 virtual void fill(const ODatabaseMetaDataResultSet::ORow& _aRow ) const override
111 {
112 switch(meFunct)
113 {
115 (*mpFirstArg->evaluate(_aRow )) = mpSecondArg->evaluate(_aRow )->getValue();
116 break;
117 default:
118 break;
119 }
120 }
121};
122
123
124// FUNCTION PARSER
125
126
127typedef const char* StringIteratorT;
128
129struct ParserContext
130{
131 typedef std::stack< std::shared_ptr<ExpressionNode> > OperandStack;
132
133 // stores a stack of not-yet-evaluated operands. This is used
134 // by the operators (i.e. '+', '*', 'sin' etc.) to pop their
135 // arguments from. If all arguments to an operator are constant,
136 // the operator pushes a precalculated result on the stack, and
137 // a composite ExpressionNode otherwise.
138 OperandStack maOperandStack;
139};
140
141typedef std::shared_ptr< ParserContext > ParserContextSharedPtr;
142
146class ConstantFunctor
147{
148 ParserContextSharedPtr mpContext;
149
150public:
151
152 explicit ConstantFunctor( ParserContextSharedPtr xContext ) :
153 mpContext(std::move( xContext ))
154 {
155 }
156 void operator()( StringIteratorT rFirst,StringIteratorT rSecond) const
157 {
158 OUString sVal( rFirst, rSecond - rFirst, RTL_TEXTENCODING_UTF8 );
159 mpContext->maOperandStack.push( std::make_shared<ConstantValueExpression>( new ORowSetValueDecorator( sVal ) ) );
160 }
161};
162
165class IntConstantFunctor
166{
167 ParserContextSharedPtr mpContext;
168
169public:
170 explicit IntConstantFunctor( ParserContextSharedPtr xContext ) :
171 mpContext(std::move( xContext ))
172 {
173 }
174 void operator()( sal_Int32 n ) const
175 {
176 mpContext->maOperandStack.push( std::make_shared<ConstantValueExpression>( new ORowSetValueDecorator( n ) ) );
177 }
178};
179
187class BinaryFunctionFunctor
188{
190 ParserContextSharedPtr mpContext;
191
192public:
193
194 BinaryFunctionFunctor( const ExpressionFunct eFunct, ParserContextSharedPtr xContext ) :
195 meFunct( eFunct ),
196 mpContext(std::move( xContext ))
197 {
198 }
199
200 void operator()( StringIteratorT, StringIteratorT ) const
201 {
202 ParserContext::OperandStack& rNodeStack( mpContext->maOperandStack );
203
204 if( rNodeStack.size() < 2 )
205 throw ParseError( "Not enough arguments for binary operator" );
206
207 // retrieve arguments
208 std::shared_ptr<ExpressionNode> pSecondArg( std::move(rNodeStack.top()) );
209 rNodeStack.pop();
210 std::shared_ptr<ExpressionNode> pFirstArg( std::move(rNodeStack.top()) );
211 rNodeStack.pop();
212
213 // create combined ExpressionNode
214 auto pNode = std::make_shared<BinaryFunctionExpression>( meFunct, pFirstArg, pSecondArg );
215 // check for constness
216 rNodeStack.push( pNode );
217 }
218};
222class UnaryFunctionExpression : public ExpressionNode
223{
224 std::shared_ptr<ExpressionNode> mpArg;
225
226public:
227 explicit UnaryFunctionExpression( std::shared_ptr<ExpressionNode> xArg ) :
228 mpArg(std::move( xArg ))
229 {
230 }
231 virtual ORowSetValueDecoratorRef evaluate(const ODatabaseMetaDataResultSet::ORow& _aRow ) const override
232 {
233 return _aRow[mpArg->evaluate(_aRow )->getValue().getUInt32()];
234 }
235 virtual void fill(const ODatabaseMetaDataResultSet::ORow& /*_aRow*/ ) const override
236 {
237 }
238};
239
240class UnaryFunctionFunctor
241{
242 ParserContextSharedPtr mpContext;
243
244public:
245
246 explicit UnaryFunctionFunctor(ParserContextSharedPtr xContext)
247 : mpContext(std::move(xContext))
248 {
249 }
250 void operator()( StringIteratorT, StringIteratorT ) const
251 {
252
253 ParserContext::OperandStack& rNodeStack( mpContext->maOperandStack );
254
255 if( rNodeStack.empty() )
256 throw ParseError( "Not enough arguments for unary operator" );
257
258 // retrieve arguments
259 std::shared_ptr<ExpressionNode> pArg( std::move(rNodeStack.top()) );
260 rNodeStack.pop();
261
262 rNodeStack.push( std::make_shared<UnaryFunctionExpression>( pArg ) );
263 }
264};
265
266/* This class implements the following grammar (more or
267 less literally written down below, only slightly
268 obfuscated by the parser actions):
269
270 basic_expression =
271 number |
272 '(' additive_expression ')'
273
274 unary_expression =
275 basic_expression
276
277 multiplicative_expression =
278 unary_expression ( ( '*' unary_expression )* |
279 ( '/' unary_expression )* )
280
281 additive_expression =
282 multiplicative_expression ( ( '+' multiplicative_expression )* |
283 ( '-' multiplicative_expression )* )
284
285 */
286class ExpressionGrammar : public ::boost::spirit::classic::grammar< ExpressionGrammar >
287{
288public:
294 explicit ExpressionGrammar( ParserContextSharedPtr xParserContext ) :
295 mpParserContext(std::move( xParserContext ))
296 {
297 }
298
299 template< typename ScannerT > class definition
300 {
301 public:
302 // grammar definition
303 explicit definition( const ExpressionGrammar& self )
304 {
305 using ::boost::spirit::classic::space_p;
306 using ::boost::spirit::classic::range_p;
307 using ::boost::spirit::classic::lexeme_d;
308 using ::boost::spirit::classic::ch_p;
309 using ::boost::spirit::classic::int_p;
310 using ::boost::spirit::classic::as_lower_d;
311 using ::boost::spirit::classic::strlit;
312 using ::boost::spirit::classic::inhibit_case;
313
314
315 typedef inhibit_case<strlit<> > token_t;
316 token_t COLUMN = as_lower_d[ "column" ];
317 token_t OR_ = as_lower_d[ "or" ];
318 token_t AND_ = as_lower_d[ "and" ];
319
320 integer =
321 int_p
322 [IntConstantFunctor(self.getContext())];
323
324 argument =
325 integer
326 | lexeme_d[ +( range_p('a','z') | range_p('A','Z') | range_p('0','9') ) ]
327 [ ConstantFunctor(self.getContext()) ]
328 ;
329
331 (COLUMN >> '(' >> integer >> ')' )
332 [ UnaryFunctionFunctor( self.getContext()) ]
333 ;
334
335 assignment =
336 unaryFunction >> ch_p('=') >> argument
337 [ BinaryFunctionFunctor( ExpressionFunct::Equation, self.getContext()) ]
338 ;
339
342 | ( '(' >> orExpression >> ')' )
343 | ( assignment >> AND_ >> assignment ) [ BinaryFunctionFunctor( ExpressionFunct::And, self.getContext()) ]
344 ;
345
348 | ( orExpression >> OR_ >> andExpression ) [ BinaryFunctionFunctor( ExpressionFunct::Or, self.getContext()) ]
349 ;
350
353 ;
354
355 BOOST_SPIRIT_DEBUG_RULE(basicExpression);
356 BOOST_SPIRIT_DEBUG_RULE(unaryFunction);
357 BOOST_SPIRIT_DEBUG_RULE(assignment);
358 BOOST_SPIRIT_DEBUG_RULE(argument);
359 BOOST_SPIRIT_DEBUG_RULE(integer);
360 BOOST_SPIRIT_DEBUG_RULE(orExpression);
361 BOOST_SPIRIT_DEBUG_RULE(andExpression);
362 }
363
364 const ::boost::spirit::classic::rule< ScannerT >& start() const
365 {
366 return basicExpression;
367 }
368
369 private:
370 // the constituents of the Spirit arithmetic expression grammar.
371 // For the sake of readability, without 'ma' prefix.
372 ::boost::spirit::classic::rule< ScannerT > basicExpression;
373 ::boost::spirit::classic::rule< ScannerT > unaryFunction;
374 ::boost::spirit::classic::rule< ScannerT > assignment;
375 ::boost::spirit::classic::rule< ScannerT > integer,argument;
376 ::boost::spirit::classic::rule< ScannerT > orExpression,andExpression;
377 };
378
379 const ParserContextSharedPtr& getContext() const
380 {
381 return mpParserContext;
382 }
383
384private:
385 ParserContextSharedPtr mpParserContext; // might get modified during parsing
386};
387
388const ParserContextSharedPtr& getParserContext()
389{
390 static ParserContextSharedPtr lcl_parserContext = std::make_shared<ParserContext>();
391
392 // clear node stack (since we reuse the static object, that's
393 // the whole point here)
394 while( !lcl_parserContext->maOperandStack.empty() )
395 lcl_parserContext->maOperandStack.pop();
396
397 return lcl_parserContext;
398}
399
400}
401
402std::shared_ptr<ExpressionNode> const & FunctionParser::parseFunction( const OUString& _sFunction)
403{
404 // TODO(Q1): Check if a combination of the RTL_UNICODETOTEXT_FLAGS_*
405 // gives better conversion robustness here (we might want to map space
406 // etc. to ASCII space here)
407 const OString& rAsciiFunction(
408 OUStringToOString( _sFunction, RTL_TEXTENCODING_ASCII_US ) );
409
410 StringIteratorT aStart( rAsciiFunction.getStr() );
411 StringIteratorT aEnd( rAsciiFunction.getStr()+rAsciiFunction.getLength() );
412
413 // static parser context, because the actual
414 // Spirit parser is also a static object
415 ParserContextSharedPtr pContext = getParserContext();
416
417 ExpressionGrammar aExpressionGrammer( pContext );
418
419 const ::boost::spirit::classic::parse_info<StringIteratorT> aParseInfo(
420 ::boost::spirit::classic::parse( aStart,
421 aEnd,
422 aExpressionGrammer,
423 ::boost::spirit::classic::space_p ) );
424
425#if (OSL_DEBUG_LEVEL > 0)
426 std::cout.flush(); // needed to keep stdout and cout in sync
427#endif
428
429 // input fully congested by the parser?
430 if( !aParseInfo.full )
431 throw ParseError( "RowFunctionParser::parseFunction(): string not fully parseable" );
432
433 // parser's state stack now must contain exactly _one_ ExpressionNode,
434 // which represents our formula.
435 if( pContext->maOperandStack.size() != 1 )
436 throw ParseError( "RowFunctionParser::parseFunction(): incomplete or empty expression" );
437
438 return pContext->maOperandStack.top();
439}
440}
441
442/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
::boost::spirit::classic::rule< ScannerT > integer
::boost::spirit::classic::rule< ScannerT > assignment
ParserContextSharedPtr mpParserContext
const ExpressionFunct meFunct
OperandStack maOperandStack
ORowSetValueDecoratorRef maValue
::boost::spirit::classic::rule< ScannerT > orExpression
::boost::spirit::classic::rule< ScannerT > andExpression
std::shared_ptr< ExpressionNode > mpFirstArg
::boost::spirit::classic::rule< ScannerT > argument
ParserContextSharedPtr mpContext
std::shared_ptr< ExpressionNode > mpArg
::boost::spirit::classic::rule< ScannerT > basicExpression
std::shared_ptr< ExpressionNode > mpSecondArg
::boost::spirit::classic::rule< ScannerT > unaryFunction
static std::shared_ptr< ExpressionNode > const & parseFunction(const OUString &_sFunction)
Parse a string.
std::vector< ORowSetValueDecoratorRef > ORow
ExpressionFunct
::rtl::Reference< ORowSetValueDecorator > ORowSetValueDecoratorRef
Definition: FValue.hxx:421
OString OUStringToOString(std::u16string_view str, ConnectionSettings const *settings)
Definition: pq_tools.cxx:100
This exception is thrown, when the arithmetic expression parser failed to parse a string.