This commit is contained in:
Alexander Aleksandrovič Klimov 2026-04-07 08:11:44 +00:00 committed by GitHub
commit 4e69a0315b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 77 additions and 25 deletions

View file

@ -23,6 +23,15 @@ using namespace icinga;
boost::signals2::signal<void (ScriptFrame&, ScriptError *ex, const DebugInfo&)> Expression::OnBreakpoint;
boost::thread_specific_ptr<bool> l_InBreakpointHandler;
RefIndex::RefIndex() : m_Foreign(&m_Own)
{ }
void RefIndex::Set(String own)
{
m_Own = std::move(own);
m_Foreign = &m_Own;
}
Expression::~Expression()
{ }
@ -64,7 +73,7 @@ ExpressionResult Expression::Evaluate(ScriptFrame& frame, DebugHint *dhint) cons
}
}
bool Expression::GetReference(ScriptFrame&, [[maybe_unused]] bool init_dict, [[maybe_unused]] Value* parent, [[maybe_unused]] String* index, DebugHint**) const
bool Expression::GetReference(ScriptFrame&, [[maybe_unused]] bool init_dict, [[maybe_unused]] Value *parent, RefIndex*, DebugHint**) const
{
return false;
}
@ -125,9 +134,9 @@ ExpressionResult VariableExpression::DoEvaluate(ScriptFrame& frame, DebugHint*)
BOOST_THROW_EXCEPTION(ScriptError{"Tried to access undefined script variable '" + m_Variable + "'"});
}
bool VariableExpression::GetReference(ScriptFrame& frame, [[maybe_unused]] bool init_dict, Value *parent, String *index, DebugHint **dhint) const
bool VariableExpression::GetReference(ScriptFrame& frame, [[maybe_unused]] bool init_dict, Value *parent, RefIndex *index, DebugHint **dhint) const
{
*index = m_Variable;
index->Set(&m_Variable);
if (frame.Locals && frame.Locals->Contains(m_Variable)) {
*parent = frame.Locals;
@ -155,7 +164,7 @@ bool VariableExpression::GetReference(ScriptFrame& frame, [[maybe_unused]] bool
ExpressionResult RefExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
{
Value parent;
String index;
RefIndex index;
if (!m_Operand->GetReference(frame, false, &parent, &index, &dhint))
BOOST_THROW_EXCEPTION(ScriptError("Cannot obtain reference for expression.", m_DebugInfo));
@ -163,7 +172,7 @@ ExpressionResult RefExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint)
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);
return new Reference(parent, index.Get());
}
ExpressionResult DerefExpression::DoEvaluate(ScriptFrame& frame, DebugHint*) const
@ -180,7 +189,7 @@ ExpressionResult DerefExpression::DoEvaluate(ScriptFrame& frame, DebugHint*) con
return ref->Get();
}
bool DerefExpression::GetReference(ScriptFrame& frame, [[maybe_unused]] bool init_dict, Value *parent, String *index, DebugHint**) const
bool DerefExpression::GetReference(ScriptFrame& frame, [[maybe_unused]] bool init_dict, Value *parent, RefIndex *index, DebugHint**) const
{
ExpressionResult operand = m_Operand->Evaluate(frame);
if (operand.GetCode() != ResultOK)
@ -193,7 +202,7 @@ bool DerefExpression::GetReference(ScriptFrame& frame, [[maybe_unused]] bool ini
}
*parent = ref->GetParent();
*index = ref->GetIndex();
index->Set(ref->GetIndex());
return true;
}
@ -456,10 +465,10 @@ ExpressionResult LogicalOrExpression::DoEvaluate(ScriptFrame& frame, DebugHint*)
ExpressionResult FunctionCallExpression::DoEvaluate(ScriptFrame& frame, DebugHint*) const
{
Value self, vfunc;
String index;
RefIndex index;
if (m_FName->GetReference(frame, false, &self, &index))
vfunc = VMOps::GetField(self, index, frame.Sandboxed, m_DebugInfo);
vfunc = VMOps::GetField(self, index.Get(), frame.Sandboxed, m_DebugInfo);
else {
ExpressionResult vfuncres = m_FName->Evaluate(frame);
CHECK_RESULT(vfuncres);
@ -618,7 +627,7 @@ ExpressionResult SetExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint)
DebugHint *psdhint = dhint;
Value parent;
String index;
RefIndex index;
if (!m_Operand1->GetReference(frame, true, &parent, &index, &psdhint))
BOOST_THROW_EXCEPTION(ScriptError("Expression cannot be assigned to.", m_DebugInfo));
@ -627,7 +636,7 @@ ExpressionResult SetExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint)
CHECK_RESULT(operand2);
if (m_Op != OpSetLiteral) {
Value object = VMOps::GetField(parent, index, frame.Sandboxed, m_DebugInfo);
Value object = VMOps::GetField(parent, index.Get(), frame.Sandboxed, m_DebugInfo);
switch (m_Op) {
case OpSetAdd:
@ -659,7 +668,7 @@ ExpressionResult SetExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint)
}
}
VMOps::SetField(parent, index, operand2.GetValue(), m_DebugInfo);
VMOps::SetField(parent, index.Get(), operand2.GetValue(), m_DebugInfo);
if (psdhint) {
psdhint->AddMessage("=", m_DebugInfo);
@ -747,10 +756,10 @@ ExpressionResult IndexerExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dh
return VMOps::GetField(operand1.GetValue(), operand2.GetValue(), frame.Sandboxed, m_DebugInfo);
}
bool IndexerExpression::GetReference(ScriptFrame& frame, bool init_dict, Value *parent, String *index, DebugHint **dhint) const
bool IndexerExpression::GetReference(ScriptFrame& frame, bool init_dict, Value *parent, RefIndex *index, DebugHint **dhint) const
{
Value vparent;
String vindex;
RefIndex vindex;
DebugHint *psdhint = nullptr;
bool free_psd = false;
@ -767,29 +776,35 @@ bool IndexerExpression::GetReference(ScriptFrame& frame, bool init_dict, Value *
if (vparent.IsObject()) {
Object::Ptr oparent = vparent;
has_field = oparent->HasOwnField(vindex);
has_field = oparent->HasOwnField(vindex.Get());
}
if (has_field)
old_value = VMOps::GetField(vparent, vindex, frame.Sandboxed, m_Operand1->GetDebugInfo());
old_value = VMOps::GetField(vparent, vindex.Get(), frame.Sandboxed, m_Operand1->GetDebugInfo());
if (old_value.IsEmpty() && !old_value.IsString())
VMOps::SetField(vparent, vindex, new Dictionary(), m_Operand1->GetDebugInfo());
VMOps::SetField(vparent, vindex.Get(), new Dictionary(), m_Operand1->GetDebugInfo());
}
*parent = VMOps::GetField(vparent, vindex, frame.Sandboxed, m_DebugInfo);
*parent = VMOps::GetField(vparent, vindex.Get(), frame.Sandboxed, m_DebugInfo);
free_psd = true;
} else {
ExpressionResult operand1 = m_Operand1->Evaluate(frame);
*parent = operand1.GetValue();
}
ExpressionResult operand2 = m_Operand2->Evaluate(frame);
*index = operand2.GetValue();
auto lit (dynamic_cast<LiteralExpression*>(m_Operand2.get()));
if (lit && lit->GetValue().IsString()) {
index->Set(&lit->GetValue().Get<String>());
} else {
ExpressionResult operand2 = m_Operand2->Evaluate(frame);
index->Set(operand2.GetValue());
}
if (dhint) {
if (psdhint)
*dhint = new DebugHint(psdhint->GetChild(*index));
*dhint = new DebugHint(psdhint->GetChild(index->Get()));
else
*dhint = nullptr;
}

View file

@ -177,6 +177,37 @@ private:
if (res.GetCode() == ResultBreak) \
break; \
/**
* Abstracts a maybe owned String
*
* @ingroup config
*/
class RefIndex
{
public:
RefIndex();
RefIndex(const RefIndex&) = delete;
RefIndex(RefIndex&&) = delete;
RefIndex& operator=(const RefIndex&) = delete;
RefIndex& operator=(RefIndex&&) = delete;
inline const String& Get() const noexcept
{
return *m_Foreign;
}
inline void Set(const String* foreign) noexcept
{
m_Foreign = foreign;
}
void Set(String own);
private:
const String* m_Foreign;
String m_Own;
};
/**
* @ingroup config
*/
@ -192,7 +223,13 @@ public:
Expression& operator=(const Expression&) = delete;
ExpressionResult Evaluate(ScriptFrame& frame, DebugHint *dhint = nullptr) const;
virtual bool GetReference(ScriptFrame& frame, bool init_dict, Value *parent, String *index, DebugHint **dhint = nullptr) const;
/**
* Caution! On return `*index` may point to a String somewhere in `this` (or subAST).
* Keep `this` alive while using `*index`!
*/
virtual bool GetReference(ScriptFrame& frame, bool init_dict, Value *parent, RefIndex *index, DebugHint **dhint = nullptr) const;
virtual const DebugInfo& GetDebugInfo() const;
virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const = 0;
@ -311,7 +348,7 @@ public:
protected:
ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const override;
bool GetReference(ScriptFrame& frame, bool init_dict, Value *parent, String *index, DebugHint **dhint) const override;
bool GetReference(ScriptFrame& frame, bool init_dict, Value *parent, RefIndex *index, DebugHint **dhint) const override;
private:
String m_Variable;
@ -329,7 +366,7 @@ public:
protected:
ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const override;
bool GetReference(ScriptFrame& frame, bool init_dict, Value *parent, String *index, DebugHint **dhint) const override;
bool GetReference(ScriptFrame& frame, bool init_dict, Value *parent, RefIndex *index, DebugHint **dhint) const override;
};
class RefExpression final : public UnaryExpression
@ -755,7 +792,7 @@ public:
protected:
ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const override;
bool GetReference(ScriptFrame& frame, bool init_dict, Value *parent, String *index, DebugHint **dhint) const override;
bool GetReference(ScriptFrame& frame, bool init_dict, Value *parent, RefIndex *index, DebugHint **dhint) const override;
friend void BindToScope(std::unique_ptr<Expression>& expr, ScopeSpecifier scopeSpec);
};