nss: upgrade to release 3.73
[LibreOffice.git] / connectivity / source / commontools / RowFunctionParser.cxx
blob21f5e638a6517727a297ca852227dbded919033a
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>
36 #if (OSL_DEBUG_LEVEL > 0)
37 #include <iostream>
38 #endif
39 #include <algorithm>
40 #include <stack>
42 namespace connectivity
44 using namespace com::sun::star;
46 namespace
50 // EXPRESSION NODES
53 class ConstantValueExpression : public ExpressionNode
55 ORowSetValueDecoratorRef maValue;
57 public:
59 explicit ConstantValueExpression( ORowSetValueDecoratorRef const & rValue ) :
60 maValue( rValue )
63 virtual ORowSetValueDecoratorRef evaluate(const ODatabaseMetaDataResultSet::ORow& /*_aRow*/ ) const override
65 return maValue;
67 virtual void fill(const ODatabaseMetaDataResultSet::ORow& /*_aRow*/ ) const override
73 /** ExpressionNode implementation for unary
74 function over two ExpressionNodes
76 class BinaryFunctionExpression : public ExpressionNode
78 const ExpressionFunct meFunct;
79 std::shared_ptr<ExpressionNode> mpFirstArg;
80 std::shared_ptr<ExpressionNode> mpSecondArg;
82 public:
84 BinaryFunctionExpression( const ExpressionFunct eFunct, const std::shared_ptr<ExpressionNode>& rFirstArg, const std::shared_ptr<ExpressionNode>& rSecondArg ) :
85 meFunct( eFunct ),
86 mpFirstArg( rFirstArg ),
87 mpSecondArg( rSecondArg )
90 virtual ORowSetValueDecoratorRef evaluate(const ODatabaseMetaDataResultSet::ORow& _aRow ) const override
92 ORowSetValueDecoratorRef aRet;
93 switch(meFunct)
95 case ExpressionFunct::Equation:
96 aRet = new ORowSetValueDecorator( mpFirstArg->evaluate(_aRow )->getValue() == mpSecondArg->evaluate(_aRow )->getValue() );
97 break;
98 case ExpressionFunct::And:
99 aRet = new ORowSetValueDecorator( mpFirstArg->evaluate(_aRow )->getValue().getBool() && mpSecondArg->evaluate(_aRow )->getValue().getBool() );
100 break;
101 case ExpressionFunct::Or:
102 aRet = new ORowSetValueDecorator( mpFirstArg->evaluate(_aRow )->getValue().getBool() || mpSecondArg->evaluate(_aRow )->getValue().getBool() );
103 break;
104 default:
105 break;
107 return aRet;
109 virtual void fill(const ODatabaseMetaDataResultSet::ORow& _aRow ) const override
111 switch(meFunct)
113 case ExpressionFunct::Equation:
114 (*mpFirstArg->evaluate(_aRow )) = mpSecondArg->evaluate(_aRow )->getValue();
115 break;
116 default:
117 break;
123 // FUNCTION PARSER
126 typedef const char* StringIteratorT;
128 struct ParserContext
130 typedef std::stack< std::shared_ptr<ExpressionNode> > OperandStack;
132 // stores a stack of not-yet-evaluated operands. This is used
133 // by the operators (i.e. '+', '*', 'sin' etc.) to pop their
134 // arguments from. If all arguments to an operator are constant,
135 // the operator pushes a precalculated result on the stack, and
136 // a composite ExpressionNode otherwise.
137 OperandStack maOperandStack;
140 typedef std::shared_ptr< ParserContext > ParserContextSharedPtr;
142 /** Generate apriori constant value
145 class ConstantFunctor
147 ParserContextSharedPtr mpContext;
149 public:
151 explicit ConstantFunctor( const ParserContextSharedPtr& rContext ) :
152 mpContext( rContext )
155 void operator()( StringIteratorT rFirst,StringIteratorT rSecond) const
157 OUString sVal( rFirst, rSecond - rFirst, RTL_TEXTENCODING_UTF8 );
158 mpContext->maOperandStack.push( std::make_shared<ConstantValueExpression>( new ORowSetValueDecorator( sVal ) ) );
162 /** Generate parse-dependent-but-then-constant value
164 class IntConstantFunctor
166 ParserContextSharedPtr mpContext;
168 public:
169 explicit IntConstantFunctor( const ParserContextSharedPtr& rContext ) :
170 mpContext( rContext )
173 void operator()( sal_Int32 n ) const
175 mpContext->maOperandStack.push( std::make_shared<ConstantValueExpression>( new ORowSetValueDecorator( n ) ) );
179 /** Implements a binary function over two ExpressionNodes
181 @tpl Generator
182 Generator functor, to generate an ExpressionNode of
183 appropriate type
186 class BinaryFunctionFunctor
188 const ExpressionFunct meFunct;
189 ParserContextSharedPtr mpContext;
191 public:
193 BinaryFunctionFunctor( const ExpressionFunct eFunct, const ParserContextSharedPtr& rContext ) :
194 meFunct( eFunct ),
195 mpContext( rContext )
199 void operator()( StringIteratorT, StringIteratorT ) const
201 ParserContext::OperandStack& rNodeStack( mpContext->maOperandStack );
203 if( rNodeStack.size() < 2 )
204 throw ParseError( "Not enough arguments for binary operator" );
206 // retrieve arguments
207 std::shared_ptr<ExpressionNode> pSecondArg( std::move(rNodeStack.top()) );
208 rNodeStack.pop();
209 std::shared_ptr<ExpressionNode> pFirstArg( std::move(rNodeStack.top()) );
210 rNodeStack.pop();
212 // create combined ExpressionNode
213 auto pNode = std::make_shared<BinaryFunctionExpression>( meFunct, pFirstArg, pSecondArg );
214 // check for constness
215 rNodeStack.push( pNode );
218 /** ExpressionNode implementation for unary
219 function over one ExpressionNode
221 class UnaryFunctionExpression : public ExpressionNode
223 std::shared_ptr<ExpressionNode> mpArg;
225 public:
226 explicit UnaryFunctionExpression( const std::shared_ptr<ExpressionNode>& rArg ) :
227 mpArg( rArg )
230 virtual ORowSetValueDecoratorRef evaluate(const ODatabaseMetaDataResultSet::ORow& _aRow ) const override
232 return _aRow[mpArg->evaluate(_aRow )->getValue().getUInt32()];
234 virtual void fill(const ODatabaseMetaDataResultSet::ORow& /*_aRow*/ ) const override
239 class UnaryFunctionFunctor
241 ParserContextSharedPtr mpContext;
243 public:
245 explicit UnaryFunctionFunctor(const ParserContextSharedPtr& rContext)
246 : mpContext(rContext)
249 void operator()( StringIteratorT, StringIteratorT ) const
252 ParserContext::OperandStack& rNodeStack( mpContext->maOperandStack );
254 if( rNodeStack.empty() )
255 throw ParseError( "Not enough arguments for unary operator" );
257 // retrieve arguments
258 std::shared_ptr<ExpressionNode> pArg( std::move(rNodeStack.top()) );
259 rNodeStack.pop();
261 rNodeStack.push( std::make_shared<UnaryFunctionExpression>( pArg ) );
265 /* This class implements the following grammar (more or
266 less literally written down below, only slightly
267 obfuscated by the parser actions):
269 basic_expression =
270 number |
271 '(' additive_expression ')'
273 unary_expression =
274 basic_expression
276 multiplicative_expression =
277 unary_expression ( ( '*' unary_expression )* |
278 ( '/' unary_expression )* )
280 additive_expression =
281 multiplicative_expression ( ( '+' multiplicative_expression )* |
282 ( '-' multiplicative_expression )* )
285 class ExpressionGrammar : public ::boost::spirit::classic::grammar< ExpressionGrammar >
287 public:
288 /** Create an arithmetic expression grammar
290 @param rParserContext
291 Contains context info for the parser
293 explicit ExpressionGrammar( const ParserContextSharedPtr& rParserContext ) :
294 mpParserContext( rParserContext )
298 template< typename ScannerT > class definition
300 public:
301 // grammar definition
302 explicit definition( const ExpressionGrammar& self )
304 using ::boost::spirit::classic::space_p;
305 using ::boost::spirit::classic::range_p;
306 using ::boost::spirit::classic::lexeme_d;
307 using ::boost::spirit::classic::ch_p;
308 using ::boost::spirit::classic::int_p;
309 using ::boost::spirit::classic::as_lower_d;
310 using ::boost::spirit::classic::strlit;
311 using ::boost::spirit::classic::inhibit_case;
314 typedef inhibit_case<strlit<> > token_t;
315 token_t COLUMN = as_lower_d[ "column" ];
316 token_t OR_ = as_lower_d[ "or" ];
317 token_t AND_ = as_lower_d[ "and" ];
319 integer =
320 int_p
321 [IntConstantFunctor(self.getContext())];
323 argument =
324 integer
325 | lexeme_d[ +( range_p('a','z') | range_p('A','Z') | range_p('0','9') ) ]
326 [ ConstantFunctor(self.getContext()) ]
329 unaryFunction =
330 (COLUMN >> '(' >> integer >> ')' )
331 [ UnaryFunctionFunctor( self.getContext()) ]
334 assignment =
335 unaryFunction >> ch_p('=') >> argument
336 [ BinaryFunctionFunctor( ExpressionFunct::Equation, self.getContext()) ]
339 andExpression =
340 assignment
341 | ( '(' >> orExpression >> ')' )
342 | ( assignment >> AND_ >> assignment ) [ BinaryFunctionFunctor( ExpressionFunct::And, self.getContext()) ]
345 orExpression =
346 andExpression
347 | ( orExpression >> OR_ >> andExpression ) [ BinaryFunctionFunctor( ExpressionFunct::Or, self.getContext()) ]
350 basicExpression =
351 orExpression
354 BOOST_SPIRIT_DEBUG_RULE(basicExpression);
355 BOOST_SPIRIT_DEBUG_RULE(unaryFunction);
356 BOOST_SPIRIT_DEBUG_RULE(assignment);
357 BOOST_SPIRIT_DEBUG_RULE(argument);
358 BOOST_SPIRIT_DEBUG_RULE(integer);
359 BOOST_SPIRIT_DEBUG_RULE(orExpression);
360 BOOST_SPIRIT_DEBUG_RULE(andExpression);
363 const ::boost::spirit::classic::rule< ScannerT >& start() const
365 return basicExpression;
368 private:
369 // the constituents of the Spirit arithmetic expression grammar.
370 // For the sake of readability, without 'ma' prefix.
371 ::boost::spirit::classic::rule< ScannerT > basicExpression;
372 ::boost::spirit::classic::rule< ScannerT > unaryFunction;
373 ::boost::spirit::classic::rule< ScannerT > assignment;
374 ::boost::spirit::classic::rule< ScannerT > integer,argument;
375 ::boost::spirit::classic::rule< ScannerT > orExpression,andExpression;
378 const ParserContextSharedPtr& getContext() const
380 return mpParserContext;
383 private:
384 ParserContextSharedPtr mpParserContext; // might get modified during parsing
387 const ParserContextSharedPtr& getParserContext()
389 static ParserContextSharedPtr lcl_parserContext = std::make_shared<ParserContext>();
391 // clear node stack (since we reuse the static object, that's
392 // the whole point here)
393 while( !lcl_parserContext->maOperandStack.empty() )
394 lcl_parserContext->maOperandStack.pop();
396 return lcl_parserContext;
401 std::shared_ptr<ExpressionNode> const & FunctionParser::parseFunction( const OUString& _sFunction)
403 // TODO(Q1): Check if a combination of the RTL_UNICODETOTEXT_FLAGS_*
404 // gives better conversion robustness here (we might want to map space
405 // etc. to ASCII space here)
406 const OString& rAsciiFunction(
407 OUStringToOString( _sFunction, RTL_TEXTENCODING_ASCII_US ) );
409 StringIteratorT aStart( rAsciiFunction.getStr() );
410 StringIteratorT aEnd( rAsciiFunction.getStr()+rAsciiFunction.getLength() );
412 // static parser context, because the actual
413 // Spirit parser is also a static object
414 ParserContextSharedPtr pContext = getParserContext();
416 ExpressionGrammar aExpressionGrammer( pContext );
418 const ::boost::spirit::classic::parse_info<StringIteratorT> aParseInfo(
419 ::boost::spirit::classic::parse( aStart,
420 aEnd,
421 aExpressionGrammer,
422 ::boost::spirit::classic::space_p ) );
424 #if (OSL_DEBUG_LEVEL > 0)
425 std::cout.flush(); // needed to keep stdout and cout in sync
426 #endif
428 // input fully congested by the parser?
429 if( !aParseInfo.full )
430 throw ParseError( "RowFunctionParser::parseFunction(): string not fully parseable" );
432 // parser's state stack now must contain exactly _one_ ExpressionNode,
433 // which represents our formula.
434 if( pContext->maOperandStack.size() != 1 )
435 throw ParseError( "RowFunctionParser::parseFunction(): incomplete or empty expression" );
437 return pContext->maOperandStack.top();
441 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */