bump product version to 6.3.0.0.beta1
[LibreOffice.git] / connectivity / source / commontools / RowFunctionParser.cxx
blob811e0fb7c70fe97064dcda1fd748a85cdd9bbfbb
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
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
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 #include <tools/fract.hxx>
37 #if (OSL_DEBUG_LEVEL > 0)
38 #include <iostream>
39 #endif
40 #include <functional>
41 #include <algorithm>
42 #include <stack>
44 namespace connectivity
46 using namespace com::sun::star;
48 namespace
52 // EXPRESSION NODES
55 class ConstantValueExpression : public ExpressionNode
57 ORowSetValueDecoratorRef maValue;
59 public:
61 explicit ConstantValueExpression( ORowSetValueDecoratorRef const & rValue ) :
62 maValue( rValue )
65 virtual ORowSetValueDecoratorRef evaluate(const ODatabaseMetaDataResultSet::ORow& /*_aRow*/ ) const override
67 return maValue;
69 virtual void fill(const ODatabaseMetaDataResultSet::ORow& /*_aRow*/ ) const override
75 /** ExpressionNode implementation for unary
76 function over two ExpressionNodes
78 class BinaryFunctionExpression : public ExpressionNode
80 const ExpressionFunct meFunct;
81 std::shared_ptr<ExpressionNode> mpFirstArg;
82 std::shared_ptr<ExpressionNode> mpSecondArg;
84 public:
86 BinaryFunctionExpression( const ExpressionFunct eFunct, const std::shared_ptr<ExpressionNode>& rFirstArg, const std::shared_ptr<ExpressionNode>& rSecondArg ) :
87 meFunct( eFunct ),
88 mpFirstArg( rFirstArg ),
89 mpSecondArg( rSecondArg )
92 virtual ORowSetValueDecoratorRef evaluate(const ODatabaseMetaDataResultSet::ORow& _aRow ) const override
94 ORowSetValueDecoratorRef aRet;
95 switch(meFunct)
97 case ExpressionFunct::Equation:
98 aRet = new ORowSetValueDecorator( mpFirstArg->evaluate(_aRow )->getValue() == mpSecondArg->evaluate(_aRow )->getValue() );
99 break;
100 case ExpressionFunct::And:
101 aRet = new ORowSetValueDecorator( mpFirstArg->evaluate(_aRow )->getValue().getBool() && mpSecondArg->evaluate(_aRow )->getValue().getBool() );
102 break;
103 case ExpressionFunct::Or:
104 aRet = new ORowSetValueDecorator( mpFirstArg->evaluate(_aRow )->getValue().getBool() || mpSecondArg->evaluate(_aRow )->getValue().getBool() );
105 break;
106 default:
107 break;
109 return aRet;
111 virtual void fill(const ODatabaseMetaDataResultSet::ORow& _aRow ) const override
113 switch(meFunct)
115 case ExpressionFunct::Equation:
116 (*mpFirstArg->evaluate(_aRow )) = mpSecondArg->evaluate(_aRow )->getValue();
117 break;
118 default:
119 break;
125 // FUNCTION PARSER
128 typedef const sal_Char* StringIteratorT;
130 struct ParserContext
132 typedef std::stack< std::shared_ptr<ExpressionNode> > OperandStack;
134 // stores a stack of not-yet-evaluated operands. This is used
135 // by the operators (i.e. '+', '*', 'sin' etc.) to pop their
136 // arguments from. If all arguments to an operator are constant,
137 // the operator pushes a precalculated result on the stack, and
138 // a composite ExpressionNode otherwise.
139 OperandStack maOperandStack;
142 typedef std::shared_ptr< ParserContext > ParserContextSharedPtr;
144 /** Generate apriori constant value
147 class ConstantFunctor
149 ParserContextSharedPtr mpContext;
151 public:
153 explicit ConstantFunctor( const ParserContextSharedPtr& rContext ) :
154 mpContext( rContext )
157 void operator()( StringIteratorT rFirst,StringIteratorT rSecond) const
159 OUString sVal( rFirst, rSecond - rFirst, RTL_TEXTENCODING_UTF8 );
160 mpContext->maOperandStack.push( std::shared_ptr<ExpressionNode>( new ConstantValueExpression( new ORowSetValueDecorator( sVal ) ) ) );
164 /** Generate parse-dependent-but-then-constant value
166 class IntConstantFunctor
168 ParserContextSharedPtr mpContext;
170 public:
171 explicit IntConstantFunctor( const ParserContextSharedPtr& rContext ) :
172 mpContext( rContext )
175 void operator()( sal_Int32 n ) const
177 mpContext->maOperandStack.push( std::shared_ptr<ExpressionNode>( new ConstantValueExpression( new ORowSetValueDecorator( n ) ) ) );
181 /** Implements a binary function over two ExpressionNodes
183 @tpl Generator
184 Generator functor, to generate an ExpressionNode of
185 appropriate type
188 class BinaryFunctionFunctor
190 const ExpressionFunct meFunct;
191 ParserContextSharedPtr mpContext;
193 public:
195 BinaryFunctionFunctor( const ExpressionFunct eFunct, const ParserContextSharedPtr& rContext ) :
196 meFunct( eFunct ),
197 mpContext( rContext )
201 void operator()( StringIteratorT, StringIteratorT ) const
203 ParserContext::OperandStack& rNodeStack( mpContext->maOperandStack );
205 if( rNodeStack.size() < 2 )
206 throw ParseError( "Not enough arguments for binary operator" );
208 // retrieve arguments
209 std::shared_ptr<ExpressionNode> pSecondArg( rNodeStack.top() );
210 rNodeStack.pop();
211 std::shared_ptr<ExpressionNode> pFirstArg( rNodeStack.top() );
212 rNodeStack.pop();
214 // create combined ExpressionNode
215 std::shared_ptr<ExpressionNode> pNode( new BinaryFunctionExpression( meFunct, pFirstArg, pSecondArg ) );
216 // check for constness
217 rNodeStack.push( pNode );
220 /** ExpressionNode implementation for unary
221 function over one ExpressionNode
223 class UnaryFunctionExpression : public ExpressionNode
225 std::shared_ptr<ExpressionNode> mpArg;
227 public:
228 explicit UnaryFunctionExpression( const std::shared_ptr<ExpressionNode>& rArg ) :
229 mpArg( rArg )
232 virtual ORowSetValueDecoratorRef evaluate(const ODatabaseMetaDataResultSet::ORow& _aRow ) const override
234 return _aRow[mpArg->evaluate(_aRow )->getValue().getUInt32()];
236 virtual void fill(const ODatabaseMetaDataResultSet::ORow& /*_aRow*/ ) const override
241 class UnaryFunctionFunctor
243 ParserContextSharedPtr mpContext;
245 public:
247 explicit UnaryFunctionFunctor(const ParserContextSharedPtr& rContext)
248 : mpContext(rContext)
251 void operator()( StringIteratorT, StringIteratorT ) const
254 ParserContext::OperandStack& rNodeStack( mpContext->maOperandStack );
256 if( rNodeStack.empty() )
257 throw ParseError( "Not enough arguments for unary operator" );
259 // retrieve arguments
260 std::shared_ptr<ExpressionNode> pArg( rNodeStack.top() );
261 rNodeStack.pop();
263 rNodeStack.push( std::shared_ptr<ExpressionNode>( new UnaryFunctionExpression( pArg ) ) );
267 /* This class implements the following grammar (more or
268 less literally written down below, only slightly
269 obfuscated by the parser actions):
271 basic_expression =
272 number |
273 '(' additive_expression ')'
275 unary_expression =
276 basic_expression
278 multiplicative_expression =
279 unary_expression ( ( '*' unary_expression )* |
280 ( '/' unary_expression )* )
282 additive_expression =
283 multiplicative_expression ( ( '+' multiplicative_expression )* |
284 ( '-' multiplicative_expression )* )
287 class ExpressionGrammar : public ::boost::spirit::grammar< ExpressionGrammar >
289 public:
290 /** Create an arithmetic expression grammar
292 @param rParserContext
293 Contains context info for the parser
295 explicit ExpressionGrammar( const ParserContextSharedPtr& rParserContext ) :
296 mpParserContext( rParserContext )
300 template< typename ScannerT > class definition
302 public:
303 // grammar definition
304 explicit definition( const ExpressionGrammar& self )
306 using ::boost::spirit::space_p;
307 using ::boost::spirit::range_p;
308 using ::boost::spirit::lexeme_d;
309 using ::boost::spirit::ch_p;
310 using ::boost::spirit::int_p;
311 using ::boost::spirit::as_lower_d;
312 using ::boost::spirit::strlit;
313 using ::boost::spirit::inhibit_case;
316 typedef inhibit_case<strlit<> > token_t;
317 token_t COLUMN = as_lower_d[ "column" ];
318 token_t OR_ = as_lower_d[ "or" ];
319 token_t AND_ = as_lower_d[ "and" ];
321 integer =
322 int_p
323 [IntConstantFunctor(self.getContext())];
325 argument =
326 integer
327 | lexeme_d[ +( range_p('a','z') | range_p('A','Z') | range_p('0','9') ) ]
328 [ ConstantFunctor(self.getContext()) ]
331 unaryFunction =
332 (COLUMN >> '(' >> integer >> ')' )
333 [ UnaryFunctionFunctor( self.getContext()) ]
336 assignment =
337 unaryFunction >> ch_p('=') >> argument
338 [ BinaryFunctionFunctor( ExpressionFunct::Equation, self.getContext()) ]
341 andExpression =
342 assignment
343 | ( '(' >> orExpression >> ')' )
344 | ( assignment >> AND_ >> assignment ) [ BinaryFunctionFunctor( ExpressionFunct::And, self.getContext()) ]
347 orExpression =
348 andExpression
349 | ( orExpression >> OR_ >> andExpression ) [ BinaryFunctionFunctor( ExpressionFunct::Or, self.getContext()) ]
352 basicExpression =
353 orExpression
356 BOOST_SPIRIT_DEBUG_RULE(basicExpression);
357 BOOST_SPIRIT_DEBUG_RULE(unaryFunction);
358 BOOST_SPIRIT_DEBUG_RULE(assignment);
359 BOOST_SPIRIT_DEBUG_RULE(argument);
360 BOOST_SPIRIT_DEBUG_RULE(integer);
361 BOOST_SPIRIT_DEBUG_RULE(orExpression);
362 BOOST_SPIRIT_DEBUG_RULE(andExpression);
365 const ::boost::spirit::rule< ScannerT >& start() const
367 return basicExpression;
370 private:
371 // the constituents of the Spirit arithmetic expression grammar.
372 // For the sake of readability, without 'ma' prefix.
373 ::boost::spirit::rule< ScannerT > basicExpression;
374 ::boost::spirit::rule< ScannerT > unaryFunction;
375 ::boost::spirit::rule< ScannerT > assignment;
376 ::boost::spirit::rule< ScannerT > integer,argument;
377 ::boost::spirit::rule< ScannerT > orExpression,andExpression;
380 const ParserContextSharedPtr& getContext() const
382 return mpParserContext;
385 private:
386 ParserContextSharedPtr mpParserContext; // might get modified during parsing
389 const ParserContextSharedPtr& getParserContext()
391 static ParserContextSharedPtr lcl_parserContext( new ParserContext );
393 // clear node stack (since we reuse the static object, that's
394 // the whole point here)
395 while( !lcl_parserContext->maOperandStack.empty() )
396 lcl_parserContext->maOperandStack.pop();
398 return lcl_parserContext;
403 std::shared_ptr<ExpressionNode> const & FunctionParser::parseFunction( const OUString& _sFunction)
405 // TODO(Q1): Check if a combination of the RTL_UNICODETOTEXT_FLAGS_*
406 // gives better conversion robustness here (we might want to map space
407 // etc. to ASCII space here)
408 const OString& rAsciiFunction(
409 OUStringToOString( _sFunction, RTL_TEXTENCODING_ASCII_US ) );
411 StringIteratorT aStart( rAsciiFunction.getStr() );
412 StringIteratorT aEnd( rAsciiFunction.getStr()+rAsciiFunction.getLength() );
414 // static parser context, because the actual
415 // Spirit parser is also a static object
416 ParserContextSharedPtr pContext = getParserContext();
418 ExpressionGrammar aExpressionGrammer( pContext );
420 const ::boost::spirit::parse_info<StringIteratorT> aParseInfo(
421 ::boost::spirit::parse( aStart,
422 aEnd,
423 aExpressionGrammer,
424 ::boost::spirit::space_p ) );
426 #if (OSL_DEBUG_LEVEL > 0)
427 std::cout.flush(); // needed to keep stdout and cout in sync
428 #endif
430 // input fully congested by the parser?
431 if( !aParseInfo.full )
432 throw ParseError( "RowFunctionParser::parseFunction(): string not fully parseable" );
434 // parser's state stack now must contain exactly _one_ ExpressionNode,
435 // which represents our formula.
436 if( pContext->maOperandStack.size() != 1 )
437 throw ParseError( "RowFunctionParser::parseFunction(): incomplete or empty expression" );
439 return pContext->maOperandStack.top();
443 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */