2019-05-30 20:40:56 +02:00
/*
2022-06-24 15:08:49 +02:00
* Copyright © 2019 - 2022 Dynare Team
2019-05-30 20:40:56 +02:00
*
* This file is part of Dynare .
*
* Dynare is free software : you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation , either version 3 of the License , or
* ( at your option ) any later version .
*
* Dynare is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
2021-06-09 16:52:20 +02:00
* along with Dynare . If not , see < https : //www.gnu.org/licenses/>.
2019-05-30 20:40:56 +02:00
*/
# ifndef _EXPRESSIONS_HH
# define _EXPRESSIONS_HH
# include "ForwardDeclarationsAndEnums.hh"
# include "Environment.hh"
# include "location.hh"
# include <cmath>
# include <vector>
# include <sstream>
# include <iomanip>
namespace macro
{
class StackTrace final : public exception
{
private :
vector < string > message ;
public :
2019-12-23 19:08:51 +01:00
StackTrace ( string message_arg ) : message { move ( message_arg ) } { }
StackTrace ( const string & prefix , const char * standard_exception_message , const Tokenizer : : location & location )
2019-05-30 20:40:56 +02:00
{
stringstream ss ;
ss < < prefix < < " : " < < location < < " " < < standard_exception_message ;
message = { ss . str ( ) } ;
}
2019-12-23 19:08:51 +01:00
StackTrace ( const string & prefix , const string & msg , const Tokenizer : : location & location )
2019-05-30 20:40:56 +02:00
{
stringstream ss ;
ss < < prefix < < " : " < < location < < " " < < msg ;
message = { ss . str ( ) } ;
}
2019-12-23 19:08:51 +01:00
void push ( const string & prefix , const Tokenizer : : location & location )
2019-05-30 20:40:56 +02:00
{
stringstream ss ;
2019-12-18 11:26:07 +01:00
auto end_col = 0 < location . end . column ? location . end . column - 1 : 0 ;
2019-05-30 20:40:56 +02:00
ss < < prefix < < " : "
2019-06-27 14:27:59 +02:00
< < R " ( " ) " << *location.begin.filename << R " ( " line ) " < < location . begin . line
< < " , col " < < location . begin . column ;
2019-05-30 20:40:56 +02:00
if ( location . end . filename
& & ( ! location . begin . filename
| | * location . begin . filename ! = * location . end . filename ) )
2019-06-27 14:27:59 +02:00
ss < < R " ( to " ) " << location.end.filename << R " ( " ) " < < " line " < < location . end . line
< < " , col " < < end_col ;
2019-05-30 20:40:56 +02:00
else if ( location . begin . line < location . end . line )
ss < < " to line " < < location . end . line < < " , col " < < end_col ;
else if ( location . begin . column < end_col )
ss < < " - " < < end_col ;
message . emplace_back ( ss . str ( ) ) ;
}
2019-12-23 19:08:51 +01:00
string trace ( ) const
2019-05-30 20:40:56 +02:00
{
stringstream ss ;
2019-12-20 16:59:30 +01:00
for ( auto & msg : message )
2019-05-30 20:40:56 +02:00
ss < < " - " < < msg < < endl ;
return ss . str ( ) ;
}
} ;
2019-12-23 19:08:51 +01:00
2019-05-30 20:40:56 +02:00
class Node
{
protected :
const Tokenizer : : location location ;
public :
2020-12-07 17:28:29 +01:00
explicit Node ( Tokenizer : : location location_arg ) :
location { move ( location_arg ) } { }
2019-12-23 19:08:51 +01:00
virtual ~ Node ( ) = default ;
2019-05-30 20:40:56 +02:00
public :
2022-06-24 15:08:49 +02:00
Tokenizer : : location getLocation ( ) const noexcept { return location ; }
void
error ( const StackTrace & e ) const noexcept
2019-05-30 20:40:56 +02:00
{
cerr < < endl < < " Macro-processing error: backtrace... " < < endl < < e . trace ( ) ;
exit ( EXIT_FAILURE ) ;
}
2022-06-24 15:08:49 +02:00
void
warning ( const StackTrace & e ) const noexcept
2019-10-03 13:02:00 +02:00
{
cerr < < endl < < " Macro-processing warning: backtrace... " < < endl < < e . trace ( ) ;
}
2022-06-24 15:08:49 +02:00
void
printLineInfo ( ostream & output ) const noexcept
2019-05-30 20:40:56 +02:00
{
2020-02-05 15:07:03 +01:00
output < < R " (@#line " ) " << *(location.begin.filename) << R " ( " ) " < < location . begin . line < < endl ;
2019-05-30 20:40:56 +02:00
}
2022-06-24 15:08:49 +02:00
void
printEndLineInfo ( ostream & output ) const noexcept
2019-05-30 20:40:56 +02:00
{
2020-02-05 15:07:03 +01:00
// Add one to end line because we want to print the line number of the line *following* the end statement
output < < R " (@#line " ) " << *(location.begin.filename) << R " ( " ) " < < location . end . line + 1 < < endl ;
2019-05-30 20:40:56 +02:00
}
} ;
2019-12-23 19:08:51 +01:00
2019-05-30 20:40:56 +02:00
class Expression : public Node
{
public :
2020-12-07 17:28:29 +01:00
explicit Expression ( Tokenizer : : location location_arg ) :
Node ( move ( location_arg ) ) { }
2019-05-30 20:40:56 +02:00
virtual string to_string ( ) const noexcept = 0 ;
2019-06-24 11:00:02 +02:00
virtual void print ( ostream & output , bool matlab_output = false ) const noexcept = 0 ;
2020-12-07 17:28:29 +01:00
virtual BaseTypePtr eval ( Environment & env ) = 0 ;
2019-06-25 12:14:23 +02:00
virtual ExpressionPtr clone ( ) const noexcept = 0 ;
2019-05-30 20:40:56 +02:00
} ;
2019-12-23 19:08:51 +01:00
2019-05-30 20:40:56 +02:00
class BaseType : public Expression , public enable_shared_from_this < BaseType >
{
public :
2020-12-07 17:28:29 +01:00
explicit BaseType ( Tokenizer : : location location_arg = Tokenizer : : location ( ) ) :
Expression ( move ( location_arg ) ) { }
2019-05-30 20:40:56 +02:00
virtual codes : : BaseType getType ( ) const noexcept = 0 ;
2022-06-24 17:10:12 +02:00
BaseTypePtr eval ( [[maybe_unused]] Environment & env ) override { return shared_from_this ( ) ; }
2019-05-30 20:40:56 +02:00
public :
2022-06-24 17:10:12 +02:00
virtual BaseTypePtr plus ( [[maybe_unused]] const BaseTypePtr & bt ) const { throw StackTrace ( " Operator + does not exist for this type " ) ; }
2019-12-23 19:08:51 +01:00
virtual BaseTypePtr unary_plus ( ) const { throw StackTrace ( " Unary operator + does not exist for this type " ) ; }
2022-06-24 17:10:12 +02:00
virtual BaseTypePtr minus ( [[maybe_unused]] const BaseTypePtr & bt ) const { throw StackTrace ( " Operator - does not exist for this type " ) ; }
2019-12-23 19:08:51 +01:00
virtual BaseTypePtr unary_minus ( ) const { throw StackTrace ( " Unary operator - does not exist for this type " ) ; }
2022-06-24 17:10:12 +02:00
virtual BaseTypePtr times ( [[maybe_unused]] const BaseTypePtr & bt ) const { throw StackTrace ( " Operator * does not exist for this type " ) ; }
virtual BaseTypePtr divide ( [[maybe_unused]] const BaseTypePtr & bt ) const { throw StackTrace ( " Operator / does not exist for this type " ) ; }
virtual BaseTypePtr power ( [[maybe_unused]] const BaseTypePtr & btp ) const { throw StackTrace ( " Operator ^ does not exist for this type " ) ; }
virtual BoolPtr is_less ( [[maybe_unused]] const BaseTypePtr & btp ) const { throw StackTrace ( " Operator < does not exist for this type " ) ; }
virtual BoolPtr is_greater ( [[maybe_unused]] const BaseTypePtr & btp ) const { throw StackTrace ( " Operator > does not exist for this type " ) ; }
virtual BoolPtr is_less_equal ( [[maybe_unused]] const BaseTypePtr & btp ) const { throw StackTrace ( " Operator <= does not exist for this type " ) ; }
virtual BoolPtr is_greater_equal ( [[maybe_unused]] const BaseTypePtr & btp ) const { throw StackTrace ( " Operator >= does not exist for this type " ) ; }
2019-05-30 20:40:56 +02:00
virtual BoolPtr is_equal ( const BaseTypePtr & btp ) const = 0 ;
virtual BoolPtr is_different ( const BaseTypePtr & btp ) const final ;
2022-06-24 17:10:12 +02:00
virtual BoolPtr logical_and ( [[maybe_unused]] const ExpressionPtr &ep, [[maybe_unused]] Environment & env ) const { throw StackTrace ( " Operator && does not exist for this type " ) ; }
virtual BoolPtr logical_or ( [[maybe_unused]] const ExpressionPtr &ep, [[maybe_unused]] Environment & env ) const { throw StackTrace ( " Operator || does not exist for this type " ) ; }
2019-12-23 19:08:51 +01:00
virtual BoolPtr logical_not ( ) const { throw StackTrace ( " Operator ! does not exist for this type " ) ; }
2022-06-24 17:10:12 +02:00
virtual ArrayPtr set_union ( [[maybe_unused]] const BaseTypePtr & btp ) const { throw StackTrace ( " Operator | does not exist for this type " ) ; }
virtual ArrayPtr set_intersection ( [[maybe_unused]] const BaseTypePtr & btp ) const { throw StackTrace ( " Operator & does not exist for this type " ) ; }
virtual BoolPtr contains ( [[maybe_unused]] const BaseTypePtr & btp ) const { throw StackTrace ( " Second argument of `in` operator must be an array " ) ; }
2019-12-23 19:08:51 +01:00
virtual RealPtr length ( ) const { throw StackTrace ( " Operator `length` does not exist for this type " ) ; }
virtual BoolPtr isempty ( ) const { throw StackTrace ( " Operator `isempty` does not exist for this type " ) ; }
2020-12-07 17:28:29 +01:00
virtual BoolPtr isboolean ( ) const noexcept { return make_shared < Bool > ( false , location ) ; }
virtual BoolPtr isreal ( ) const noexcept { return make_shared < Bool > ( false , location ) ; }
virtual BoolPtr isinteger ( ) const noexcept { return make_shared < Bool > ( false , location ) ; }
virtual BoolPtr isstring ( ) const noexcept { return make_shared < Bool > ( false , location ) ; }
virtual BoolPtr istuple ( ) const noexcept { return make_shared < Bool > ( false , location ) ; }
virtual BoolPtr isarray ( ) const noexcept { return make_shared < Bool > ( false , location ) ; }
2022-06-24 17:10:12 +02:00
virtual RealPtr max ( [[maybe_unused]] const BaseTypePtr & btp ) const { throw StackTrace ( " Operator `max` does not exist for this type " ) ; }
virtual RealPtr min ( [[maybe_unused]] const BaseTypePtr & btp ) const { throw StackTrace ( " Operator `min` does not exist for this type " ) ; }
virtual RealPtr mod ( [[maybe_unused]] const BaseTypePtr & btp ) const { throw StackTrace ( " Operator `mod` does not exist for this type " ) ; }
2019-12-23 19:08:51 +01:00
virtual RealPtr exp ( ) const { throw StackTrace ( " Operator `exp` does not exist for this type " ) ; }
virtual RealPtr ln ( ) const { throw StackTrace ( " Operator `ln` does not exist for this type " ) ; }
virtual RealPtr log10 ( ) const { throw StackTrace ( " Operator `log10` does not exist for this type " ) ; }
virtual BoolPtr isinf ( ) const { throw StackTrace ( " Operator `isinf` does not exist for this type " ) ; }
virtual BoolPtr isnan ( ) const { throw StackTrace ( " Operator `isnan` does not exist for this type " ) ; }
virtual BoolPtr isfinite ( ) const { throw StackTrace ( " Operator `isfinite` does not exist for this type " ) ; }
virtual BoolPtr isnormal ( ) const { throw StackTrace ( " Operator `isnormal` does not exist for this type " ) ; }
virtual RealPtr sin ( ) const { throw StackTrace ( " Operator `sin` does not exist for this type " ) ; }
virtual RealPtr cos ( ) const { throw StackTrace ( " Operator `cos` does not exist for this type " ) ; }
virtual RealPtr tan ( ) const { throw StackTrace ( " Operator `tan` does not exist for this type " ) ; }
virtual RealPtr asin ( ) const { throw StackTrace ( " Operator `asin` does not exist for this type " ) ; }
virtual RealPtr acos ( ) const { throw StackTrace ( " Operator `acos` does not exist for this type " ) ; }
virtual RealPtr atan ( ) const { throw StackTrace ( " Operator `atan` does not exist for this type " ) ; }
virtual RealPtr sqrt ( ) const { throw StackTrace ( " Operator `sqrt` does not exist for this type " ) ; }
virtual RealPtr cbrt ( ) const { throw StackTrace ( " Operator `cbrt` does not exist for this type " ) ; }
virtual RealPtr sign ( ) const { throw StackTrace ( " Operator `sign` does not exist for this type " ) ; }
virtual RealPtr floor ( ) const { throw StackTrace ( " Operator `floor` does not exist for this type " ) ; }
virtual RealPtr ceil ( ) const { throw StackTrace ( " Operator `ceil` does not exist for this type " ) ; }
virtual RealPtr trunc ( ) const { throw StackTrace ( " Operator `trunc` does not exist for this type " ) ; }
virtual RealPtr sum ( ) const { throw StackTrace ( " Operator `sum` does not exist for this type " ) ; }
virtual RealPtr erf ( ) const { throw StackTrace ( " Operator `erf` does not exist for this type " ) ; }
virtual RealPtr erfc ( ) const { throw StackTrace ( " Operator `erfc` does not exist for this type " ) ; }
virtual RealPtr gamma ( ) const { throw StackTrace ( " Operator `gamma` does not exist for this type " ) ; }
virtual RealPtr lgamma ( ) const { throw StackTrace ( " Operator `lgamma` does not exist for this type " ) ; }
virtual RealPtr round ( ) const { throw StackTrace ( " Operator `round` does not exist for this type " ) ; }
virtual RealPtr normpdf ( ) const { throw StackTrace ( " Operator `normpdf` does not exist for this type " ) ; }
2022-06-24 17:10:12 +02:00
virtual RealPtr normpdf ( [[maybe_unused]] const BaseTypePtr &btp1, [[maybe_unused]] const BaseTypePtr & btp2 ) const { throw StackTrace ( " Operator `normpdf` does not exist for this type " ) ; }
2019-12-23 19:08:51 +01:00
virtual RealPtr normcdf ( ) const { throw StackTrace ( " Operator `normcdf` does not exist for this type " ) ; }
2022-06-24 17:10:12 +02:00
virtual RealPtr normcdf ( [[maybe_unused]] const BaseTypePtr &btp1, [[maybe_unused]] const BaseTypePtr & btp2 ) const { throw StackTrace ( " Operator `normcdf` does not exist for this type " ) ; }
virtual BoolPtr cast_bool ( [[maybe_unused]] Environment & env ) const { throw StackTrace ( " This type cannot be cast to a boolean " ) ; }
virtual RealPtr cast_real ( [[maybe_unused]] Environment & env ) const { throw StackTrace ( " This type cannot be cast to a real " ) ; }
2019-12-23 19:08:51 +01:00
virtual StringPtr cast_string ( ) const { throw StackTrace ( " This type cannot be cast to a string " ) ; }
virtual TuplePtr cast_tuple ( ) const { throw StackTrace ( " This type cannot be cast to a tuple " ) ; }
virtual ArrayPtr cast_array ( ) const { throw StackTrace ( " This type cannot be cast to an array " ) ; }
2022-06-24 17:10:12 +02:00
virtual BoolPtr defined ( [[maybe_unused]] const Environment & env ) const { throw StackTrace ( " Operator `defined` does not exist for this type " ) ; }
2019-05-30 20:40:56 +02:00
} ;
2019-12-23 19:08:51 +01:00
2019-05-30 20:40:56 +02:00
class Bool final : public BaseType
{
private :
2019-08-14 17:14:42 +02:00
const bool value ;
2019-05-30 20:40:56 +02:00
public :
2019-08-14 16:42:19 +02:00
Bool ( bool value_arg ,
2020-12-07 17:28:29 +01:00
Tokenizer : : location location_arg = Tokenizer : : location ( ) ) :
BaseType ( move ( location_arg ) ) ,
2019-12-23 19:08:51 +01:00
value { value_arg } { }
2022-06-24 15:08:49 +02:00
codes : : BaseType getType ( ) const noexcept override { return codes : : BaseType : : Bool ; }
string to_string ( ) const noexcept override { return value ? " true " : " false " ; }
2022-06-24 17:10:12 +02:00
void print ( ostream & output , [[maybe_unused]] bool matlab_output = false ) const noexcept override { output < < to_string ( ) ; }
2022-06-24 15:08:49 +02:00
ExpressionPtr clone ( ) const noexcept override { return make_shared < Bool > ( value , location ) ; }
2019-05-30 20:40:56 +02:00
public :
operator bool ( ) const { return value ; }
BoolPtr is_equal ( const BaseTypePtr & btp ) const override ;
2020-12-07 17:28:29 +01:00
BoolPtr logical_and ( const ExpressionPtr & ep , Environment & env ) const override ;
BoolPtr logical_or ( const ExpressionPtr & ep , Environment & env ) const override ;
2019-05-30 20:40:56 +02:00
BoolPtr logical_not ( ) const override ;
2022-06-24 15:08:49 +02:00
BoolPtr isboolean ( ) const noexcept override { return make_shared < Bool > ( true , location ) ; }
2022-06-24 17:10:12 +02:00
BoolPtr cast_bool ( [[maybe_unused]] Environment & env ) const override { return make_shared < Bool > ( value ) ; }
RealPtr cast_real ( [[maybe_unused]] Environment & env ) const override { return value ? make_shared < Real > ( 1 ) : make_shared < Real > ( 0 ) ; }
2022-06-24 15:08:49 +02:00
StringPtr cast_string ( ) const override { return make_shared < String > ( this - > to_string ( ) ) ; }
TuplePtr
cast_tuple ( ) const override
2019-08-02 22:56:01 +02:00
{
2020-12-07 17:28:29 +01:00
return make_shared < Tuple > ( vector < ExpressionPtr > { make_shared < Bool > ( value ) } ) ;
2019-08-02 22:56:01 +02:00
}
2022-06-24 15:08:49 +02:00
ArrayPtr
cast_array ( ) const override
2019-08-02 23:00:23 +02:00
{
2020-12-07 17:28:29 +01:00
return make_shared < Array > ( vector < ExpressionPtr > { make_shared < Bool > ( value ) } ) ;
2019-08-02 23:00:23 +02:00
}
2019-05-30 20:40:56 +02:00
} ;
2019-12-23 19:08:51 +01:00
2019-08-07 16:37:35 +02:00
class Real final : public BaseType
2019-05-30 20:40:56 +02:00
{
private :
2019-08-14 17:14:42 +02:00
const double value ;
2019-05-30 20:40:56 +02:00
public :
// Use strtod to handle extreme cases (e.g. 1e500, 1e-500), nan, inf
// See Note in NumericalConstants::AddNonNegativeConstant
2019-08-14 16:42:19 +02:00
Real ( const string & value_arg ,
2020-12-07 17:28:29 +01:00
Tokenizer : : location location_arg = Tokenizer : : location ( ) ) :
BaseType ( move ( location_arg ) ) ,
2019-12-23 19:08:51 +01:00
value { strtod ( value_arg . c_str ( ) , nullptr ) } { }
2019-08-07 16:37:35 +02:00
Real ( double value_arg ,
2020-12-07 17:28:29 +01:00
Tokenizer : : location location_arg = Tokenizer : : location ( ) ) :
BaseType ( move ( location_arg ) ) ,
2019-12-23 19:08:51 +01:00
value { value_arg } { }
2022-06-24 15:08:49 +02:00
codes : : BaseType getType ( ) const noexcept override { return codes : : BaseType : : Real ; }
string
to_string ( ) const noexcept override
2019-05-30 20:40:56 +02:00
{
ostringstream strs ;
strs < < setprecision ( 15 ) < < value ;
return strs . str ( ) ;
}
2022-06-24 17:10:12 +02:00
void print ( ostream & output , [[maybe_unused]] bool matlab_output = false ) const noexcept override { output < < to_string ( ) ; }
2022-06-24 15:08:49 +02:00
ExpressionPtr clone ( ) const noexcept override { return make_shared < Real > ( value , location ) ; }
2019-05-30 20:40:56 +02:00
public :
operator double ( ) const { return value ; }
BaseTypePtr plus ( const BaseTypePtr & bt ) const override ;
2022-06-24 15:08:49 +02:00
BaseTypePtr unary_plus ( ) const override { return make_shared < Real > ( value ) ; }
2019-05-30 20:40:56 +02:00
BaseTypePtr minus ( const BaseTypePtr & bt ) const override ;
2022-06-24 15:08:49 +02:00
BaseTypePtr unary_minus ( ) const override { return make_shared < Real > ( - value ) ; }
2019-05-30 20:40:56 +02:00
BaseTypePtr times ( const BaseTypePtr & bt ) const override ;
BaseTypePtr divide ( const BaseTypePtr & bt ) const override ;
BaseTypePtr power ( const BaseTypePtr & btp ) const override ;
BoolPtr is_less ( const BaseTypePtr & btp ) const override ;
BoolPtr is_greater ( const BaseTypePtr & btp ) const override ;
BoolPtr is_less_equal ( const BaseTypePtr & btp ) const override ;
BoolPtr is_greater_equal ( const BaseTypePtr & btp ) const override ;
BoolPtr is_equal ( const BaseTypePtr & btp ) const override ;
2022-06-24 15:08:49 +02:00
BoolPtr isreal ( ) const noexcept override { return make_shared < Bool > ( true , location ) ; }
BoolPtr isinteger ( ) const noexcept override
2019-08-22 15:44:31 +02:00
{
double intpart ;
2020-12-07 17:28:29 +01:00
return make_shared < Bool > ( modf ( value , & intpart ) = = 0.0 , location ) ;
2019-08-22 15:44:31 +02:00
}
2020-12-07 17:28:29 +01:00
BoolPtr logical_and ( const ExpressionPtr & ep , Environment & env ) const override ;
BoolPtr logical_or ( const ExpressionPtr & ep , Environment & env ) const override ;
2019-05-30 20:40:56 +02:00
BoolPtr logical_not ( ) const override ;
2019-08-07 16:37:35 +02:00
RealPtr max ( const BaseTypePtr & btp ) const override ;
RealPtr min ( const BaseTypePtr & btp ) const override ;
RealPtr mod ( const BaseTypePtr & btp ) const override ;
2022-06-24 15:08:49 +02:00
RealPtr exp ( ) const override { return make_shared < Real > ( std : : exp ( value ) ) ; }
RealPtr ln ( ) const override { return make_shared < Real > ( std : : log ( value ) ) ; }
RealPtr log10 ( ) const override { return make_shared < Real > ( std : : log10 ( value ) ) ; }
BoolPtr isinf ( ) const override { return make_shared < Bool > ( std : : isinf ( value ) ) ; }
BoolPtr isnan ( ) const override { return make_shared < Bool > ( std : : isnan ( value ) ) ; }
BoolPtr isfinite ( ) const override { return make_shared < Bool > ( std : : isfinite ( value ) ) ; }
BoolPtr isnormal ( ) const override { return make_shared < Bool > ( std : : isnormal ( value ) ) ; }
RealPtr sin ( ) const override { return make_shared < Real > ( std : : sin ( value ) ) ; }
RealPtr cos ( ) const override { return make_shared < Real > ( std : : cos ( value ) ) ; }
RealPtr tan ( ) const override { return make_shared < Real > ( std : : tan ( value ) ) ; }
RealPtr asin ( ) const override { return make_shared < Real > ( std : : asin ( value ) ) ; }
RealPtr acos ( ) const override { return make_shared < Real > ( std : : acos ( value ) ) ; }
RealPtr atan ( ) const override { return make_shared < Real > ( std : : atan ( value ) ) ; }
RealPtr sqrt ( ) const override { return make_shared < Real > ( std : : sqrt ( value ) ) ; }
RealPtr cbrt ( ) const override { return make_shared < Real > ( std : : cbrt ( value ) ) ; }
RealPtr
sign ( ) const override
2019-06-27 14:27:59 +02:00
{
2020-12-07 17:28:29 +01:00
return make_shared < Real > ( ( value > 0 ) ? 1. : ( ( value < 0 ) ? - 1. : 0. ) ) ;
2019-06-27 14:27:59 +02:00
}
2022-06-24 15:08:49 +02:00
RealPtr floor ( ) const override { return make_shared < Real > ( std : : floor ( value ) ) ; }
RealPtr ceil ( ) const override { return make_shared < Real > ( std : : ceil ( value ) ) ; }
RealPtr trunc ( ) const override { return make_shared < Real > ( std : : trunc ( value ) ) ; }
RealPtr erf ( ) const override { return make_shared < Real > ( std : : erf ( value ) ) ; }
RealPtr erfc ( ) const override { return make_shared < Real > ( std : : erfc ( value ) ) ; }
RealPtr gamma ( ) const override { return make_shared < Real > ( std : : tgamma ( value ) ) ; }
RealPtr lgamma ( ) const override { return make_shared < Real > ( std : : lgamma ( value ) ) ; }
RealPtr round ( ) const override { return make_shared < Real > ( std : : round ( value ) ) ; }
RealPtr
normpdf ( ) const override
2019-06-27 14:27:59 +02:00
{
2020-12-07 17:28:29 +01:00
return normpdf ( make_shared < Real > ( 0 ) , make_shared < Real > ( 1 ) ) ;
2019-06-27 14:27:59 +02:00
}
2019-08-07 16:37:35 +02:00
RealPtr normpdf ( const BaseTypePtr & btp1 , const BaseTypePtr & btp2 ) const override ;
2022-06-24 15:08:49 +02:00
RealPtr
normcdf ( ) const override
2019-06-27 14:27:59 +02:00
{
2020-12-07 17:28:29 +01:00
return normcdf ( make_shared < Real > ( 0 ) , make_shared < Real > ( 1 ) ) ;
2019-06-27 14:27:59 +02:00
}
2019-08-07 16:37:35 +02:00
RealPtr normcdf ( const BaseTypePtr & btp1 , const BaseTypePtr & btp2 ) const override ;
2022-06-24 17:10:12 +02:00
BoolPtr cast_bool ( [[maybe_unused]] Environment & env ) const override { return make_shared < Bool > ( static_cast < bool > ( value ) ) ; }
RealPtr cast_real ( [[maybe_unused]] Environment & env ) const override { return make_shared < Real > ( value ) ; }
2022-06-24 15:08:49 +02:00
StringPtr cast_string ( ) const override { return make_shared < String > ( this - > to_string ( ) ) ; }
TuplePtr
cast_tuple ( ) const override
2019-08-02 22:56:01 +02:00
{
2020-12-07 17:28:29 +01:00
return make_shared < Tuple > ( vector < ExpressionPtr > { make_shared < Real > ( value ) } ) ;
2019-08-02 22:56:01 +02:00
}
2022-06-24 15:08:49 +02:00
ArrayPtr
cast_array ( ) const override
2019-08-02 23:00:23 +02:00
{
2020-12-07 17:28:29 +01:00
return make_shared < Array > ( vector < ExpressionPtr > { make_shared < Real > ( value ) } ) ;
2019-08-02 23:00:23 +02:00
}
2019-05-30 20:40:56 +02:00
} ;
class String final : public BaseType
{
private :
2019-08-14 17:14:42 +02:00
const string value ;
2019-05-30 20:40:56 +02:00
public :
2019-08-14 16:42:19 +02:00
String ( string value_arg ,
2020-12-07 17:28:29 +01:00
Tokenizer : : location location_arg = Tokenizer : : location ( ) ) :
BaseType ( move ( location_arg ) ) ,
2019-12-23 19:08:51 +01:00
value { move ( value_arg ) } { }
2022-06-24 15:08:49 +02:00
codes : : BaseType getType ( ) const noexcept override { return codes : : BaseType : : String ; }
string to_string ( ) const noexcept override { return value ; }
2019-06-24 11:00:02 +02:00
void print ( ostream & output , bool matlab_output = false ) const noexcept override ;
2022-06-24 15:08:49 +02:00
ExpressionPtr clone ( ) const noexcept override { return make_shared < String > ( value , location ) ; }
2019-05-30 20:40:56 +02:00
public :
operator string ( ) const { return value ; }
BaseTypePtr plus ( const BaseTypePtr & bt ) const override ;
BoolPtr is_less ( const BaseTypePtr & btp ) const override ;
BoolPtr is_greater ( const BaseTypePtr & btp ) const override ;
BoolPtr is_less_equal ( const BaseTypePtr & btp ) const override ;
BoolPtr is_greater_equal ( const BaseTypePtr & btp ) const override ;
BoolPtr is_equal ( const BaseTypePtr & btp ) const override ;
2022-06-24 15:08:49 +02:00
BoolPtr isstring ( ) const noexcept override { return make_shared < Bool > ( true , location ) ; }
RealPtr length ( ) const override { return make_shared < Real > ( value . size ( ) ) ; }
BoolPtr isempty ( ) const override { return make_shared < Bool > ( value . empty ( ) ) ; }
2020-12-07 17:28:29 +01:00
BoolPtr cast_bool ( Environment & env ) const override ;
RealPtr cast_real ( Environment & env ) const override ;
2022-06-24 15:08:49 +02:00
StringPtr cast_string ( ) const override { return make_shared < String > ( value ) ; }
TuplePtr
cast_tuple ( ) const override
2019-08-02 22:56:01 +02:00
{
2020-12-07 17:28:29 +01:00
return make_shared < Tuple > ( vector < ExpressionPtr > { make_shared < String > ( value ) } ) ;
2019-08-02 22:56:01 +02:00
}
2022-06-24 15:08:49 +02:00
ArrayPtr
cast_array ( ) const override
2019-08-02 23:00:23 +02:00
{
2020-12-07 17:28:29 +01:00
return make_shared < Array > ( vector < ExpressionPtr > { make_shared < String > ( value ) } ) ;
2019-08-02 23:00:23 +02:00
}
2022-06-24 15:08:49 +02:00
BoolPtr
defined ( const Environment & env ) const override
2019-08-19 15:04:39 +02:00
{
2020-12-07 17:28:29 +01:00
return make_shared < Bool > ( env . isSymbolDefined ( value ) ) ;
2019-08-19 15:04:39 +02:00
}
2019-05-30 20:40:56 +02:00
} ;
2019-12-23 19:08:51 +01:00
2019-05-30 20:40:56 +02:00
class Tuple final : public BaseType
{
private :
2019-08-14 17:14:42 +02:00
const vector < ExpressionPtr > tup ;
2019-05-30 20:40:56 +02:00
public :
2019-08-14 16:42:19 +02:00
Tuple ( vector < ExpressionPtr > tup_arg ,
2020-12-07 17:28:29 +01:00
Tokenizer : : location location_arg = Tokenizer : : location ( ) ) :
BaseType ( move ( location_arg ) ) ,
2019-12-23 19:08:51 +01:00
tup { move ( tup_arg ) } { }
2022-06-24 15:08:49 +02:00
codes : : BaseType getType ( ) const noexcept override { return codes : : BaseType : : Tuple ; }
2019-05-30 20:40:56 +02:00
string to_string ( ) const noexcept override ;
2019-06-24 11:00:02 +02:00
void print ( ostream & output , bool matlab_output = false ) const noexcept override ;
2020-12-07 17:28:29 +01:00
BaseTypePtr eval ( Environment & env ) override ;
2019-06-25 12:14:23 +02:00
ExpressionPtr clone ( ) const noexcept override ;
2019-05-30 20:40:56 +02:00
public :
2022-06-24 15:08:49 +02:00
size_t size ( ) const { return tup . size ( ) ; }
bool empty ( ) const { return tup . empty ( ) ; }
const vector < ExpressionPtr > & getValue ( ) const { return tup ; }
const ExpressionPtr & at ( int i ) const { return tup . at ( i ) ; }
2019-05-30 20:40:56 +02:00
BoolPtr is_equal ( const BaseTypePtr & btp ) const override ;
2022-06-24 15:08:49 +02:00
BoolPtr istuple ( ) const noexcept override { return make_shared < Bool > ( true , location ) ; }
2019-05-30 20:40:56 +02:00
BoolPtr contains ( const BaseTypePtr & btp ) const override ;
2022-06-24 15:08:49 +02:00
RealPtr length ( ) const override { return make_shared < Real > ( tup . size ( ) ) ; }
BoolPtr isempty ( ) const override { return make_shared < Bool > ( empty ( ) ) ; }
2020-12-07 17:28:29 +01:00
BoolPtr cast_bool ( Environment & env ) const override ;
RealPtr cast_real ( Environment & env ) const override ;
2022-06-24 15:08:49 +02:00
StringPtr cast_string ( ) const override { return make_shared < String > ( this - > to_string ( ) ) ; }
TuplePtr cast_tuple ( ) const override { return make_shared < Tuple > ( tup ) ; }
ArrayPtr cast_array ( ) const override { return make_shared < Array > ( tup ) ; }
2019-05-30 20:40:56 +02:00
} ;
2019-12-23 19:08:51 +01:00
2019-05-30 20:40:56 +02:00
class Array final : public BaseType
{
private :
2019-08-20 14:33:15 +02:00
const vector < ExpressionPtr > arr ;
2019-05-30 20:40:56 +02:00
public :
2019-08-14 16:42:19 +02:00
Array ( vector < ExpressionPtr > arr_arg ,
2020-12-07 17:28:29 +01:00
Tokenizer : : location location_arg = Tokenizer : : location ( ) ) :
BaseType ( move ( location_arg ) ) , arr { move ( arr_arg ) } { }
2022-06-24 15:08:49 +02:00
codes : : BaseType getType ( ) const noexcept override { return codes : : BaseType : : Array ; }
2019-05-30 20:40:56 +02:00
string to_string ( ) const noexcept override ;
2019-06-24 11:00:02 +02:00
void print ( ostream & output , bool matlab_output = false ) const noexcept override ;
2020-12-07 17:28:29 +01:00
BaseTypePtr eval ( Environment & env ) override ;
2019-06-25 12:14:23 +02:00
ExpressionPtr clone ( ) const noexcept override ;
2019-05-30 20:40:56 +02:00
public :
2022-06-24 15:08:49 +02:00
size_t size ( ) const { return arr . size ( ) ; }
const vector < ExpressionPtr > & getValue ( ) const { return arr ; }
const ExpressionPtr & at ( int i ) const { return arr . at ( i ) ; }
bool empty ( ) const { return arr . empty ( ) ; }
2019-05-30 20:40:56 +02:00
BaseTypePtr plus ( const BaseTypePtr & bt ) const override ;
BaseTypePtr minus ( const BaseTypePtr & bt ) const override ;
BaseTypePtr times ( const BaseTypePtr & bt ) const override ;
BaseTypePtr power ( const BaseTypePtr & btp ) const override ;
BoolPtr is_equal ( const BaseTypePtr & btp ) const override ;
2022-06-24 15:08:49 +02:00
BoolPtr isarray ( ) const noexcept override { return make_shared < Bool > ( true , location ) ; }
2019-05-30 20:40:56 +02:00
ArrayPtr set_union ( const BaseTypePtr & btp ) const override ;
ArrayPtr set_intersection ( const BaseTypePtr & btp ) const override ;
BoolPtr contains ( const BaseTypePtr & btp ) const override ;
2022-06-24 15:08:49 +02:00
RealPtr length ( ) const override { return make_shared < Real > ( arr . size ( ) ) ; }
BoolPtr isempty ( ) const override { return make_shared < Bool > ( empty ( ) ) ; }
2019-08-07 16:37:35 +02:00
RealPtr sum ( ) const override ;
2020-12-07 17:28:29 +01:00
BoolPtr cast_bool ( Environment & env ) const override ;
RealPtr cast_real ( Environment & env ) const override ;
2022-06-24 15:08:49 +02:00
StringPtr cast_string ( ) const override { return make_shared < String > ( this - > to_string ( ) ) ; }
TuplePtr cast_tuple ( ) const override { return make_shared < Tuple > ( arr ) ; }
ArrayPtr cast_array ( ) const override { return make_shared < Array > ( arr ) ; }
2019-05-30 20:40:56 +02:00
} ;
2019-12-23 19:08:51 +01:00
2019-08-20 14:33:15 +02:00
class Range final : public BaseType
{
private :
const ExpressionPtr start , inc , end ;
public :
Range ( ExpressionPtr start_arg , ExpressionPtr end_arg ,
2020-12-07 17:28:29 +01:00
Tokenizer : : location location_arg ) :
BaseType ( move ( location_arg ) ) , start { move ( start_arg ) } , end { move ( end_arg ) } { }
2019-08-20 14:33:15 +02:00
Range ( ExpressionPtr start_arg , ExpressionPtr inc_arg , ExpressionPtr end_arg ,
2020-12-07 17:28:29 +01:00
Tokenizer : : location location_arg ) :
BaseType ( move ( location_arg ) ) ,
2019-12-23 19:08:51 +01:00
start { move ( start_arg ) } , inc { move ( inc_arg ) } , end { move ( end_arg ) } { }
2022-06-24 15:08:49 +02:00
codes : : BaseType getType ( ) const noexcept override { return codes : : BaseType : : Range ; }
string
to_string ( ) const noexcept override
2019-08-20 14:33:15 +02:00
{
string retval = " [ " + start - > to_string ( ) + " : " ;
if ( inc )
2019-12-20 16:59:30 +01:00
retval + = inc - > to_string ( ) + " : " ;
2019-08-20 14:33:15 +02:00
return retval + end - > to_string ( ) + " ] " ;
}
2022-06-24 17:10:12 +02:00
void print ( ostream & output , [[maybe_unused]] bool matlab_output = false ) const noexcept override { output < < to_string ( ) ; }
2020-12-07 17:28:29 +01:00
BaseTypePtr eval ( Environment & env ) override ;
2022-06-24 15:08:49 +02:00
ExpressionPtr
clone ( ) const noexcept override
2019-08-20 14:33:15 +02:00
{
return inc ?
2020-12-07 17:28:29 +01:00
make_shared < Range > ( start , inc , end , location )
: make_shared < Range > ( start , end , location ) ;
2019-08-20 14:33:15 +02:00
}
public :
2022-06-24 15:08:49 +02:00
BoolPtr
2022-06-24 17:10:12 +02:00
is_equal ( [[maybe_unused]] const BaseTypePtr & btp ) const override
2019-08-20 14:33:15 +02:00
{
throw StackTrace ( " Internal error: Range: Should not arrive here: is_equal " ) ;
}
} ;
2019-12-23 19:08:51 +01:00
2019-05-30 20:40:56 +02:00
class Variable final : public Expression
{
private :
const string name ;
2019-08-20 11:16:33 +02:00
const ArrayPtr indices ; // for indexing strings/arrays
2019-05-30 20:40:56 +02:00
public :
2019-08-14 16:42:19 +02:00
Variable ( string name_arg ,
2020-12-07 17:28:29 +01:00
Tokenizer : : location location_arg ) :
Expression ( move ( location_arg ) ) , name { move ( name_arg ) } { }
2019-08-14 16:42:19 +02:00
Variable ( string name_arg , ArrayPtr indices_arg ,
2020-12-07 17:28:29 +01:00
Tokenizer : : location location_arg ) :
Expression ( move ( location_arg ) ) , name { move ( name_arg ) } , indices { move ( indices_arg ) } { }
2022-06-24 15:08:49 +02:00
string to_string ( ) const noexcept override { return name ; }
2022-06-24 17:10:12 +02:00
void print ( ostream & output , [[maybe_unused]] bool matlab_output = false ) const noexcept override { output < < name ; }
2020-12-07 17:28:29 +01:00
BaseTypePtr eval ( Environment & env ) override ;
2022-06-24 15:08:49 +02:00
ExpressionPtr
clone ( ) const noexcept override
2019-06-27 14:27:59 +02:00
{
2020-12-07 17:28:29 +01:00
return indices ? make_shared < Variable > ( name , indices , location ) :
make_shared < Variable > ( name , location ) ;
2019-06-27 14:27:59 +02:00
}
2019-05-30 20:40:56 +02:00
public :
2022-06-24 15:08:49 +02:00
const string & getName ( ) const noexcept { return name ; }
codes : : BaseType getType ( const Environment & env ) const { return env . getType ( name ) ; }
2019-05-30 20:40:56 +02:00
} ;
2019-12-23 19:08:51 +01:00
2019-05-30 20:40:56 +02:00
class Function final : public Expression
{
private :
const string name ;
const vector < ExpressionPtr > args ;
public :
2019-08-14 16:42:19 +02:00
Function ( string name_arg ,
vector < ExpressionPtr > args_arg ,
2020-12-07 17:28:29 +01:00
Tokenizer : : location location_arg ) :
Expression ( move ( location_arg ) ) , name { move ( name_arg ) } , args { move ( args_arg ) } { }
2019-05-30 20:40:56 +02:00
string to_string ( ) const noexcept override ;
2022-06-24 15:08:49 +02:00
void
2022-06-24 17:10:12 +02:00
print ( ostream & output , [[maybe_unused]] bool matlab_output = false ) const noexcept override
2019-06-27 14:27:59 +02:00
{
printName ( output ) ; printArgs ( output ) ;
}
2020-12-07 17:28:29 +01:00
BaseTypePtr eval ( Environment & env ) override ;
2019-06-25 12:14:23 +02:00
ExpressionPtr clone ( ) const noexcept override ;
2019-05-30 20:40:56 +02:00
public :
2022-06-24 15:08:49 +02:00
void printName ( ostream & output ) const noexcept { output < < name ; }
2019-06-24 11:00:02 +02:00
void printArgs ( ostream & output ) const noexcept ;
2022-06-24 15:08:49 +02:00
const string & getName ( ) const { return name ; }
const vector < ExpressionPtr > & getArgs ( ) const { return args ; }
2019-05-30 20:40:56 +02:00
} ;
2019-12-23 19:08:51 +01:00
2019-05-30 20:40:56 +02:00
class UnaryOp final : public Expression
{
private :
const codes : : UnaryOp op_code ;
const ExpressionPtr arg ;
public :
UnaryOp ( codes : : UnaryOp op_code_arg ,
2019-08-14 16:42:19 +02:00
ExpressionPtr arg_arg ,
2020-12-07 17:28:29 +01:00
Tokenizer : : location location_arg ) :
Expression ( move ( location_arg ) ) , op_code { move ( op_code_arg ) } , arg { move ( arg_arg ) } { }
2019-05-30 20:40:56 +02:00
string to_string ( ) const noexcept override ;
2019-06-24 11:00:02 +02:00
void print ( ostream & output , bool matlab_output = false ) const noexcept override ;
2020-12-07 17:28:29 +01:00
BaseTypePtr eval ( Environment & env ) override ;
2022-06-24 15:08:49 +02:00
ExpressionPtr
clone ( ) const noexcept override
2019-06-27 14:27:59 +02:00
{
2020-12-07 17:28:29 +01:00
return make_shared < UnaryOp > ( op_code , arg - > clone ( ) , location ) ;
2019-06-27 14:27:59 +02:00
}
2019-05-30 20:40:56 +02:00
} ;
2019-12-23 19:08:51 +01:00
2019-05-30 20:40:56 +02:00
class BinaryOp final : public Expression
{
private :
const codes : : BinaryOp op_code ;
const ExpressionPtr arg1 , arg2 ;
public :
BinaryOp ( codes : : BinaryOp op_code_arg ,
2019-08-14 16:42:19 +02:00
ExpressionPtr arg1_arg , ExpressionPtr arg2_arg ,
2020-12-07 17:28:29 +01:00
Tokenizer : : location location_arg ) :
Expression ( move ( location_arg ) ) , op_code { op_code_arg } ,
2019-12-23 19:08:51 +01:00
arg1 { move ( arg1_arg ) } , arg2 { move ( arg2_arg ) } { }
2019-05-30 20:40:56 +02:00
public :
string to_string ( ) const noexcept override ;
2019-06-24 11:00:02 +02:00
void print ( ostream & output , bool matlab_output = false ) const noexcept override ;
2020-12-07 17:28:29 +01:00
BaseTypePtr eval ( Environment & env ) override ;
2022-06-24 15:08:49 +02:00
ExpressionPtr
clone ( ) const noexcept override
2019-06-27 14:27:59 +02:00
{
2020-12-07 17:28:29 +01:00
return make_shared < BinaryOp > ( op_code , arg1 - > clone ( ) , arg2 - > clone ( ) , location ) ;
2019-06-27 14:27:59 +02:00
}
2019-05-30 20:40:56 +02:00
} ;
2019-12-23 19:08:51 +01:00
2019-05-30 20:40:56 +02:00
class TrinaryOp final : public Expression
{
private :
const codes : : TrinaryOp op_code ;
const ExpressionPtr arg1 , arg2 , arg3 ;
public :
TrinaryOp ( codes : : TrinaryOp op_code_arg ,
2019-08-14 16:42:19 +02:00
ExpressionPtr arg1_arg , ExpressionPtr arg2_arg , ExpressionPtr arg3_arg ,
2020-12-07 17:28:29 +01:00
Tokenizer : : location location_arg ) :
Expression ( move ( location_arg ) ) , op_code { op_code_arg } ,
2019-12-23 19:08:51 +01:00
arg1 { move ( arg1_arg ) } , arg2 { move ( arg2_arg ) } , arg3 { move ( arg3_arg ) } { }
2019-05-30 20:40:56 +02:00
string to_string ( ) const noexcept override ;
2019-06-24 11:00:02 +02:00
void print ( ostream & output , bool matlab_output = false ) const noexcept override ;
2020-12-07 17:28:29 +01:00
BaseTypePtr eval ( Environment & env ) override ;
2022-06-24 15:08:49 +02:00
ExpressionPtr
clone ( ) const noexcept override
2019-06-27 14:27:59 +02:00
{
2020-12-07 17:28:29 +01:00
return make_shared < TrinaryOp > ( op_code , arg1 - > clone ( ) , arg2 - > clone ( ) , arg3 - > clone ( ) , location ) ;
2019-06-27 14:27:59 +02:00
}
2019-05-30 20:40:56 +02:00
} ;
2019-12-23 19:08:51 +01:00
2019-06-27 11:27:21 +02:00
class Comprehension final : public Expression
2019-06-25 12:14:23 +02:00
{
2019-06-27 11:27:21 +02:00
/*
* Filter : [ c_vars IN c_set WHEN c_when ] = > c_expr = = nullptr
* Map : [ c_expr FOR c_vars IN c_set ] = > c_when = = nullptr
* Filter + Map : [ c_expr FOR c_vars IN c_set WHEN c_when ] = > all members assigned
*/
2019-06-25 12:14:23 +02:00
private :
const ExpressionPtr c_expr , c_vars , c_set , c_when ;
public :
2019-08-14 16:42:19 +02:00
Comprehension ( ExpressionPtr c_expr_arg ,
ExpressionPtr c_vars_arg ,
ExpressionPtr c_set_arg ,
ExpressionPtr c_when_arg ,
2020-12-07 17:28:29 +01:00
Tokenizer : : location location_arg ) :
Expression ( move ( location_arg ) ) ,
2019-06-25 12:14:23 +02:00
c_expr { move ( c_expr_arg ) } , c_vars { move ( c_vars_arg ) } ,
2019-12-23 19:08:51 +01:00
c_set { move ( c_set_arg ) } , c_when { move ( c_when_arg ) } { }
2019-08-14 16:42:19 +02:00
Comprehension ( ExpressionPtr c_expr_arg ,
ExpressionPtr c_vars_arg ,
ExpressionPtr c_set_arg ,
2020-12-07 17:28:29 +01:00
Tokenizer : : location location_arg ) :
Expression ( move ( location_arg ) ) ,
2019-12-23 19:08:51 +01:00
c_expr { move ( c_expr_arg ) } , c_vars { move ( c_vars_arg ) } , c_set { move ( c_set_arg ) } { }
2022-06-24 17:10:12 +02:00
Comprehension ( [[maybe_unused]] bool filter_only_arg ,
2019-08-14 16:42:19 +02:00
ExpressionPtr c_vars_arg ,
ExpressionPtr c_set_arg ,
ExpressionPtr c_when_arg ,
2020-12-07 17:28:29 +01:00
Tokenizer : : location location_arg ) :
Expression ( move ( location_arg ) ) ,
2019-12-23 19:08:51 +01:00
c_vars { move ( c_vars_arg ) } , c_set { move ( c_set_arg ) } , c_when { move ( c_when_arg ) } { }
2019-06-25 12:14:23 +02:00
string to_string ( ) const noexcept override ;
void print ( ostream & output , bool matlab_output = false ) const noexcept override ;
2020-12-07 17:28:29 +01:00
BaseTypePtr eval ( Environment & env ) override ;
2019-06-27 11:27:21 +02:00
ExpressionPtr clone ( ) const noexcept override ;
2019-05-30 20:40:56 +02:00
} ;
}
# endif