From 093be8b5c98196c77e8e3ce6bd4c9ea1aaa28002 Mon Sep 17 00:00:00 2001 From: Gunnar Beutner Date: Thu, 8 Jan 2015 10:30:34 +0100 Subject: [PATCH] Allow side-effect-free expressions in a limited number of cases refs #6570 --- lib/config/config_parser.yy | 129 +++++++++++++++++++++------------- lib/config/configcompiler.hpp | 6 ++ test/config-ops.cpp | 2 +- 3 files changed, 88 insertions(+), 49 deletions(-) diff --git a/lib/config/config_parser.yy b/lib/config/config_parser.yy index 956921a96..86ba59a92 100644 --- a/lib/config/config_parser.yy +++ b/lib/config/config_parser.yy @@ -82,7 +82,7 @@ static void MakeRBinaryOp(Expression** result, Expression *left, Expression *rig %error-verbose %glr-parser -%parse-param { std::vector *elist } +%parse-param { std::vector > *llist } %parse-param { ConfigCompiler *context } %lex-param { void *scanner } @@ -95,6 +95,7 @@ static void MakeRBinaryOp(Expression** result, Expression *left, Expression *rig CombinedSetOp csop; icinga::TypeSpecifier type; std::vector *slist; + std::vector > *llist; std::vector *elist; std::pair *cvitem; std::map *cvlist; @@ -181,11 +182,12 @@ static void MakeRBinaryOp(Expression** result, Expression *left, Expression *rig %type typerulelist %type combined_set_op %type type -%type statements -%type lterm_items -%type lterm_items_inner +%type statements +%type lterm_items +%type lterm_items_inner %type rterm %type rterm_array +%type rterm_scope_require_side_effect %type rterm_scope %type rterm_side_effect %type rterm_no_side_effect @@ -228,23 +230,34 @@ int yylex(YYSTYPE *lvalp, YYLTYPE *llocp, void *scanner); extern int yydebug; -void yyerror(const YYLTYPE *locp, std::vector *, ConfigCompiler *, const char *err) +void yyerror(const YYLTYPE *locp, std::vector > *, ConfigCompiler *, const char *err) { BOOST_THROW_EXCEPTION(ScriptError(err, *locp)); } -int yyparse(std::vector *elist, ConfigCompiler *context); +int yyparse(std::vector > *llist, ConfigCompiler *context); Expression *ConfigCompiler::Compile(void) { - std::vector elist; + std::vector > llist; //yydebug = 1; - if (yyparse(&elist, this) != 0) + if (yyparse(&llist, this) != 0) return NULL; - DictExpression *expr = new DictExpression(elist); + std::vector dlist; + typedef std::pair EListItem; + int num = 0; + BOOST_FOREACH(const EListItem& litem, llist) { + if (!litem.second.SideEffect && num != llist.size() - 1) { + yyerror(&litem.second.DebugInfo, NULL, NULL, "Value computed is not used."); + } + dlist.push_back(litem.first); + num++; + } + + DictExpression *expr = new DictExpression(dlist); expr->MakeInline(); return expr; } @@ -256,7 +269,7 @@ Expression *ConfigCompiler::Compile(void) %% script: statements { - elist->swap(*$1); + llist->swap(*$1); delete $1; } ; @@ -273,48 +286,47 @@ statements: newlines lterm_items lterm_items: /* empty */ { - $$ = new std::vector(); + $$ = new std::vector >(); } | lterm_items_inner + | lterm_items_inner sep + ; + +lterm_items_inner: lterm %dprec 2 { - $$ = $1; - } - | lterm_items_inner ',' - { - $$ = $1; - } - | lterm_items_inner ',' newlines - { - $$ = $1; - } - | lterm_items_inner ';' - { - $$ = $1; + $$ = new std::vector >(); + EItemInfo info = { true, @1 }; + $$->push_back(std::make_pair($1, info)); } - | lterm_items_inner ';' newlines + | rterm_no_side_effect { - $$ = $1; + $$ = new std::vector >(); + EItemInfo info = { false, @1 }; + $$->push_back(std::make_pair($1, info)); } - | lterm_items_inner newlines + | lterm_items_inner sep lterm %dprec 1 { - $$ = $1; - } - ; + if ($1) + $$ = $1; + else + $$ = new std::vector >(); -lterm_items_inner: lterm %dprec 2 - { - $$ = new std::vector(); - $$->push_back($1); + if ($3) { + EItemInfo info = { true, @3 }; + $$->push_back(std::make_pair($3, info)); + } } - | lterm_items_inner sep lterm %dprec 1 + | lterm_items_inner sep rterm_no_side_effect %dprec 1 { if ($1) $$ = $1; else - $$ = new std::vector(); + $$ = new std::vector >(); - if ($3) - $$->push_back($3); + if ($3) { + EItemInfo info = { false, @3 }; + $$->push_back(std::make_pair($3, info)); + } } ; @@ -439,7 +451,7 @@ object: context->m_Assign.push(NULL); context->m_Ignore.push(NULL); } - object_declaration identifier rterm use_specifier rterm_scope + object_declaration identifier rterm use_specifier rterm_scope_require_side_effect { context->m_ObjectAssign.pop(); @@ -609,7 +621,7 @@ lterm: type { $$ = $1; } - | T_FOR '(' identifier T_FOLLOWS identifier T_IN rterm ')' rterm_scope + | T_FOR '(' identifier T_FOLLOWS identifier T_IN rterm ')' rterm_scope_require_side_effect { DictExpression *aexpr = dynamic_cast($9); aexpr->MakeInline(); @@ -618,7 +630,7 @@ lterm: type free($3); free($5); } - | T_FOR '(' identifier T_IN rterm ')' rterm_scope + | T_FOR '(' identifier T_IN rterm ')' rterm_scope_require_side_effect { DictExpression *aexpr = dynamic_cast($7); aexpr->MakeInline(); @@ -658,10 +670,6 @@ lterm: type { $$ = $1; } - | rterm_no_side_effect - { - yyerror(&@1, NULL, NULL, "Value computed is not used."); - } ; rterm_items: /* empty */ @@ -710,10 +718,35 @@ rterm_array: '[' newlines rterm_items ']' } ; +rterm_scope_require_side_effect: '{' statements '}' + { + std::vector dlist; + typedef std::pair EListItem; + int num = 0; + BOOST_FOREACH(const EListItem& litem, *$2) { + if (!litem.second.SideEffect) + yyerror(&litem.second.DebugInfo, NULL, NULL, "Value computed is not used."); + dlist.push_back(litem.first); + num++; + } + delete $2; + $$ = new DictExpression(dlist, DebugInfoRange(@1, @3)); + } + ; + rterm_scope: '{' statements '}' { - $$ = new DictExpression(*$2, DebugInfoRange(@1, @3)); + std::vector dlist; + typedef std::pair EListItem; + int num = 0; + BOOST_FOREACH(const EListItem& litem, *$2) { + if (!litem.second.SideEffect && num != $2->size() - 1) + yyerror(&litem.second.DebugInfo, NULL, NULL, "Value computed is not used."); + dlist.push_back(litem.first); + num++; + } delete $2; + $$ = new DictExpression(dlist, DebugInfoRange(@1, @3)); } ; @@ -814,7 +847,7 @@ rterm_no_side_effect: T_STRING $$ = new GetScopeExpression(ScopeThis); } | rterm_array - | rterm_scope + | rterm_scope_require_side_effect { Expression *expr = $1; BindToScope(expr, ScopeCurrent); @@ -949,7 +982,7 @@ apply: context->m_FVVar.push(""); context->m_FTerm.push(NULL); } - T_APPLY identifier optional_rterm apply_for_specifier target_type_specifier use_specifier rterm_scope + T_APPLY identifier optional_rterm apply_for_specifier target_type_specifier use_specifier rterm_scope_require_side_effect { context->m_Apply.pop(); diff --git a/lib/config/configcompiler.hpp b/lib/config/configcompiler.hpp index 84e2828c1..4ab81d07d 100644 --- a/lib/config/configcompiler.hpp +++ b/lib/config/configcompiler.hpp @@ -59,6 +59,12 @@ struct CompilerDebugInfo } }; +struct EItemInfo +{ + bool SideEffect; + CompilerDebugInfo DebugInfo; +}; + /** * The configuration compiler can be used to compile a configuration file * into a number of configuration items. diff --git a/test/config-ops.cpp b/test/config-ops.cpp index 3b154583e..2ef162a15 100644 --- a/test/config-ops.cpp +++ b/test/config-ops.cpp @@ -39,7 +39,7 @@ BOOST_AUTO_TEST_CASE(simple) delete expr; expr = ConfigCompiler::CompileText("", "{ 3\n\n5 }"); - BOOST_CHECK(expr->Evaluate(frame) != Empty); + BOOST_CHECK_THROW(expr->Evaluate(frame), ScriptError); delete expr; expr = ConfigCompiler::CompileText("", "1 + 3"); -- 2.40.0