2013-10-20 15:06:05 +02:00
/******************************************************************************
* Icinga 2 *
2014-03-19 01:02:29 +01:00
* Copyright ( C ) 2012 - 2014 Icinga Development Team ( http : //www.icinga.org) *
2013-10-20 15:06:05 +02:00
* *
* This program 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 2 *
* of the License , or ( at your option ) any later version . *
* *
* This program 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 *
* along with this program ; if not , write to the Free Software Foundation *
* Inc . , 51 Franklin St , Fifth Floor , Boston , MA 02110 - 1301 , USA . *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2014-10-16 17:44:06 +02:00
# include "config/expression.hpp"
2014-05-25 16:23:35 +02:00
# include "config/configitem.hpp"
# include "config/configitembuilder.hpp"
# include "config/applyrule.hpp"
# include "config/objectrule.hpp"
# include "base/array.hpp"
2014-10-26 19:59:49 +01:00
# include "base/json.hpp"
2014-05-25 16:23:35 +02:00
# include "base/scriptfunction.hpp"
# include "base/scriptvariable.hpp"
# include "base/utility.hpp"
# include "base/objectlock.hpp"
# include "base/object.hpp"
2014-10-19 14:21:12 +02:00
# include "base/logger.hpp"
2014-10-01 17:01:47 +02:00
# include "base/configerror.hpp"
2014-03-18 15:29:04 +01:00
# include <boost/foreach.hpp>
2014-03-22 08:40:09 +01:00
# include <boost/exception_ptr.hpp>
# include <boost/exception/errinfo_nested_exception.hpp>
2013-10-20 15:06:05 +02:00
using namespace icinga ;
2014-10-16 17:44:06 +02:00
Expression : : Expression ( OpCallback op , const Value & operand1 , const DebugInfo & di )
2014-03-23 11:27:40 +01:00
: m_Operator ( op ) , m_Operand1 ( operand1 ) , m_Operand2 ( ) , m_DebugInfo ( di )
2014-03-22 10:29:45 +01:00
{ }
2014-10-16 17:44:06 +02:00
Expression : : Expression ( OpCallback op , const Value & operand1 , const Value & operand2 , const DebugInfo & di )
2014-03-22 10:29:45 +01:00
: m_Operator ( op ) , m_Operand1 ( operand1 ) , m_Operand2 ( operand2 ) , m_DebugInfo ( di )
{ }
2014-10-16 17:44:06 +02:00
Value Expression : : Evaluate ( const Dictionary : : Ptr & locals , DebugHint * dhint ) const
2013-10-20 15:06:05 +02:00
{
2014-03-22 10:29:45 +01:00
try {
2014-03-29 13:48:04 +01:00
# ifdef _DEBUG
2014-10-16 17:44:06 +02:00
if ( m_Operator ! = & Expression : : OpLiteral ) {
2014-03-29 13:48:04 +01:00
std : : ostringstream msgbuf ;
ShowCodeFragment ( msgbuf , m_DebugInfo , false ) ;
2014-10-19 17:52:17 +02:00
Log ( LogDebug , " Expression " )
< < " Executing: \n " < < msgbuf . str ( ) ;
2014-03-29 13:48:04 +01:00
}
# endif /* _DEBUG */
2014-08-12 15:31:47 +02:00
return m_Operator ( this , locals , dhint ) ;
2014-03-22 10:29:45 +01:00
} catch ( const std : : exception & ex ) {
if ( boost : : get_error_info < boost : : errinfo_nested_exception > ( ex ) )
throw ;
else
2014-03-23 11:27:40 +01:00
BOOST_THROW_EXCEPTION ( ConfigError ( " Error while evaluating expression: " + String ( ex . what ( ) ) ) < < boost : : errinfo_nested_exception ( boost : : current_exception ( ) ) < < errinfo_debuginfo ( m_DebugInfo ) ) ;
2014-03-22 10:29:45 +01:00
}
2013-10-20 15:06:05 +02:00
}
2014-10-16 17:44:06 +02:00
void Expression : : MakeInline ( void )
2014-03-23 11:27:40 +01:00
{
2014-10-16 17:44:06 +02:00
if ( m_Operator = = & Expression : : OpDict )
2014-03-23 17:26:31 +01:00
m_Operand2 = true ;
2014-03-23 11:27:40 +01:00
}
2014-10-16 17:44:06 +02:00
void Expression : : DumpOperand ( std : : ostream & stream , const Value & operand , int indent ) {
2014-03-23 19:58:24 +01:00
if ( operand . IsObjectType < Array > ( ) ) {
Array : : Ptr arr = operand ;
stream < < String ( indent , ' ' ) < < " Array: \n " ;
2014-03-24 09:15:45 +01:00
ObjectLock olock ( arr ) ;
2014-03-23 19:58:24 +01:00
BOOST_FOREACH ( const Value & elem , arr ) {
DumpOperand ( stream , elem , indent + 1 ) ;
}
2014-10-16 17:44:06 +02:00
} else if ( operand . IsObjectType < Expression > ( ) ) {
Expression : : Ptr left = operand ;
2014-03-23 19:58:24 +01:00
left - > Dump ( stream , indent ) ;
} else {
2014-10-26 19:59:49 +01:00
stream < < String ( indent , ' ' ) < < JsonEncode ( operand ) < < " \n " ;
2014-03-23 19:58:24 +01:00
}
}
2014-10-16 17:44:06 +02:00
void Expression : : Dump ( std : : ostream & stream , int indent ) const
2014-03-23 19:58:24 +01:00
{
String sym = Utility : : GetSymbolName ( reinterpret_cast < const void * > ( m_Operator ) ) ;
stream < < String ( indent , ' ' ) < < " op: " < < Utility : : DemangleSymbolName ( sym ) < < " \n " ;
stream < < String ( indent , ' ' ) < < " left: \n " ;
DumpOperand ( stream , m_Operand1 , indent + 1 ) ;
stream < < String ( indent , ' ' ) < < " right: \n " ;
DumpOperand ( stream , m_Operand2 , indent + 1 ) ;
}
2014-10-16 17:44:06 +02:00
Value Expression : : EvaluateOperand1 ( const Dictionary : : Ptr & locals , DebugHint * dhint ) const
2013-10-20 15:06:05 +02:00
{
2014-10-16 17:44:06 +02:00
return static_cast < Expression : : Ptr > ( m_Operand1 ) - > Evaluate ( locals , dhint ) ;
2013-10-20 15:06:05 +02:00
}
2014-10-16 17:44:06 +02:00
Value Expression : : EvaluateOperand2 ( const Dictionary : : Ptr & locals , DebugHint * dhint ) const
2014-03-22 10:29:45 +01:00
{
2014-10-16 17:44:06 +02:00
return static_cast < Expression : : Ptr > ( m_Operand2 ) - > Evaluate ( locals , dhint ) ;
2014-03-22 10:29:45 +01:00
}
2014-10-16 17:44:06 +02:00
Value Expression : : OpLiteral ( const Expression * expr , const Dictionary : : Ptr & locals , DebugHint * dhint )
2014-03-22 10:29:45 +01:00
{
2014-03-23 19:58:24 +01:00
return expr - > m_Operand1 ;
2014-03-22 10:29:45 +01:00
}
2014-10-16 17:44:06 +02:00
Value Expression : : OpVariable ( const Expression * expr , const Dictionary : : Ptr & locals , DebugHint * dhint )
2014-03-22 10:29:45 +01:00
{
2014-03-24 09:10:37 +01:00
Dictionary : : Ptr scope = locals ;
while ( scope ) {
if ( scope - > Contains ( expr - > m_Operand1 ) )
return scope - > Get ( expr - > m_Operand1 ) ;
scope = scope - > Get ( " __parent " ) ;
}
return ScriptVariable : : Get ( expr - > m_Operand1 ) ;
2014-03-22 10:29:45 +01:00
}
2014-10-16 17:44:06 +02:00
Value Expression : : OpNegate ( const Expression * expr , const Dictionary : : Ptr & locals , DebugHint * dhint )
2014-03-22 10:29:45 +01:00
{
2014-03-23 19:58:24 +01:00
return ~ ( long ) expr - > EvaluateOperand1 ( locals ) ;
2014-03-22 10:29:45 +01:00
}
2014-10-16 17:44:06 +02:00
Value Expression : : OpLogicalNegate ( const Expression * expr , const Dictionary : : Ptr & locals , DebugHint * dhint )
2014-03-28 13:25:40 +01:00
{
return ! expr - > EvaluateOperand1 ( locals ) . ToBool ( ) ;
}
2014-10-16 17:44:06 +02:00
Value Expression : : OpAdd ( const Expression * expr , const Dictionary : : Ptr & locals , DebugHint * dhint )
2014-03-22 10:29:45 +01:00
{
2014-03-23 19:58:24 +01:00
return expr - > EvaluateOperand1 ( locals ) + expr - > EvaluateOperand2 ( locals ) ;
2014-03-22 10:29:45 +01:00
}
2014-10-16 17:44:06 +02:00
Value Expression : : OpSubtract ( const Expression * expr , const Dictionary : : Ptr & locals , DebugHint * dhint )
2014-03-22 10:29:45 +01:00
{
2014-03-23 19:58:24 +01:00
return expr - > EvaluateOperand1 ( locals ) - expr - > EvaluateOperand2 ( locals ) ;
2014-03-22 10:29:45 +01:00
}
2014-10-16 17:44:06 +02:00
Value Expression : : OpMultiply ( const Expression * expr , const Dictionary : : Ptr & locals , DebugHint * dhint )
2014-03-22 10:29:45 +01:00
{
2014-03-23 19:58:24 +01:00
return expr - > EvaluateOperand1 ( locals ) * expr - > EvaluateOperand2 ( locals ) ;
2014-03-22 10:29:45 +01:00
}
2014-10-16 17:44:06 +02:00
Value Expression : : OpDivide ( const Expression * expr , const Dictionary : : Ptr & locals , DebugHint * dhint )
2014-03-22 10:29:45 +01:00
{
2014-03-23 19:58:24 +01:00
return expr - > EvaluateOperand1 ( locals ) / expr - > EvaluateOperand2 ( locals ) ;
2014-03-22 10:29:45 +01:00
}
2014-10-16 17:44:06 +02:00
Value Expression : : OpBinaryAnd ( const Expression * expr , const Dictionary : : Ptr & locals , DebugHint * dhint )
2014-03-22 10:29:45 +01:00
{
2014-03-23 19:58:24 +01:00
return expr - > EvaluateOperand1 ( locals ) & expr - > EvaluateOperand2 ( locals ) ;
2014-03-22 10:29:45 +01:00
}
2014-10-16 17:44:06 +02:00
Value Expression : : OpBinaryOr ( const Expression * expr , const Dictionary : : Ptr & locals , DebugHint * dhint )
2014-03-22 10:29:45 +01:00
{
2014-03-23 19:58:24 +01:00
return expr - > EvaluateOperand1 ( locals ) | expr - > EvaluateOperand2 ( locals ) ;
2014-03-22 10:29:45 +01:00
}
2014-10-16 17:44:06 +02:00
Value Expression : : OpShiftLeft ( const Expression * expr , const Dictionary : : Ptr & locals , DebugHint * dhint )
2014-03-22 10:29:45 +01:00
{
2014-03-23 19:58:24 +01:00
return expr - > EvaluateOperand1 ( locals ) < < expr - > EvaluateOperand2 ( locals ) ;
2014-03-22 10:29:45 +01:00
}
2014-10-16 17:44:06 +02:00
Value Expression : : OpShiftRight ( const Expression * expr , const Dictionary : : Ptr & locals , DebugHint * dhint )
2014-03-22 10:29:45 +01:00
{
2014-03-23 19:58:24 +01:00
return expr - > EvaluateOperand1 ( locals ) > > expr - > EvaluateOperand2 ( locals ) ;
2014-03-22 10:29:45 +01:00
}
2014-10-16 17:44:06 +02:00
Value Expression : : OpEqual ( const Expression * expr , const Dictionary : : Ptr & locals , DebugHint * dhint )
2014-03-22 10:29:45 +01:00
{
2014-03-23 19:58:24 +01:00
return expr - > EvaluateOperand1 ( locals ) = = expr - > EvaluateOperand2 ( locals ) ;
2014-03-22 10:29:45 +01:00
}
2014-10-16 17:44:06 +02:00
Value Expression : : OpNotEqual ( const Expression * expr , const Dictionary : : Ptr & locals , DebugHint * dhint )
2014-03-22 10:29:45 +01:00
{
2014-03-23 19:58:24 +01:00
return expr - > EvaluateOperand1 ( locals ) ! = expr - > EvaluateOperand2 ( locals ) ;
2014-03-22 10:29:45 +01:00
}
2014-10-16 17:44:06 +02:00
Value Expression : : OpLessThan ( const Expression * expr , const Dictionary : : Ptr & locals , DebugHint * dhint )
2014-03-22 10:29:45 +01:00
{
2014-03-23 19:58:24 +01:00
return expr - > EvaluateOperand1 ( locals ) < expr - > EvaluateOperand2 ( locals ) ;
2014-03-22 10:29:45 +01:00
}
2014-10-16 17:44:06 +02:00
Value Expression : : OpGreaterThan ( const Expression * expr , const Dictionary : : Ptr & locals , DebugHint * dhint )
2014-03-22 10:29:45 +01:00
{
2014-03-23 19:58:24 +01:00
return expr - > EvaluateOperand1 ( locals ) > expr - > EvaluateOperand2 ( locals ) ;
2014-03-22 10:29:45 +01:00
}
2014-10-16 17:44:06 +02:00
Value Expression : : OpLessThanOrEqual ( const Expression * expr , const Dictionary : : Ptr & locals , DebugHint * dhint )
2014-03-22 10:29:45 +01:00
{
2014-03-23 19:58:24 +01:00
return expr - > EvaluateOperand1 ( locals ) < = expr - > EvaluateOperand2 ( locals ) ;
2014-03-22 10:29:45 +01:00
}
2014-10-16 17:44:06 +02:00
Value Expression : : OpGreaterThanOrEqual ( const Expression * expr , const Dictionary : : Ptr & locals , DebugHint * dhint )
2014-03-22 10:29:45 +01:00
{
2014-03-23 19:58:24 +01:00
return expr - > EvaluateOperand1 ( locals ) > = expr - > EvaluateOperand2 ( locals ) ;
2014-03-22 10:29:45 +01:00
}
2014-10-16 17:44:06 +02:00
Value Expression : : OpIn ( const Expression * expr , const Dictionary : : Ptr & locals , DebugHint * dhint )
2013-10-20 15:06:05 +02:00
{
2014-03-23 19:58:24 +01:00
Value right = expr - > EvaluateOperand2 ( locals ) ;
2014-03-22 10:29:45 +01:00
2014-03-28 12:17:22 +01:00
if ( right . IsEmpty ( ) )
return false ;
else if ( ! right . IsObjectType < Array > ( ) )
2014-10-26 19:59:49 +01:00
BOOST_THROW_EXCEPTION ( ConfigError ( " Invalid right side argument for 'in' operator: " + JsonEncode ( right ) ) ) ;
2014-03-22 10:29:45 +01:00
2014-03-23 19:58:24 +01:00
Value left = expr - > EvaluateOperand1 ( locals ) ;
2014-03-22 10:29:45 +01:00
Array : : Ptr arr = right ;
bool found = false ;
2014-03-24 09:15:45 +01:00
ObjectLock olock ( arr ) ;
2014-03-22 10:29:45 +01:00
BOOST_FOREACH ( const Value & value , arr ) {
if ( value = = left ) {
found = true ;
break ;
}
}
return found ;
}
2014-10-16 17:44:06 +02:00
Value Expression : : OpNotIn ( const Expression * expr , const Dictionary : : Ptr & locals , DebugHint * dhint )
2014-03-22 10:29:45 +01:00
{
2014-08-12 15:31:47 +02:00
return ! OpIn ( expr , locals , dhint ) ;
2014-03-22 10:29:45 +01:00
}
2014-10-16 17:44:06 +02:00
Value Expression : : OpLogicalAnd ( const Expression * expr , const Dictionary : : Ptr & locals , DebugHint * dhint )
2014-03-22 10:29:45 +01:00
{
2014-03-23 19:58:24 +01:00
return expr - > EvaluateOperand1 ( locals ) . ToBool ( ) & & expr - > EvaluateOperand2 ( locals ) . ToBool ( ) ;
2014-03-22 10:29:45 +01:00
}
2014-10-16 17:44:06 +02:00
Value Expression : : OpLogicalOr ( const Expression * expr , const Dictionary : : Ptr & locals , DebugHint * dhint )
2014-03-22 10:29:45 +01:00
{
2014-03-23 19:58:24 +01:00
return expr - > EvaluateOperand1 ( locals ) . ToBool ( ) | | expr - > EvaluateOperand2 ( locals ) . ToBool ( ) ;
2014-03-22 10:29:45 +01:00
}
2014-10-16 17:44:06 +02:00
Value Expression : : OpFunctionCall ( const Expression * expr , const Dictionary : : Ptr & locals , DebugHint * dhint )
2014-03-22 10:29:45 +01:00
{
2014-04-02 09:04:17 +02:00
Value funcName = expr - > EvaluateOperand1 ( locals ) ;
ScriptFunction : : Ptr func ;
if ( funcName . IsObjectType < ScriptFunction > ( ) )
func = funcName ;
else
func = ScriptFunction : : GetByName ( funcName ) ;
2014-03-22 10:29:45 +01:00
if ( ! func )
BOOST_THROW_EXCEPTION ( ConfigError ( " Function ' " + funcName + " ' does not exist. " ) ) ;
2014-03-23 19:58:24 +01:00
Array : : Ptr arr = expr - > EvaluateOperand2 ( locals ) ;
2014-03-19 10:51:09 +01:00
std : : vector < Value > arguments ;
2014-05-11 06:00:34 +02:00
for ( Array : : SizeType index = 0 ; index < arr - > GetLength ( ) ; index + + ) {
2014-10-16 17:44:06 +02:00
const Expression : : Ptr & aexpr = arr - > Get ( index ) ;
2014-03-22 10:29:45 +01:00
arguments . push_back ( aexpr - > Evaluate ( locals ) ) ;
}
2013-10-20 15:06:05 +02:00
2014-03-22 10:29:45 +01:00
return func - > Invoke ( arguments ) ;
}
2013-10-20 15:06:05 +02:00
2014-10-16 17:44:06 +02:00
Value Expression : : OpArray ( const Expression * expr , const Dictionary : : Ptr & locals , DebugHint * dhint )
2014-03-22 10:29:45 +01:00
{
2014-03-23 19:58:24 +01:00
Array : : Ptr arr = expr - > m_Operand1 ;
2014-03-22 10:29:45 +01:00
Array : : Ptr result = make_shared < Array > ( ) ;
2014-03-18 15:29:04 +01:00
2014-03-22 10:29:45 +01:00
if ( arr ) {
2014-05-11 06:00:34 +02:00
for ( Array : : SizeType index = 0 ; index < arr - > GetLength ( ) ; index + + ) {
2014-10-16 17:44:06 +02:00
const Expression : : Ptr & aexpr = arr - > Get ( index ) ;
2014-03-22 10:29:45 +01:00
result - > Add ( aexpr - > Evaluate ( locals ) ) ;
2014-03-22 08:40:09 +01:00
}
2013-10-20 15:06:05 +02:00
}
2014-03-22 10:29:45 +01:00
return result ;
2013-11-03 10:41:30 +01:00
}
2014-03-23 11:27:40 +01:00
2014-10-16 17:44:06 +02:00
Value Expression : : OpDict ( const Expression * expr , const Dictionary : : Ptr & locals , DebugHint * dhint )
2014-03-23 11:27:40 +01:00
{
2014-03-23 19:58:24 +01:00
Array : : Ptr arr = expr - > m_Operand1 ;
bool in_place = expr - > m_Operand2 ;
2014-03-23 11:27:40 +01:00
Dictionary : : Ptr result = make_shared < Dictionary > ( ) ;
2014-03-24 09:10:37 +01:00
result - > Set ( " __parent " , locals ) ;
2014-03-23 11:27:40 +01:00
if ( arr ) {
2014-05-11 06:00:34 +02:00
for ( Array : : SizeType index = 0 ; index < arr - > GetLength ( ) ; index + + ) {
2014-10-16 17:44:06 +02:00
const Expression : : Ptr & aexpr = arr - > Get ( index ) ;
2014-04-09 10:36:57 +02:00
Dictionary : : Ptr alocals = in_place ? locals : result ;
2014-08-12 15:31:47 +02:00
aexpr - > Evaluate ( alocals , dhint ) ;
2014-04-09 10:36:57 +02:00
if ( alocals - > Contains ( " __result " ) )
break ;
2014-03-23 11:27:40 +01:00
}
}
2014-05-10 12:43:16 +02:00
Dictionary : : Ptr xresult = result - > ShallowClone ( ) ;
xresult - > Remove ( " __parent " ) ;
return xresult ;
2014-03-23 11:27:40 +01:00
}
2014-10-16 17:44:06 +02:00
Value Expression : : OpSet ( const Expression * expr , const Dictionary : : Ptr & locals , DebugHint * dhint )
2014-03-23 11:27:40 +01:00
{
2014-03-30 10:00:11 +02:00
Value index = expr - > EvaluateOperand1 ( locals ) ;
2014-08-16 22:12:40 +02:00
DebugHint * sdhint = NULL ;
if ( dhint )
sdhint = dhint - > GetChild ( index ) ;
2014-08-12 15:31:47 +02:00
Value right = expr - > EvaluateOperand2 ( locals , sdhint ) ;
2014-03-30 10:00:11 +02:00
locals - > Set ( index , right ) ;
2014-08-16 22:12:40 +02:00
if ( sdhint )
sdhint - > AddMessage ( " = " , expr - > m_DebugInfo ) ;
2014-03-23 11:27:40 +01:00
return right ;
}
2014-10-16 17:44:06 +02:00
Value Expression : : OpSetPlus ( const Expression * expr , const Dictionary : : Ptr & locals , DebugHint * dhint )
2014-03-23 11:27:40 +01:00
{
2014-03-30 10:00:11 +02:00
Value index = expr - > EvaluateOperand1 ( locals ) ;
Value left = locals - > Get ( index ) ;
2014-10-16 17:44:06 +02:00
Expression : : Ptr exp_right = expr - > m_Operand2 ;
2014-03-23 17:26:31 +01:00
Dictionary : : Ptr xlocals = locals ;
2014-10-16 17:44:06 +02:00
if ( exp_right - > m_Operator = = & Expression : : OpDict ) {
2014-03-23 17:26:31 +01:00
xlocals = left ;
2014-03-23 19:58:24 +01:00
if ( ! xlocals )
xlocals = make_shared < Dictionary > ( ) ;
2014-03-24 09:44:18 +01:00
xlocals - > Set ( " __parent " , locals ) ;
2014-03-23 19:58:24 +01:00
}
2014-08-16 22:12:40 +02:00
DebugHint * sdhint = NULL ;
if ( dhint )
sdhint = dhint - > GetChild ( index ) ;
2014-08-12 15:31:47 +02:00
Value result = left + expr - > EvaluateOperand2 ( xlocals , sdhint ) ;
2014-03-24 09:44:18 +01:00
2014-10-16 17:44:06 +02:00
if ( exp_right - > m_Operator = = & Expression : : OpDict ) {
2014-03-24 11:34:41 +01:00
Dictionary : : Ptr dict = result ;
dict - > Remove ( " __parent " ) ;
}
2014-03-24 09:44:18 +01:00
2014-03-30 10:00:11 +02:00
locals - > Set ( index , result ) ;
2014-08-16 22:12:40 +02:00
if ( sdhint )
sdhint - > AddMessage ( " += " , expr - > m_DebugInfo ) ;
2014-08-12 15:31:47 +02:00
2014-03-23 11:27:40 +01:00
return result ;
}
2014-10-16 17:44:06 +02:00
Value Expression : : OpSetMinus ( const Expression * expr , const Dictionary : : Ptr & locals , DebugHint * dhint )
2014-03-23 11:27:40 +01:00
{
2014-03-30 10:00:11 +02:00
Value index = expr - > EvaluateOperand1 ( locals ) ;
Value left = locals - > Get ( index ) ;
2014-10-16 17:44:06 +02:00
Expression : : Ptr exp_right = expr - > m_Operand2 ;
2014-03-23 17:26:31 +01:00
Dictionary : : Ptr xlocals = locals ;
2014-10-16 17:44:06 +02:00
if ( exp_right - > m_Operator = = & Expression : : OpDict ) {
2014-03-23 17:26:31 +01:00
xlocals = left ;
2014-03-23 19:58:24 +01:00
if ( ! xlocals )
xlocals = make_shared < Dictionary > ( ) ;
2014-03-24 09:44:18 +01:00
xlocals - > Set ( " __parent " , locals ) ;
2014-03-23 19:58:24 +01:00
}
2014-08-16 22:12:40 +02:00
DebugHint * sdhint = NULL ;
if ( dhint )
sdhint = dhint - > GetChild ( index ) ;
2014-08-12 15:31:47 +02:00
Value result = left - expr - > EvaluateOperand2 ( xlocals , sdhint ) ;
2014-03-24 09:44:18 +01:00
2014-10-16 17:44:06 +02:00
if ( exp_right - > m_Operator = = & Expression : : OpDict ) {
2014-03-24 11:34:41 +01:00
Dictionary : : Ptr dict = result ;
dict - > Remove ( " __parent " ) ;
}
2014-03-24 09:44:18 +01:00
2014-03-30 10:00:11 +02:00
locals - > Set ( index , result ) ;
2014-08-16 22:12:40 +02:00
if ( sdhint )
sdhint - > AddMessage ( " -= " , expr - > m_DebugInfo ) ;
2014-08-12 15:31:47 +02:00
2014-03-23 11:27:40 +01:00
return result ;
}
2014-10-16 17:44:06 +02:00
Value Expression : : OpSetMultiply ( const Expression * expr , const Dictionary : : Ptr & locals , DebugHint * dhint )
2014-03-23 11:27:40 +01:00
{
2014-03-30 10:00:11 +02:00
Value index = expr - > EvaluateOperand1 ( locals ) ;
Value left = locals - > Get ( index ) ;
2014-10-16 17:44:06 +02:00
Expression : : Ptr exp_right = expr - > m_Operand2 ;
2014-03-23 17:26:31 +01:00
Dictionary : : Ptr xlocals = locals ;
2014-10-16 17:44:06 +02:00
if ( exp_right - > m_Operator = = & Expression : : OpDict ) {
2014-03-23 17:26:31 +01:00
xlocals = left ;
2014-03-23 19:58:24 +01:00
if ( ! xlocals )
xlocals = make_shared < Dictionary > ( ) ;
2014-03-24 09:44:18 +01:00
xlocals - > Set ( " __parent " , locals ) ;
2014-03-23 19:58:24 +01:00
}
2014-08-16 22:12:40 +02:00
DebugHint * sdhint = NULL ;
if ( dhint )
sdhint = dhint - > GetChild ( index ) ;
2014-08-12 15:31:47 +02:00
Value result = left * expr - > EvaluateOperand2 ( xlocals , sdhint ) ;
2014-03-24 09:44:18 +01:00
2014-10-16 17:44:06 +02:00
if ( exp_right - > m_Operator = = & Expression : : OpDict ) {
2014-03-24 11:34:41 +01:00
Dictionary : : Ptr dict = result ;
dict - > Remove ( " __parent " ) ;
}
2014-03-24 09:44:18 +01:00
2014-03-30 10:00:11 +02:00
locals - > Set ( index , result ) ;
2014-08-16 22:12:40 +02:00
if ( sdhint )
sdhint - > AddMessage ( " *= " , expr - > m_DebugInfo ) ;
2014-08-12 15:31:47 +02:00
2014-03-23 11:27:40 +01:00
return result ;
}
2014-10-16 17:44:06 +02:00
Value Expression : : OpSetDivide ( const Expression * expr , const Dictionary : : Ptr & locals , DebugHint * dhint )
2014-03-23 11:27:40 +01:00
{
2014-03-30 10:00:11 +02:00
Value index = expr - > EvaluateOperand1 ( locals ) ;
Value left = locals - > Get ( index ) ;
2014-10-16 17:44:06 +02:00
Expression : : Ptr exp_right = expr - > m_Operand2 ;
2014-03-23 17:26:31 +01:00
Dictionary : : Ptr xlocals = locals ;
2014-10-16 17:44:06 +02:00
if ( exp_right - > m_Operator = = & Expression : : OpDict ) {
2014-03-23 17:26:31 +01:00
xlocals = left ;
2014-03-23 19:58:24 +01:00
if ( ! xlocals )
xlocals = make_shared < Dictionary > ( ) ;
2014-03-24 09:44:18 +01:00
xlocals - > Set ( " __parent " , locals ) ;
2014-03-23 19:58:24 +01:00
}
2014-08-16 22:12:40 +02:00
DebugHint * sdhint = NULL ;
if ( dhint )
sdhint = dhint - > GetChild ( index ) ;
2014-08-12 15:31:47 +02:00
Value result = left / expr - > EvaluateOperand2 ( xlocals , sdhint ) ;
2014-03-24 09:44:18 +01:00
2014-10-16 17:44:06 +02:00
if ( exp_right - > m_Operator = = & Expression : : OpDict ) {
2014-03-24 11:34:41 +01:00
Dictionary : : Ptr dict = result ;
dict - > Remove ( " __parent " ) ;
}
2014-03-24 09:44:18 +01:00
2014-03-30 10:00:11 +02:00
locals - > Set ( index , result ) ;
2014-08-16 22:12:40 +02:00
if ( sdhint )
sdhint - > AddMessage ( " /= " , expr - > m_DebugInfo ) ;
2014-08-12 15:31:47 +02:00
2014-03-23 11:27:40 +01:00
return result ;
}
2014-03-23 17:26:31 +01:00
2014-10-16 17:44:06 +02:00
Value Expression : : OpIndexer ( const Expression * expr , const Dictionary : : Ptr & locals , DebugHint * dhint )
2014-03-23 17:26:31 +01:00
{
2014-03-28 12:17:22 +01:00
Value value = expr - > EvaluateOperand1 ( locals ) ;
Value index = expr - > EvaluateOperand2 ( locals ) ;
if ( value . IsObjectType < Dictionary > ( ) ) {
Dictionary : : Ptr dict = value ;
return dict - > Get ( index ) ;
2014-05-10 10:46:49 +02:00
} else if ( value . IsObjectType < Array > ( ) ) {
Array : : Ptr arr = value ;
return arr - > Get ( index ) ;
2014-03-28 12:17:22 +01:00
} else if ( value . IsObjectType < Object > ( ) ) {
Object : : Ptr object = value ;
2014-11-03 00:44:04 +01:00
Type : : Ptr type = object - > GetReflectionType ( ) ;
2014-03-28 12:17:22 +01:00
if ( ! type )
BOOST_THROW_EXCEPTION ( ConfigError ( " Dot operator applied to object which does not support reflection " ) ) ;
int field = type - > GetFieldId ( index ) ;
if ( field = = - 1 )
BOOST_THROW_EXCEPTION ( ConfigError ( " Tried to access invalid property ' " + index + " ' " ) ) ;
return object - > GetField ( field ) ;
2014-03-28 16:32:15 +01:00
} else if ( value . IsEmpty ( ) ) {
return Empty ;
2014-03-28 12:17:22 +01:00
} else {
BOOST_THROW_EXCEPTION ( ConfigError ( " Dot operator cannot be applied to type ' " + value . GetTypeName ( ) + " ' " ) ) ;
}
2014-03-23 17:26:31 +01:00
}
2014-03-27 12:30:24 +01:00
2014-10-16 17:44:06 +02:00
Value Expression : : OpImport ( const Expression * expr , const Dictionary : : Ptr & locals , DebugHint * dhint )
2014-03-27 12:30:24 +01:00
{
Value type = expr - > EvaluateOperand1 ( locals ) ;
Value name = expr - > EvaluateOperand2 ( locals ) ;
ConfigItem : : Ptr item = ConfigItem : : GetObject ( type , name ) ;
if ( ! item )
BOOST_THROW_EXCEPTION ( ConfigError ( " Import references unknown template: ' " + name + " ' " ) ) ;
2014-08-12 15:31:47 +02:00
item - > GetExpressionList ( ) - > Evaluate ( locals , dhint ) ;
2014-03-27 12:30:24 +01:00
return Empty ;
}
2014-03-30 15:04:53 +02:00
2014-10-16 17:44:06 +02:00
Value Expression : : FunctionWrapper ( const std : : vector < Value > & arguments , const Array : : Ptr & funcargs , const Expression : : Ptr & expr , const Dictionary : : Ptr & scope )
2014-03-30 15:04:53 +02:00
{
if ( arguments . size ( ) < funcargs - > GetLength ( ) )
BOOST_THROW_EXCEPTION ( ConfigError ( " Too few arguments for function " ) ) ;
Dictionary : : Ptr locals = make_shared < Dictionary > ( ) ;
locals - > Set ( " __parent " , scope ) ;
2014-05-11 06:00:34 +02:00
for ( std : : vector < Value > : : size_type i = 0 ; i < std : : min ( arguments . size ( ) , funcargs - > GetLength ( ) ) ; i + + )
2014-03-30 15:04:53 +02:00
locals - > Set ( funcargs - > Get ( i ) , arguments [ i ] ) ;
2014-04-02 09:04:49 +02:00
expr - > Evaluate ( locals ) ;
return locals - > Get ( " __result " ) ;
2014-03-30 15:04:53 +02:00
}
2014-10-16 17:44:06 +02:00
Value Expression : : OpFunction ( const Expression * expr , const Dictionary : : Ptr & locals , DebugHint * dhint )
2014-03-30 15:04:53 +02:00
{
Array : : Ptr left = expr - > m_Operand1 ;
2014-10-16 17:44:06 +02:00
Expression : : Ptr aexpr = left - > Get ( 1 ) ;
2014-03-30 15:04:53 +02:00
String name = left - > Get ( 0 ) ;
Array : : Ptr funcargs = expr - > m_Operand2 ;
2014-10-16 17:44:06 +02:00
ScriptFunction : : Ptr func = make_shared < ScriptFunction > ( boost : : bind ( & Expression : : FunctionWrapper , _1 , funcargs , aexpr , locals ) ) ;
2014-04-02 09:04:17 +02:00
if ( ! name . IsEmpty ( ) )
ScriptFunction : : Register ( name , func ) ;
return func ;
2014-03-30 15:04:53 +02:00
}
2014-10-16 17:44:06 +02:00
Value Expression : : OpApply ( const Expression * expr , const Dictionary : : Ptr & locals , DebugHint * dhint )
2014-03-30 15:04:53 +02:00
{
Array : : Ptr left = expr - > m_Operand1 ;
2014-10-16 17:44:06 +02:00
Expression : : Ptr exprl = expr - > m_Operand2 ;
2014-03-30 15:04:53 +02:00
String type = left - > Get ( 0 ) ;
2014-04-05 12:56:56 +02:00
String target = left - > Get ( 1 ) ;
2014-10-16 17:44:06 +02:00
Expression : : Ptr aname = left - > Get ( 2 ) ;
Expression : : Ptr filter = left - > Get ( 3 ) ;
2014-11-04 11:01:00 +01:00
String fkvar = left - > Get ( 4 ) ;
String fvvar = left - > Get ( 5 ) ;
Expression : : Ptr fterm = left - > Get ( 6 ) ;
2014-03-30 15:04:53 +02:00
2014-08-12 15:31:47 +02:00
String name = aname - > Evaluate ( locals , dhint ) ;
2014-03-30 15:04:53 +02:00
2014-11-04 11:01:00 +01:00
ApplyRule : : AddRule ( type , target , name , exprl , filter , fkvar , fvvar , fterm , expr - > m_DebugInfo , locals ) ;
2014-03-30 15:04:53 +02:00
return Empty ;
}
2014-10-16 17:44:06 +02:00
Value Expression : : OpObject ( const Expression * expr , const Dictionary : : Ptr & locals , DebugHint * dhint )
2014-03-30 15:04:53 +02:00
{
Array : : Ptr left = expr - > m_Operand1 ;
2014-10-16 17:44:06 +02:00
Expression : : Ptr exprl = expr - > m_Operand2 ;
2014-03-30 15:04:53 +02:00
bool abstract = left - > Get ( 0 ) ;
String type = left - > Get ( 1 ) ;
2014-10-16 17:44:06 +02:00
Expression : : Ptr aname = left - > Get ( 2 ) ;
Expression : : Ptr filter = left - > Get ( 3 ) ;
2014-05-03 20:02:22 +02:00
String zone = left - > Get ( 4 ) ;
2014-03-30 15:04:53 +02:00
2014-08-12 15:31:47 +02:00
String name = aname - > Evaluate ( locals , dhint ) ;
2014-03-30 15:04:53 +02:00
ConfigItemBuilder : : Ptr item = make_shared < ConfigItemBuilder > ( expr - > m_DebugInfo ) ;
2014-04-05 22:53:44 +02:00
String checkName = name ;
2014-03-30 15:04:53 +02:00
2014-04-05 22:53:44 +02:00
if ( ! abstract ) {
2014-11-03 00:44:04 +01:00
shared_ptr < NameComposer > nc = dynamic_pointer_cast < NameComposer > ( Type : : GetByName ( type ) ) ;
2014-04-05 22:53:44 +02:00
2014-04-06 08:09:49 +02:00
if ( nc )
checkName = nc - > MakeName ( name , Dictionary : : Ptr ( ) ) ;
2014-04-05 22:53:44 +02:00
}
if ( ! checkName . IsEmpty ( ) ) {
2014-04-05 23:07:52 +02:00
ConfigItem : : Ptr oldItem = ConfigItem : : GetObject ( type , checkName ) ;
2014-04-05 22:53:44 +02:00
if ( oldItem ) {
std : : ostringstream msgbuf ;
msgbuf < < " Object ' " < < name < < " ' of type ' " < < type < < " ' re-defined: " < < expr - > m_DebugInfo < < " ; previous definition: " < < oldItem - > GetDebugInfo ( ) ;
BOOST_THROW_EXCEPTION ( ConfigError ( msgbuf . str ( ) ) < < errinfo_debuginfo ( expr - > m_DebugInfo ) ) ;
}
2014-03-30 15:04:53 +02:00
}
item - > SetType ( type ) ;
if ( name . FindFirstOf ( " ! " ) ! = String : : NPos ) {
std : : ostringstream msgbuf ;
msgbuf < < " Name for object ' " < < name < < " ' of type ' " < < type < < " ' is invalid: Object names may not contain '!' " ;
BOOST_THROW_EXCEPTION ( ConfigError ( msgbuf . str ( ) ) < < errinfo_debuginfo ( expr - > m_DebugInfo ) ) ;
}
item - > SetName ( name ) ;
item - > AddExpression ( exprl ) ;
item - > SetAbstract ( abstract ) ;
item - > SetScope ( locals ) ;
2014-05-03 20:02:22 +02:00
item - > SetZone ( zone ) ;
2014-03-30 15:04:53 +02:00
item - > Compile ( ) - > Register ( ) ;
2014-04-23 12:44:36 +02:00
ObjectRule : : AddRule ( type , name , exprl , filter , expr - > m_DebugInfo , locals ) ;
2014-03-30 15:04:53 +02:00
return Empty ;
2014-04-02 09:04:17 +02:00
}
2014-05-10 11:26:56 +02:00
2014-10-16 17:44:06 +02:00
Value Expression : : OpFor ( const Expression * expr , const Dictionary : : Ptr & locals , DebugHint * dhint )
2014-05-10 11:26:56 +02:00
{
Array : : Ptr left = expr - > m_Operand1 ;
2014-11-04 11:01:00 +01:00
String kvar = left - > Get ( 0 ) ;
String vvar = left - > Get ( 1 ) ;
Expression : : Ptr aexpr = left - > Get ( 2 ) ;
2014-10-16 17:44:06 +02:00
Expression : : Ptr ascope = expr - > m_Operand2 ;
2014-05-10 11:26:56 +02:00
2014-11-04 11:01:00 +01:00
Value value = aexpr - > Evaluate ( locals , dhint ) ;
2014-05-10 11:26:56 +02:00
2014-11-04 11:01:00 +01:00
if ( value . IsObjectType < Array > ( ) ) {
if ( ! vvar . IsEmpty ( ) )
BOOST_THROW_EXCEPTION ( ConfigError ( " Cannot use dictionary iterator for array. " ) < < errinfo_debuginfo ( expr - > m_DebugInfo ) ) ;
2014-05-10 11:26:56 +02:00
2014-11-04 11:01:00 +01:00
Array : : Ptr arr = value ;
ObjectLock olock ( arr ) ;
BOOST_FOREACH ( const Value & value , arr ) {
Dictionary : : Ptr xlocals = make_shared < Dictionary > ( ) ;
xlocals - > Set ( " __parent " , locals ) ;
xlocals - > Set ( kvar , value ) ;
ascope - > Evaluate ( xlocals , dhint ) ;
}
} else if ( value . IsObjectType < Dictionary > ( ) ) {
if ( vvar . IsEmpty ( ) )
BOOST_THROW_EXCEPTION ( ConfigError ( " Cannot use array iterator for dictionary. " ) < < errinfo_debuginfo ( expr - > m_DebugInfo ) ) ;
Dictionary : : Ptr dict = value ;
ObjectLock olock ( dict ) ;
BOOST_FOREACH ( const Dictionary : : Pair & kv , dict ) {
Dictionary : : Ptr xlocals = make_shared < Dictionary > ( ) ;
xlocals - > Set ( " __parent " , locals ) ;
xlocals - > Set ( kvar , kv . first ) ;
xlocals - > Set ( vvar , kv . second ) ;
ascope - > Evaluate ( xlocals , dhint ) ;
}
} else
BOOST_THROW_EXCEPTION ( ConfigError ( " Invalid type in __for expression: " + value . GetTypeName ( ) ) < < errinfo_debuginfo ( expr - > m_DebugInfo ) ) ;
2014-05-10 11:26:56 +02:00
return Empty ;
}
2014-08-12 15:31:47 +02:00
Dictionary : : Ptr DebugHint : : ToDictionary ( void ) const
{
Dictionary : : Ptr result = make_shared < Dictionary > ( ) ;
Array : : Ptr messages = make_shared < Array > ( ) ;
typedef std : : pair < String , DebugInfo > MessageType ;
BOOST_FOREACH ( const MessageType & message , Messages ) {
Array : : Ptr amsg = make_shared < Array > ( ) ;
amsg - > Add ( message . first ) ;
amsg - > Add ( message . second . Path ) ;
amsg - > Add ( message . second . FirstLine ) ;
amsg - > Add ( message . second . FirstColumn ) ;
amsg - > Add ( message . second . LastLine ) ;
amsg - > Add ( message . second . LastColumn ) ;
messages - > Add ( amsg ) ;
}
result - > Set ( " messages " , messages ) ;
Dictionary : : Ptr properties = make_shared < Dictionary > ( ) ;
typedef std : : map < String , DebugHint > : : value_type ChildType ;
BOOST_FOREACH ( const ChildType & kv , Children ) {
properties - > Set ( kv . first , kv . second . ToDictionary ( ) ) ;
}
result - > Set ( " properties " , properties ) ;
return result ;
}