Implement support for modifying frozen attributes

This commit is contained in:
Gunnar Beutner 2018-08-07 13:55:41 +02:00
parent d9c0b6f806
commit 9d513d8f05
10 changed files with 86 additions and 58 deletions

View File

@ -62,13 +62,14 @@ Value Array::Get(SizeType index) const
* *
* @param index The index. * @param index The index.
* @param value The value. * @param value The value.
* @param overrideFrozen Whether to allow modifying frozen arrays.
*/ */
void Array::Set(SizeType index, const Value& value) void Array::Set(SizeType index, const Value& value, bool overrideFrozen)
{ {
ObjectLock olock(this); ObjectLock olock(this);
if (m_Frozen) if (m_Frozen && !overrideFrozen)
BOOST_THROW_EXCEPTION(std::invalid_argument("Array must not be modified.")); BOOST_THROW_EXCEPTION(std::invalid_argument("Value in array must not be modified."));
m_Data.at(index) = value; m_Data.at(index) = value;
} }
@ -78,12 +79,13 @@ void Array::Set(SizeType index, const Value& value)
* *
* @param index The index. * @param index The index.
* @param value The value. * @param value The value.
* @param overrideFrozen Whether to allow modifying frozen arrays.
*/ */
void Array::Set(SizeType index, Value&& value) void Array::Set(SizeType index, Value&& value, bool overrideFrozen)
{ {
ObjectLock olock(this); ObjectLock olock(this);
if (m_Frozen) if (m_Frozen && !overrideFrozen)
BOOST_THROW_EXCEPTION(std::invalid_argument("Array must not be modified.")); BOOST_THROW_EXCEPTION(std::invalid_argument("Array must not be modified."));
m_Data.at(index).Swap(value); m_Data.at(index).Swap(value);
@ -93,12 +95,13 @@ void Array::Set(SizeType index, Value&& value)
* Adds a value to the array. * Adds a value to the array.
* *
* @param value The value. * @param value The value.
* @param overrideFrozen Whether to allow modifying frozen arrays.
*/ */
void Array::Add(Value value) void Array::Add(Value value, bool overrideFrozen)
{ {
ObjectLock olock(this); ObjectLock olock(this);
if (m_Frozen) if (m_Frozen && !overrideFrozen)
BOOST_THROW_EXCEPTION(std::invalid_argument("Array must not be modified.")); BOOST_THROW_EXCEPTION(std::invalid_argument("Array must not be modified."));
m_Data.push_back(std::move(value)); m_Data.push_back(std::move(value));
@ -162,14 +165,15 @@ bool Array::Contains(const Value& value) const
* *
* @param index The index * @param index The index
* @param value The value to add * @param value The value to add
* @param overrideFrozen Whether to allow modifying frozen arrays.
*/ */
void Array::Insert(SizeType index, Value value) void Array::Insert(SizeType index, Value value, bool overrideFrozen)
{ {
ObjectLock olock(this); ObjectLock olock(this);
ASSERT(index <= m_Data.size()); ASSERT(index <= m_Data.size());
if (m_Frozen) if (m_Frozen && !overrideFrozen)
BOOST_THROW_EXCEPTION(std::invalid_argument("Array must not be modified.")); BOOST_THROW_EXCEPTION(std::invalid_argument("Array must not be modified."));
m_Data.insert(m_Data.begin() + index, std::move(value)); m_Data.insert(m_Data.begin() + index, std::move(value));
@ -179,12 +183,13 @@ void Array::Insert(SizeType index, Value value)
* Removes the specified index from the array. * Removes the specified index from the array.
* *
* @param index The index. * @param index The index.
* @param overrideFrozen Whether to allow modifying frozen arrays.
*/ */
void Array::Remove(SizeType index) void Array::Remove(SizeType index, bool overrideFrozen)
{ {
ObjectLock olock(this); ObjectLock olock(this);
if (m_Frozen) if (m_Frozen && !overrideFrozen)
BOOST_THROW_EXCEPTION(std::invalid_argument("Array must not be modified.")); BOOST_THROW_EXCEPTION(std::invalid_argument("Array must not be modified."));
m_Data.erase(m_Data.begin() + index); m_Data.erase(m_Data.begin() + index);
@ -194,42 +199,43 @@ void Array::Remove(SizeType index)
* Removes the item specified by the iterator from the array. * Removes the item specified by the iterator from the array.
* *
* @param it The iterator. * @param it The iterator.
* @param overrideFrozen Whether to allow modifying frozen arrays.
*/ */
void Array::Remove(Array::Iterator it) void Array::Remove(Array::Iterator it, bool overrideFrozen)
{ {
ASSERT(OwnsLock()); ASSERT(OwnsLock());
if (m_Frozen) if (m_Frozen && !overrideFrozen)
BOOST_THROW_EXCEPTION(std::invalid_argument("Array must not be modified.")); BOOST_THROW_EXCEPTION(std::invalid_argument("Array must not be modified."));
m_Data.erase(it); m_Data.erase(it);
} }
void Array::Resize(SizeType newSize) void Array::Resize(SizeType newSize, bool overrideFrozen)
{ {
ObjectLock olock(this); ObjectLock olock(this);
if (m_Frozen) if (m_Frozen && !overrideFrozen)
BOOST_THROW_EXCEPTION(std::invalid_argument("Array must not be modified.")); BOOST_THROW_EXCEPTION(std::invalid_argument("Array must not be modified."));
m_Data.resize(newSize); m_Data.resize(newSize);
} }
void Array::Clear() void Array::Clear(bool overrideFrozen)
{ {
ObjectLock olock(this); ObjectLock olock(this);
if (m_Frozen) if (m_Frozen && !overrideFrozen)
BOOST_THROW_EXCEPTION(std::invalid_argument("Array must not be modified.")); BOOST_THROW_EXCEPTION(std::invalid_argument("Array must not be modified."));
m_Data.clear(); m_Data.clear();
} }
void Array::Reserve(SizeType newSize) void Array::Reserve(SizeType newSize, bool overrideFrozen)
{ {
ObjectLock olock(this); ObjectLock olock(this);
if (m_Frozen) if (m_Frozen && !overrideFrozen)
BOOST_THROW_EXCEPTION(std::invalid_argument("Array must not be modified.")); BOOST_THROW_EXCEPTION(std::invalid_argument("Array must not be modified."));
m_Data.reserve(newSize); m_Data.reserve(newSize);
@ -288,11 +294,11 @@ Array::Ptr Array::Reverse() const
return result; return result;
} }
void Array::Sort() void Array::Sort(bool overrideFrozen)
{ {
ObjectLock olock(this); ObjectLock olock(this);
if (m_Frozen) if (m_Frozen && !overrideFrozen)
BOOST_THROW_EXCEPTION(std::invalid_argument("Array must not be modified.")); BOOST_THROW_EXCEPTION(std::invalid_argument("Array must not be modified."));
std::sort(m_Data.begin(), m_Data.end()); std::sort(m_Data.begin(), m_Data.end());
@ -342,7 +348,7 @@ Value Array::GetFieldByName(const String& field, bool sandboxed, const DebugInfo
return Get(index); return Get(index);
} }
void Array::SetFieldByName(const String& field, const Value& value, const DebugInfo& debugInfo) void Array::SetFieldByName(const String& field, const Value& value, bool overrideFrozen, const DebugInfo& debugInfo)
{ {
ObjectLock olock(this); ObjectLock olock(this);
@ -352,9 +358,9 @@ void Array::SetFieldByName(const String& field, const Value& value, const DebugI
BOOST_THROW_EXCEPTION(ScriptError("Array index '" + Convert::ToString(index) + "' is out of bounds.", debugInfo)); BOOST_THROW_EXCEPTION(ScriptError("Array index '" + Convert::ToString(index) + "' is out of bounds.", debugInfo));
if (static_cast<size_t>(index) >= GetLength()) if (static_cast<size_t>(index) >= GetLength())
Resize(index + 1); Resize(index + 1, overrideFrozen);
Set(index, value); Set(index, value, overrideFrozen);
} }
Array::Iterator icinga::begin(const Array::Ptr& x) Array::Iterator icinga::begin(const Array::Ptr& x)

View File

@ -55,9 +55,9 @@ public:
Array(std::initializer_list<Value> init); Array(std::initializer_list<Value> init);
Value Get(SizeType index) const; Value Get(SizeType index) const;
void Set(SizeType index, const Value& value); void Set(SizeType index, const Value& value, bool overrideFrozen = false);
void Set(SizeType index, Value&& value); void Set(SizeType index, Value&& value, bool overrideFrozen = false);
void Add(Value value); void Add(Value value, bool overrideFrozen = false);
Iterator Begin(); Iterator Begin();
Iterator End(); Iterator End();
@ -65,14 +65,14 @@ public:
size_t GetLength() const; size_t GetLength() const;
bool Contains(const Value& value) const; bool Contains(const Value& value) const;
void Insert(SizeType index, Value value); void Insert(SizeType index, Value value, bool overrideFrozen = false);
void Remove(SizeType index); void Remove(SizeType index, bool overrideFrozen = false);
void Remove(Iterator it); void Remove(Iterator it, bool overrideFrozen = false);
void Resize(SizeType newSize); void Resize(SizeType newSize, bool overrideFrozen = false);
void Clear(); void Clear(bool overrideFrozen = false);
void Reserve(SizeType newSize); void Reserve(SizeType newSize, bool overrideFrozen = false);
void CopyTo(const Array::Ptr& dest) const; void CopyTo(const Array::Ptr& dest) const;
Array::Ptr ShallowClone() const; Array::Ptr ShallowClone() const;
@ -108,7 +108,7 @@ public:
Array::Ptr Reverse() const; Array::Ptr Reverse() const;
void Sort(); void Sort(bool overrideFrozen = false);
String ToString() const override; String ToString() const override;
@ -116,7 +116,7 @@ public:
void Freeze(); void Freeze();
Value GetFieldByName(const String& field, bool sandboxed, const DebugInfo& debugInfo) const override; Value GetFieldByName(const String& field, bool sandboxed, const DebugInfo& debugInfo) const override;
void SetFieldByName(const String& field, const Value& value, const DebugInfo& debugInfo) override; void SetFieldByName(const String& field, const Value& value, bool overrideFrozen, const DebugInfo& debugInfo) override;
private: private:
std::vector<Value> m_Data; /**< The data for the array. */ std::vector<Value> m_Data; /**< The data for the array. */

View File

@ -89,13 +89,14 @@ bool Dictionary::Get(const String& key, Value *result) const
* *
* @param key The key. * @param key The key.
* @param value The value. * @param value The value.
* @param overrideFrozen Whether to allow modifying frozen dictionaries.
*/ */
void Dictionary::Set(const String& key, Value value) void Dictionary::Set(const String& key, Value value, bool overrideFrozen)
{ {
ObjectLock olock(this); ObjectLock olock(this);
if (m_Frozen) if (m_Frozen && !overrideFrozen)
BOOST_THROW_EXCEPTION(std::invalid_argument("Dictionary must not be modified.")); BOOST_THROW_EXCEPTION(std::invalid_argument("Value in dictionary must not be modified."));
m_Data[key] = std::move(value); m_Data[key] = std::move(value);
} }
@ -157,12 +158,13 @@ Dictionary::Iterator Dictionary::End()
* Removes the item specified by the iterator from the dictionary. * Removes the item specified by the iterator from the dictionary.
* *
* @param it The iterator. * @param it The iterator.
* @param overrideFrozen Whether to allow modifying frozen dictionaries.
*/ */
void Dictionary::Remove(Dictionary::Iterator it) void Dictionary::Remove(Dictionary::Iterator it, bool overrideFrozen)
{ {
ASSERT(OwnsLock()); ASSERT(OwnsLock());
if (m_Frozen) if (m_Frozen && !overrideFrozen)
BOOST_THROW_EXCEPTION(std::invalid_argument("Dictionary must not be modified.")); BOOST_THROW_EXCEPTION(std::invalid_argument("Dictionary must not be modified."));
m_Data.erase(it); m_Data.erase(it);
@ -172,12 +174,13 @@ void Dictionary::Remove(Dictionary::Iterator it)
* Removes the specified key from the dictionary. * Removes the specified key from the dictionary.
* *
* @param key The key. * @param key The key.
* @param overrideFrozen Whether to allow modifying frozen dictionaries.
*/ */
void Dictionary::Remove(const String& key) void Dictionary::Remove(const String& key, bool overrideFrozen)
{ {
ObjectLock olock(this); ObjectLock olock(this);
if (m_Frozen) if (m_Frozen && !overrideFrozen)
BOOST_THROW_EXCEPTION(std::invalid_argument("Dictionary must not be modified.")); BOOST_THROW_EXCEPTION(std::invalid_argument("Dictionary must not be modified."));
Dictionary::Iterator it; Dictionary::Iterator it;
@ -191,12 +194,14 @@ void Dictionary::Remove(const String& key)
/** /**
* Removes all dictionary items. * Removes all dictionary items.
*
* @param overrideFrozen Whether to allow modifying frozen dictionaries.
*/ */
void Dictionary::Clear() void Dictionary::Clear(bool overrideFrozen)
{ {
ObjectLock olock(this); ObjectLock olock(this);
if (m_Frozen) if (m_Frozen && !overrideFrozen)
BOOST_THROW_EXCEPTION(std::invalid_argument("Dictionary must not be modified.")); BOOST_THROW_EXCEPTION(std::invalid_argument("Dictionary must not be modified."));
m_Data.clear(); m_Data.clear();
@ -288,9 +293,9 @@ Value Dictionary::GetFieldByName(const String& field, bool, const DebugInfo& deb
return GetPrototypeField(const_cast<Dictionary *>(this), field, false, debugInfo); return GetPrototypeField(const_cast<Dictionary *>(this), field, false, debugInfo);
} }
void Dictionary::SetFieldByName(const String& field, const Value& value, const DebugInfo&) void Dictionary::SetFieldByName(const String& field, const Value& value, bool overrideFrozen, const DebugInfo&)
{ {
Set(field, value); Set(field, value, overrideFrozen);
} }
bool Dictionary::HasOwnField(const String& field) const bool Dictionary::HasOwnField(const String& field) const

View File

@ -58,7 +58,7 @@ public:
Value Get(const String& key) const; Value Get(const String& key) const;
bool Get(const String& key, Value *result) const; bool Get(const String& key, Value *result) const;
void Set(const String& key, Value value); void Set(const String& key, Value value, bool overrideFrozen = false);
bool Contains(const String& key) const; bool Contains(const String& key) const;
Iterator Begin(); Iterator Begin();
@ -66,11 +66,11 @@ public:
size_t GetLength() const; size_t GetLength() const;
void Remove(const String& key); void Remove(const String& key, bool overrideFrozen = false);
void Remove(Iterator it); void Remove(Iterator it, bool overrideFrozen = false);
void Clear(); void Clear(bool overrideFrozen = false);
void CopyTo(const Dictionary::Ptr& dest) const; void CopyTo(const Dictionary::Ptr& dest) const;
Dictionary::Ptr ShallowClone() const; Dictionary::Ptr ShallowClone() const;
@ -86,7 +86,7 @@ public:
void Freeze(); void Freeze();
Value GetFieldByName(const String& field, bool sandboxed, const DebugInfo& debugInfo) const override; Value GetFieldByName(const String& field, bool sandboxed, const DebugInfo& debugInfo) const override;
void SetFieldByName(const String& field, const Value& value, const DebugInfo& debugInfo) override; void SetFieldByName(const String& field, const Value& value, bool overrideFrozen, const DebugInfo& debugInfo) override;
bool HasOwnField(const String& field) const override; bool HasOwnField(const String& field) const override;
bool GetOwnField(const String& field, Value *result) const override; bool GetOwnField(const String& field, Value *result) const override;

View File

@ -138,7 +138,7 @@ Value Object::GetFieldByName(const String& field, bool sandboxed, const DebugInf
return GetField(fid); return GetField(fid);
} }
void Object::SetFieldByName(const String& field, const Value& value, const DebugInfo& debugInfo) void Object::SetFieldByName(const String& field, const Value& value, bool overrideFrozen, const DebugInfo& debugInfo)
{ {
Type::Ptr type = GetReflectionType(); Type::Ptr type = GetReflectionType();

View File

@ -183,7 +183,7 @@ public:
virtual void SetField(int id, const Value& value, bool suppress_events = false, const Value& cookie = Empty); virtual void SetField(int id, const Value& value, bool suppress_events = false, const Value& cookie = Empty);
virtual Value GetField(int id) const; virtual Value GetField(int id) const;
virtual Value GetFieldByName(const String& field, bool sandboxed, const DebugInfo& debugInfo) const; virtual Value GetFieldByName(const String& field, bool sandboxed, const DebugInfo& debugInfo) const;
virtual void SetFieldByName(const String& field, const Value& value, const DebugInfo& debugInfo); virtual void SetFieldByName(const String& field, const Value& value, bool overrideFrozen, const DebugInfo& debugInfo);
virtual bool HasOwnField(const String& field) const; virtual bool HasOwnField(const String& field) const;
virtual bool GetOwnField(const String& field, Value *result) const; virtual bool GetOwnField(const String& field, Value *result) const;
virtual void ValidateField(int id, const Lazy<Value>& lvalue, const ValidationUtils& utils); virtual void ValidateField(int id, const Lazy<Value>& lvalue, const ValidationUtils& utils);

View File

@ -41,7 +41,7 @@ Value Reference::Get() const
void Reference::Set(const Value& value) void Reference::Set(const Value& value)
{ {
m_Parent->SetFieldByName(m_Index, value, DebugInfo()); m_Parent->SetFieldByName(m_Index, value, false, DebugInfo());
} }
Object::Ptr Reference::GetParent() const Object::Ptr Reference::GetParent() const

View File

@ -608,7 +608,7 @@ ExpressionResult SetExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint)
} }
} }
VMOps::SetField(parent, index, operand2.GetValue(), m_DebugInfo); VMOps::SetField(parent, index, operand2.GetValue(), m_OverrideFrozen, m_DebugInfo);
if (psdhint) { if (psdhint) {
psdhint->AddMessage("=", m_DebugInfo); psdhint->AddMessage("=", m_DebugInfo);
@ -620,6 +620,11 @@ ExpressionResult SetExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint)
return Empty; return Empty;
} }
void SetExpression::SetOverrideFrozen()
{
m_OverrideFrozen = true;
}
ExpressionResult ConditionalExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const ExpressionResult ConditionalExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
{ {
ExpressionResult condition = m_Condition->Evaluate(frame, dhint); ExpressionResult condition = m_Condition->Evaluate(frame, dhint);
@ -699,7 +704,7 @@ bool IndexerExpression::GetReference(ScriptFrame& frame, bool init_dict, Value *
Value old_value = VMOps::GetField(vparent, vindex, frame.Sandboxed, m_Operand1->GetDebugInfo()); Value old_value = VMOps::GetField(vparent, vindex, frame.Sandboxed, m_Operand1->GetDebugInfo());
if (old_value.IsEmpty() && !old_value.IsString()) if (old_value.IsEmpty() && !old_value.IsString())
VMOps::SetField(vparent, vindex, new Dictionary(), m_Operand1->GetDebugInfo()); VMOps::SetField(vparent, vindex, new Dictionary(), m_OverrideFrozen, m_Operand1->GetDebugInfo());
} }
*parent = VMOps::GetField(vparent, vindex, frame.Sandboxed, m_DebugInfo); *parent = VMOps::GetField(vparent, vindex, frame.Sandboxed, m_DebugInfo);
@ -725,6 +730,11 @@ bool IndexerExpression::GetReference(ScriptFrame& frame, bool init_dict, Value *
return true; return true;
} }
void IndexerExpression::SetOverrideFrozen()
{
m_OverrideFrozen = true;
}
void icinga::BindToScope(std::unique_ptr<Expression>& expr, ScopeSpecifier scopeSpec) void icinga::BindToScope(std::unique_ptr<Expression>& expr, ScopeSpecifier scopeSpec)
{ {
auto *dexpr = dynamic_cast<DictExpression *>(expr.get()); auto *dexpr = dynamic_cast<DictExpression *>(expr.get());

View File

@ -644,11 +644,14 @@ public:
: BinaryExpression(std::move(operand1), std::move(operand2), debugInfo), m_Op(op) : BinaryExpression(std::move(operand1), std::move(operand2), debugInfo), m_Op(op)
{ } { }
void SetOverrideFrozen();
protected: protected:
ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const override; ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const override;
private: private:
CombinedSetOp m_Op; CombinedSetOp m_Op;
bool m_OverrideFrozen{false};
friend void BindToScope(std::unique_ptr<Expression>& expr, ScopeSpecifier scopeSpec); friend void BindToScope(std::unique_ptr<Expression>& expr, ScopeSpecifier scopeSpec);
}; };
@ -739,7 +742,11 @@ public:
: BinaryExpression(std::move(operand1), std::move(operand2), debugInfo) : BinaryExpression(std::move(operand1), std::move(operand2), debugInfo)
{ } { }
void SetOverrideFrozen();
protected: protected:
bool m_OverrideFrozen{false};
ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const override; 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, String *index, DebugHint **dhint) const override;

View File

@ -244,12 +244,12 @@ public:
return object->GetFieldByName(field, sandboxed, debugInfo); return object->GetFieldByName(field, sandboxed, debugInfo);
} }
static inline void SetField(const Object::Ptr& context, const String& field, const Value& value, const DebugInfo& debugInfo = DebugInfo()) static inline void SetField(const Object::Ptr& context, const String& field, const Value& value, bool overrideFrozen, const DebugInfo& debugInfo = DebugInfo())
{ {
if (!context) if (!context)
BOOST_THROW_EXCEPTION(ScriptError("Cannot set field '" + field + "' on a value that is not an object.", debugInfo)); BOOST_THROW_EXCEPTION(ScriptError("Cannot set field '" + field + "' on a value that is not an object.", debugInfo));
return context->SetFieldByName(field, value, debugInfo); return context->SetFieldByName(field, value, overrideFrozen, debugInfo);
} }
private: private: