From d366dd8e30218702d0b2dba917ca4a247100eac1 Mon Sep 17 00:00:00 2001 From: Gunnar Beutner Date: Sun, 23 Nov 2014 15:20:51 +0100 Subject: [PATCH] Fix the reduce/reduce conflicts refs #7800 --- lib/config/config_parser.yy | 44 ++++++++------- lib/config/configitembuilder.cpp | 5 +- lib/config/expression.cpp | 21 +++++-- lib/config/expression.hpp | 14 ++++- lib/config/vmops.hpp | 96 +++++++++++++++++--------------- test/config-ops.cpp | 3 +- 6 files changed, 105 insertions(+), 78 deletions(-) diff --git a/lib/config/config_parser.yy b/lib/config/config_parser.yy index 9ba840a72..4625dacc7 100644 --- a/lib/config/config_parser.yy +++ b/lib/config/config_parser.yy @@ -181,6 +181,7 @@ static void MakeRBinaryOp(Expression** result, Expression *left, Expression *rig %type combined_set_op %type type %type rterm +%type rterm_without_indexer %type rterm_array %type rterm_scope %type lterm @@ -505,17 +506,10 @@ identifier_items_inner: /* empty */ } ; -indexer: identifier - { - $$ = new std::vector(); - $$->push_back(MakeLiteral($1)); - free($1); - } - | identifier indexer_items +indexer: rterm_without_indexer indexer_items { $$ = $2; - $$->insert($$->begin(), MakeLiteral($1)); - free($1); + $$->insert($$->begin(), $1); } ; @@ -591,6 +585,16 @@ lterm: T_LOCAL indexer combined_set_op rterm $$ = new SetExpression(*$1, $2, $3, false, DebugInfoRange(@1, @3)); delete $1; } + | T_LOCAL identifier combined_set_op rterm + { + $$ = new SetExpression(MakeIndexer($2), $3, $4, true, DebugInfoRange(@1, @4)); + free($2); + } + | identifier combined_set_op rterm + { + $$ = new SetExpression(MakeIndexer($1), $2, $3, false, DebugInfoRange(@1, @3)); + free($1); + } | T_INCLUDE rterm { VMFrame frame; @@ -735,7 +739,18 @@ rterm_scope: '{' newlines lterm_items newlines '}' } ; -rterm: T_STRING +rterm: rterm_without_indexer + { + $$ = $1; + } + | indexer + { + $$ = new IndexerExpression(*$1, @1); + delete $1; + } + ; + +rterm_without_indexer: T_STRING { $$ = MakeLiteral($1); free($1); @@ -748,11 +763,6 @@ rterm: T_STRING { $$ = MakeLiteral(); } - | rterm '.' T_IDENTIFIER - { - $$ = new IndexerExpression($1, MakeLiteral($3), DebugInfoRange(@1, @3)); - free($3); - } | rterm '(' rterm_items ')' { $$ = new FunctionCallExpression($1, *$3, DebugInfoRange(@1, @4)); @@ -771,10 +781,6 @@ rterm: T_STRING { $$ = new NegateExpression($2, DebugInfoRange(@1, @2)); } - | rterm '[' rterm ']' - { - $$ = new IndexerExpression($1, $3, DebugInfoRange(@1, @4)); - } | rterm_array { $$ = $1; diff --git a/lib/config/configitembuilder.cpp b/lib/config/configitembuilder.cpp index f74cb8e7f..8601760e5 100644 --- a/lib/config/configitembuilder.cpp +++ b/lib/config/configitembuilder.cpp @@ -100,10 +100,7 @@ ConfigItem::Ptr ConfigItemBuilder::Compile(void) Array::Ptr templateArray = new Array(); templateArray->Add(m_Name); - std::vector indexer; - indexer.push_back(new LiteralExpression("templates")); - - exprs.push_back(new SetExpression(indexer, OpSetAdd, + exprs.push_back(new SetExpression(MakeIndexer("templates"), OpSetAdd, new LiteralExpression(templateArray), false, m_DebugInfo)); DictExpression *dexpr = new DictExpression(m_Expressions, m_DebugInfo); diff --git a/lib/config/expression.cpp b/lib/config/expression.cpp index bee6b6bf3..85804a2b1 100644 --- a/lib/config/expression.cpp +++ b/lib/config/expression.cpp @@ -64,7 +64,7 @@ const DebugInfo& Expression::GetDebugInfo(void) const std::vector icinga::MakeIndexer(const String& index1) { std::vector result; - result.push_back(MakeLiteral(index1)); + result.push_back(new VariableExpression(index1)); return result; } @@ -270,7 +270,20 @@ Value SetExpression::DoEvaluate(VMFrame& frame, DebugHint *dhint) const for (Array::SizeType i = 0; i < m_Indexer.size(); i++) { Expression *indexExpr = m_Indexer[i]; - String tempindex = indexExpr->Evaluate(frame, dhint); + + String tempindex; + + if (i == 0) { + VariableExpression *vexpr = dynamic_cast(indexExpr); + + if (!vexpr) { + object = indexExpr->Evaluate(frame, dhint); + continue; + } + + tempindex = vexpr->GetVariable(); + } else + tempindex = indexExpr->Evaluate(frame, dhint); if (psdhint) { sdhint = psdhint->GetChild(tempindex); @@ -290,7 +303,7 @@ Value SetExpression::DoEvaluate(VMFrame& frame, DebugHint *dhint) const break; } - object = VMOps::Indexer(frame, parent, tempindex); + object = VMOps::GetField(parent, tempindex); if (i != m_Indexer.size() - 1 && object.IsEmpty()) { object = new Dictionary(); @@ -333,7 +346,7 @@ Value SetExpression::DoEvaluate(VMFrame& frame, DebugHint *dhint) const Value IndexerExpression::DoEvaluate(VMFrame& frame, DebugHint *dhint) const { - return VMOps::Indexer(frame, m_Operand1->Evaluate(frame), m_Operand2->Evaluate(frame)); + return VMOps::Indexer(frame, m_Indexer); } Value ImportExpression::DoEvaluate(VMFrame& frame, DebugHint *dhint) const diff --git a/lib/config/expression.hpp b/lib/config/expression.hpp index 23ac200ff..84e5d8b57 100644 --- a/lib/config/expression.hpp +++ b/lib/config/expression.hpp @@ -213,6 +213,11 @@ public: : DebuggableExpression(debugInfo), m_Variable(variable) { } + String GetVariable(void) const + { + return m_Variable; + } + protected: virtual Value DoEvaluate(VMFrame& frame, DebugHint *dhint) const; @@ -532,15 +537,18 @@ private: }; -class I2_CONFIG_API IndexerExpression : public BinaryExpression +class I2_CONFIG_API IndexerExpression : public DebuggableExpression { public: - IndexerExpression(Expression *operand1, Expression *operand2, const DebugInfo& debugInfo = DebugInfo()) - : BinaryExpression(operand1, operand2, debugInfo) + IndexerExpression(const std::vector& indexer, const DebugInfo& debugInfo = DebugInfo()) + : DebuggableExpression(debugInfo), m_Indexer(indexer) { } protected: virtual Value DoEvaluate(VMFrame& frame, DebugHint *dhint) const; + +private: + std::vector m_Indexer; }; class I2_CONFIG_API ImportExpression : public DebuggableExpression diff --git a/lib/config/vmops.hpp b/lib/config/vmops.hpp index 172384a9b..a44ac019c 100644 --- a/lib/config/vmops.hpp +++ b/lib/config/vmops.hpp @@ -72,32 +72,19 @@ public: return func->Invoke(arguments); } - static inline Value Indexer(VMFrame& frame, const Value& value, const String& index) + static inline Value Indexer(VMFrame& frame, const std::vector& indexer) { - if (value.IsObjectType()) { - Dictionary::Ptr dict = value; - return dict->Get(index); - } else if (value.IsObjectType()) { - Array::Ptr arr = value; - return arr->Get(Convert::ToLong(index)); - } else if (value.IsObject()) { - Object::Ptr object = value; - Type::Ptr type = object->GetReflectionType(); - - if (!type) - BOOST_THROW_EXCEPTION(ConfigError("Dot operator applied to object which does not support reflection")); + Value result = indexer[0]->Evaluate(frame); - int field = type->GetFieldId(index); - - if (field == -1) - BOOST_THROW_EXCEPTION(ConfigError("Tried to access invalid property '" + index + "'")); + for (int i = 1; i < indexer.size(); i++) { + if (result.IsEmpty()) + return Empty; - return object->GetField(field); - } else if (value.IsEmpty()) { - return Empty; - } else { - BOOST_THROW_EXCEPTION(ConfigError("Dot operator cannot be applied to type '" + value.GetTypeName() + "'")); + Value index = indexer[i]->Evaluate(frame); + result = GetField(result, index); } + + return result; } static inline Value NewFunction(VMFrame& frame, const String& name, const std::vector& args, @@ -234,45 +221,62 @@ public: if (dict) return dict->Get(field); - else { - Type::Ptr type = context->GetReflectionType(); - if (!type) - return Empty; + Array::Ptr arr = dynamic_pointer_cast(context); - int fid = type->GetFieldId(field); + if (arr) { + int index = Convert::ToLong(field); + return arr->Get(index); + } - if (fid == -1) - return Empty; + Type::Ptr type = context->GetReflectionType(); - return context->GetField(fid); - } + if (!type) + return Empty; + + int fid = type->GetFieldId(field); + + if (fid == -1) + return Empty; + + return context->GetField(fid); } static inline void SetField(const Object::Ptr& context, const String& field, const Value& value) { Dictionary::Ptr dict = dynamic_pointer_cast(context); - if (dict) + if (dict) { dict->Set(field, value); - else { - Type::Ptr type = context->GetReflectionType(); + return; + } - if (!type) - BOOST_THROW_EXCEPTION(ConfigError("Cannot set field on object.")); + Array::Ptr arr = dynamic_pointer_cast(context); - int fid = type->GetFieldId(field); + if (arr) { + int index = Convert::ToLong(field); + if (index >= arr->GetLength()) + arr->Resize(index + 1); + arr->Set(index, value); + return; + } - if (fid == -1) - BOOST_THROW_EXCEPTION(ConfigError("Attribute '" + field + "' does not exist.")); + Type::Ptr type = context->GetReflectionType(); - try { - context->SetField(fid, value); - } catch (const boost::bad_lexical_cast&) { - BOOST_THROW_EXCEPTION(ConfigError("Attribute '" + field + "' cannot be set to value of type '" + value.GetTypeName() + "'")); - } catch (const std::bad_cast&) { - BOOST_THROW_EXCEPTION(ConfigError("Attribute '" + field + "' cannot be set to value of type '" + value.GetTypeName() + "'")); - } + if (!type) + BOOST_THROW_EXCEPTION(ConfigError("Cannot set field on object.")); + + int fid = type->GetFieldId(field); + + if (fid == -1) + BOOST_THROW_EXCEPTION(ConfigError("Attribute '" + field + "' does not exist.")); + + try { + context->SetField(fid, value); + } catch (const boost::bad_lexical_cast&) { + BOOST_THROW_EXCEPTION(ConfigError("Attribute '" + field + "' cannot be set to value of type '" + value.GetTypeName() + "'")); + } catch (const std::bad_cast&) { + BOOST_THROW_EXCEPTION(ConfigError("Attribute '" + field + "' cannot be set to value of type '" + value.GetTypeName() + "'")); } } diff --git a/test/config-ops.cpp b/test/config-ops.cpp index ae0ecd179..4ec5d164b 100644 --- a/test/config-ops.cpp +++ b/test/config-ops.cpp @@ -208,10 +208,9 @@ BOOST_AUTO_TEST_CASE(advanced) BOOST_CHECK(expr->Evaluate(frame) == 3); delete expr; - /* Uncomment this once #7800 is fixed expr = ConfigCompiler::CompileText("", "local v = { a = 3}; v.a"); BOOST_CHECK(expr->Evaluate(frame) == 3); - delete expr;*/ + delete expr; expr = ConfigCompiler::CompileText("", "a = 3 b = 3"); BOOST_CHECK(expr == NULL); -- 2.40.0