mirror of https://github.com/Icinga/icinga2.git
Implement references
This commit is contained in:
parent
33492420f3
commit
8bfd419702
|
@ -168,6 +168,8 @@ Operator | Precedence | Examples (Result) | Descript
|
|||
~ | 2 | ~true (false) | Bitwise negation of the operand
|
||||
+ | 2 | +3 | Unary plus
|
||||
- | 2 | -3 | Unary minus
|
||||
& | 2 | &var (reference to 'var') | Reference operator
|
||||
* | 2 | *var | Indirection operator
|
||||
* | 3 | 5m * 10 (3000) | Multiplies two numbers
|
||||
/ | 3 | 5m / 5 (60) | Divides two numbers
|
||||
% | 3 | 17 % 12 (5) | Remainder after division
|
||||
|
@ -191,6 +193,16 @@ in | 7 | "foo" in [ "foo", "bar" ] (true) | Element
|
|||
= | 12 | a = 3 | Assignment
|
||||
=> | 15 | x => x * x (function with arg x) | Lambda, for loop
|
||||
|
||||
### References <a id="references"></a>
|
||||
|
||||
A reference to a value can be obtained using the `&` operator. The `*` operator can be used
|
||||
to dereference a reference:
|
||||
|
||||
var value = "Hello!"
|
||||
var p = &value /* p refers to value */
|
||||
*p = "Hi!"
|
||||
log(value) // Prints "Hi!" because the variable was changed
|
||||
|
||||
### Function Calls <a id="function-calls"></a>
|
||||
|
||||
Functions can be called using the `()` operator:
|
||||
|
|
|
@ -62,6 +62,7 @@ set(base_SOURCES
|
|||
perfdatavalue.cpp perfdatavalue.hpp perfdatavalue-ti.hpp
|
||||
primitivetype.cpp primitivetype.hpp
|
||||
process.cpp process.hpp
|
||||
reference.cpp reference.hpp reference-script.cpp
|
||||
registry.hpp
|
||||
ringbuffer.cpp ringbuffer.hpp
|
||||
scriptframe.cpp scriptframe.hpp
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
/******************************************************************************
|
||||
* Icinga 2 *
|
||||
* Copyright (C) 2012-2018 Icinga Development Team (https://www.icinga.com/) *
|
||||
* *
|
||||
* 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. *
|
||||
******************************************************************************/
|
||||
|
||||
#include "base/reference.hpp"
|
||||
#include "base/function.hpp"
|
||||
#include "base/functionwrapper.hpp"
|
||||
#include "base/scriptframe.hpp"
|
||||
#include "base/exception.hpp"
|
||||
|
||||
using namespace icinga;
|
||||
|
||||
static void ReferenceSet(const Value& value)
|
||||
{
|
||||
ScriptFrame *vframe = ScriptFrame::GetCurrentFrame();
|
||||
Reference::Ptr self = static_cast<Reference::Ptr>(vframe->Self);
|
||||
REQUIRE_NOT_NULL(self);
|
||||
self->Set(value);
|
||||
}
|
||||
|
||||
static Value ReferenceGet()
|
||||
{
|
||||
ScriptFrame *vframe = ScriptFrame::GetCurrentFrame();
|
||||
Reference::Ptr self = static_cast<Reference::Ptr>(vframe->Self);
|
||||
REQUIRE_NOT_NULL(self);
|
||||
return self->Get();
|
||||
}
|
||||
|
||||
Object::Ptr Reference::GetPrototype()
|
||||
{
|
||||
static Dictionary::Ptr prototype = new Dictionary({
|
||||
{ "set", new Function("Reference#set", ReferenceSet, { "value" }) },
|
||||
{ "get", new Function("Reference#get", ReferenceGet, {}, true) },
|
||||
});
|
||||
|
||||
return prototype;
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
/******************************************************************************
|
||||
* Icinga 2 *
|
||||
* Copyright (C) 2012-2018 Icinga Development Team (https://www.icinga.com/) *
|
||||
* *
|
||||
* 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. *
|
||||
******************************************************************************/
|
||||
|
||||
#include "base/reference.hpp"
|
||||
#include "base/debug.hpp"
|
||||
#include "base/primitivetype.hpp"
|
||||
#include "base/dictionary.hpp"
|
||||
#include "base/configwriter.hpp"
|
||||
#include "base/convert.hpp"
|
||||
#include "base/exception.hpp"
|
||||
|
||||
using namespace icinga;
|
||||
|
||||
REGISTER_PRIMITIVE_TYPE_NOINST(Reference, Object, Reference::GetPrototype());
|
||||
|
||||
Reference::Reference(const Object::Ptr& parent, const String& index)
|
||||
: m_Parent(parent), m_Index(index)
|
||||
{
|
||||
}
|
||||
|
||||
Value Reference::Get() const
|
||||
{
|
||||
return m_Parent->GetFieldByName(m_Index, true, DebugInfo());
|
||||
}
|
||||
|
||||
void Reference::Set(const Value& value)
|
||||
{
|
||||
m_Parent->SetFieldByName(m_Index, value, DebugInfo());
|
||||
}
|
||||
|
||||
Object::Ptr Reference::GetParent() const
|
||||
{
|
||||
return m_Parent;
|
||||
}
|
||||
|
||||
String Reference::GetIndex() const
|
||||
{
|
||||
return m_Index;
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
/******************************************************************************
|
||||
* Icinga 2 *
|
||||
* Copyright (C) 2012-2018 Icinga Development Team (https://www.icinga.com/) *
|
||||
* *
|
||||
* 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. *
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef REFERENCE_H
|
||||
#define REFERENCE_H
|
||||
|
||||
#include "base/i2-base.hpp"
|
||||
#include "base/objectlock.hpp"
|
||||
#include "base/value.hpp"
|
||||
|
||||
namespace icinga
|
||||
{
|
||||
|
||||
/**
|
||||
* A reference.
|
||||
*
|
||||
* @ingroup base
|
||||
*/
|
||||
class Reference final : public Object
|
||||
{
|
||||
public:
|
||||
DECLARE_OBJECT(Reference);
|
||||
|
||||
Reference(const Object::Ptr& parent, const String& index);
|
||||
|
||||
Value Get() const;
|
||||
void Set(const Value& value);
|
||||
|
||||
Object::Ptr GetParent() const;
|
||||
String GetIndex() const;
|
||||
|
||||
static Object::Ptr GetPrototype();
|
||||
|
||||
private:
|
||||
Object::Ptr m_Parent;
|
||||
String m_Index;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* REFERENCE_H */
|
|
@ -227,6 +227,7 @@ static void MakeRBinaryOp(Expression** result, Expression *left, Expression *rig
|
|||
%left T_PLUS T_MINUS
|
||||
%left T_MULTIPLY T_DIVIDE_OP T_MODULO
|
||||
%left UNARY_MINUS UNARY_PLUS
|
||||
%right REF_OP DEREF_OP
|
||||
%right '!' '~'
|
||||
%left '.' '(' '['
|
||||
%left T_VAR T_THIS T_GLOBALS T_LOCALS
|
||||
|
@ -881,6 +882,14 @@ rterm_no_side_effect_no_dict: T_STRING
|
|||
$$ = new VariableExpression(*$1, @1);
|
||||
delete $1;
|
||||
}
|
||||
| T_MULTIPLY rterm %prec DEREF_OP
|
||||
{
|
||||
$$ = new DerefExpression(std::unique_ptr<Expression>($2), @$);
|
||||
}
|
||||
| T_BINARY_AND rterm %prec REF_OP
|
||||
{
|
||||
$$ = new RefExpression(std::unique_ptr<Expression>($2), @$);
|
||||
}
|
||||
| '!' rterm
|
||||
{
|
||||
$$ = new LogicalNegateExpression(std::unique_ptr<Expression>($2), @$);
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include "base/exception.hpp"
|
||||
#include "base/scriptglobal.hpp"
|
||||
#include "base/loader.hpp"
|
||||
#include "base/reference.hpp"
|
||||
#include <boost/exception_ptr.hpp>
|
||||
#include <boost/exception/errinfo_nested_exception.hpp>
|
||||
|
||||
|
@ -156,6 +157,47 @@ bool VariableExpression::GetReference(ScriptFrame& frame, bool init_dict, Value
|
|||
return true;
|
||||
}
|
||||
|
||||
ExpressionResult RefExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
|
||||
{
|
||||
Value parent;
|
||||
String index;
|
||||
|
||||
if (!m_Operand->GetReference(frame, false, &parent, &index, &dhint))
|
||||
BOOST_THROW_EXCEPTION(ScriptError("Cannot obtain reference for expression.", m_DebugInfo));
|
||||
|
||||
if (!parent.IsObject())
|
||||
BOOST_THROW_EXCEPTION(ScriptError("Cannot obtain reference for expression because parent is not an object.", m_DebugInfo));
|
||||
|
||||
return new Reference(parent, index);
|
||||
}
|
||||
|
||||
ExpressionResult DerefExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
|
||||
{
|
||||
ExpressionResult operand = m_Operand->Evaluate(frame);
|
||||
CHECK_RESULT(operand);
|
||||
|
||||
Object::Ptr obj = operand.GetValue();
|
||||
Reference::Ptr ref = dynamic_pointer_cast<Reference>(obj);
|
||||
|
||||
if (!ref)
|
||||
BOOST_THROW_EXCEPTION(ScriptError("Invalid reference specified.", GetDebugInfo()));
|
||||
|
||||
return ref->Get();
|
||||
}
|
||||
|
||||
bool DerefExpression::GetReference(ScriptFrame& frame, bool init_dict, Value *parent, String *index, DebugHint **dhint) const
|
||||
{
|
||||
ExpressionResult operand = m_Operand->Evaluate(frame);
|
||||
if (operand.GetCode() != ResultOK)
|
||||
return false;
|
||||
|
||||
Reference::Ptr ref = operand.GetValue();
|
||||
|
||||
*parent = ref->GetParent();
|
||||
*index = ref->GetIndex();
|
||||
return true;
|
||||
}
|
||||
|
||||
ExpressionResult NegateExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
|
||||
{
|
||||
ExpressionResult operand = m_Operand->Evaluate(frame);
|
||||
|
|
|
@ -324,6 +324,29 @@ private:
|
|||
friend void BindToScope(std::unique_ptr<Expression>& expr, ScopeSpecifier scopeSpec);
|
||||
};
|
||||
|
||||
class DerefExpression final : public UnaryExpression
|
||||
{
|
||||
public:
|
||||
DerefExpression(std::unique_ptr<Expression> operand, const DebugInfo& debugInfo = DebugInfo())
|
||||
: UnaryExpression(std::move(operand), debugInfo)
|
||||
{ }
|
||||
|
||||
protected:
|
||||
ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const override;
|
||||
bool GetReference(ScriptFrame& frame, bool init_dict, Value *parent, String *index, DebugHint **dhint) const override;
|
||||
};
|
||||
|
||||
class RefExpression final : public UnaryExpression
|
||||
{
|
||||
public:
|
||||
RefExpression(std::unique_ptr<Expression> operand, const DebugInfo& debugInfo = DebugInfo())
|
||||
: UnaryExpression(std::move(operand), debugInfo)
|
||||
{ }
|
||||
|
||||
protected:
|
||||
ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const override;
|
||||
};
|
||||
|
||||
class NegateExpression final : public UnaryExpression
|
||||
{
|
||||
public:
|
||||
|
|
Loading…
Reference in New Issue