mirror of
https://github.com/Icinga/icinga2.git
synced 2025-07-23 13:45:04 +02:00
Allow side-effect-free expressions in a limited number of cases
refs #6570
This commit is contained in:
parent
0091c70c41
commit
093be8b5c9
@ -82,7 +82,7 @@ static void MakeRBinaryOp(Expression** result, Expression *left, Expression *rig
|
|||||||
%error-verbose
|
%error-verbose
|
||||||
%glr-parser
|
%glr-parser
|
||||||
|
|
||||||
%parse-param { std::vector<Expression *> *elist }
|
%parse-param { std::vector<std::pair<Expression *, EItemInfo> > *llist }
|
||||||
%parse-param { ConfigCompiler *context }
|
%parse-param { ConfigCompiler *context }
|
||||||
%lex-param { void *scanner }
|
%lex-param { void *scanner }
|
||||||
|
|
||||||
@ -95,6 +95,7 @@ static void MakeRBinaryOp(Expression** result, Expression *left, Expression *rig
|
|||||||
CombinedSetOp csop;
|
CombinedSetOp csop;
|
||||||
icinga::TypeSpecifier type;
|
icinga::TypeSpecifier type;
|
||||||
std::vector<String> *slist;
|
std::vector<String> *slist;
|
||||||
|
std::vector<std::pair<Expression *, EItemInfo> > *llist;
|
||||||
std::vector<Expression *> *elist;
|
std::vector<Expression *> *elist;
|
||||||
std::pair<String, Expression *> *cvitem;
|
std::pair<String, Expression *> *cvitem;
|
||||||
std::map<String, Expression *> *cvlist;
|
std::map<String, Expression *> *cvlist;
|
||||||
@ -181,11 +182,12 @@ static void MakeRBinaryOp(Expression** result, Expression *left, Expression *rig
|
|||||||
%type <variant> typerulelist
|
%type <variant> typerulelist
|
||||||
%type <csop> combined_set_op
|
%type <csop> combined_set_op
|
||||||
%type <type> type
|
%type <type> type
|
||||||
%type <elist> statements
|
%type <llist> statements
|
||||||
%type <elist> lterm_items
|
%type <llist> lterm_items
|
||||||
%type <elist> lterm_items_inner
|
%type <llist> lterm_items_inner
|
||||||
%type <expr> rterm
|
%type <expr> rterm
|
||||||
%type <expr> rterm_array
|
%type <expr> rterm_array
|
||||||
|
%type <expr> rterm_scope_require_side_effect
|
||||||
%type <expr> rterm_scope
|
%type <expr> rterm_scope
|
||||||
%type <expr> rterm_side_effect
|
%type <expr> rterm_side_effect
|
||||||
%type <expr> rterm_no_side_effect
|
%type <expr> rterm_no_side_effect
|
||||||
@ -228,23 +230,34 @@ int yylex(YYSTYPE *lvalp, YYLTYPE *llocp, void *scanner);
|
|||||||
|
|
||||||
extern int yydebug;
|
extern int yydebug;
|
||||||
|
|
||||||
void yyerror(const YYLTYPE *locp, std::vector<Expression *> *, ConfigCompiler *, const char *err)
|
void yyerror(const YYLTYPE *locp, std::vector<std::pair<Expression *, EItemInfo> > *, ConfigCompiler *, const char *err)
|
||||||
{
|
{
|
||||||
BOOST_THROW_EXCEPTION(ScriptError(err, *locp));
|
BOOST_THROW_EXCEPTION(ScriptError(err, *locp));
|
||||||
}
|
}
|
||||||
|
|
||||||
int yyparse(std::vector<Expression *> *elist, ConfigCompiler *context);
|
int yyparse(std::vector<std::pair<Expression *, EItemInfo> > *llist, ConfigCompiler *context);
|
||||||
|
|
||||||
Expression *ConfigCompiler::Compile(void)
|
Expression *ConfigCompiler::Compile(void)
|
||||||
{
|
{
|
||||||
std::vector<Expression *> elist;
|
std::vector<std::pair<Expression *, EItemInfo> > llist;
|
||||||
|
|
||||||
//yydebug = 1;
|
//yydebug = 1;
|
||||||
|
|
||||||
if (yyparse(&elist, this) != 0)
|
if (yyparse(&llist, this) != 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
DictExpression *expr = new DictExpression(elist);
|
std::vector<Expression *> dlist;
|
||||||
|
typedef std::pair<Expression *, EItemInfo> 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();
|
expr->MakeInline();
|
||||||
return expr;
|
return expr;
|
||||||
}
|
}
|
||||||
@ -256,7 +269,7 @@ Expression *ConfigCompiler::Compile(void)
|
|||||||
%%
|
%%
|
||||||
script: statements
|
script: statements
|
||||||
{
|
{
|
||||||
elist->swap(*$1);
|
llist->swap(*$1);
|
||||||
delete $1;
|
delete $1;
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
@ -273,48 +286,47 @@ statements: newlines lterm_items
|
|||||||
|
|
||||||
lterm_items: /* empty */
|
lterm_items: /* empty */
|
||||||
{
|
{
|
||||||
$$ = new std::vector<Expression *>();
|
$$ = new std::vector<std::pair<Expression *, EItemInfo> >();
|
||||||
}
|
}
|
||||||
| lterm_items_inner
|
| lterm_items_inner
|
||||||
{
|
| lterm_items_inner sep
|
||||||
$$ = $1;
|
|
||||||
}
|
|
||||||
| lterm_items_inner ','
|
|
||||||
{
|
|
||||||
$$ = $1;
|
|
||||||
}
|
|
||||||
| lterm_items_inner ',' newlines
|
|
||||||
{
|
|
||||||
$$ = $1;
|
|
||||||
}
|
|
||||||
| lterm_items_inner ';'
|
|
||||||
{
|
|
||||||
$$ = $1;
|
|
||||||
}
|
|
||||||
| lterm_items_inner ';' newlines
|
|
||||||
{
|
|
||||||
$$ = $1;
|
|
||||||
}
|
|
||||||
| lterm_items_inner newlines
|
|
||||||
{
|
|
||||||
$$ = $1;
|
|
||||||
}
|
|
||||||
;
|
;
|
||||||
|
|
||||||
lterm_items_inner: lterm %dprec 2
|
lterm_items_inner: lterm %dprec 2
|
||||||
{
|
{
|
||||||
$$ = new std::vector<Expression *>();
|
$$ = new std::vector<std::pair<Expression *, EItemInfo> >();
|
||||||
$$->push_back($1);
|
EItemInfo info = { true, @1 };
|
||||||
|
$$->push_back(std::make_pair($1, info));
|
||||||
|
}
|
||||||
|
| rterm_no_side_effect
|
||||||
|
{
|
||||||
|
$$ = new std::vector<std::pair<Expression *, EItemInfo> >();
|
||||||
|
EItemInfo info = { false, @1 };
|
||||||
|
$$->push_back(std::make_pair($1, info));
|
||||||
}
|
}
|
||||||
| lterm_items_inner sep lterm %dprec 1
|
| lterm_items_inner sep lterm %dprec 1
|
||||||
{
|
{
|
||||||
if ($1)
|
if ($1)
|
||||||
$$ = $1;
|
$$ = $1;
|
||||||
else
|
else
|
||||||
$$ = new std::vector<Expression *>();
|
$$ = new std::vector<std::pair<Expression *, EItemInfo> >();
|
||||||
|
|
||||||
if ($3)
|
if ($3) {
|
||||||
$$->push_back($3);
|
EItemInfo info = { true, @3 };
|
||||||
|
$$->push_back(std::make_pair($3, info));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
| lterm_items_inner sep rterm_no_side_effect %dprec 1
|
||||||
|
{
|
||||||
|
if ($1)
|
||||||
|
$$ = $1;
|
||||||
|
else
|
||||||
|
$$ = new std::vector<std::pair<Expression *, EItemInfo> >();
|
||||||
|
|
||||||
|
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_Assign.push(NULL);
|
||||||
context->m_Ignore.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();
|
context->m_ObjectAssign.pop();
|
||||||
|
|
||||||
@ -609,7 +621,7 @@ lterm: type
|
|||||||
{
|
{
|
||||||
$$ = $1;
|
$$ = $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<DictExpression *>($9);
|
DictExpression *aexpr = dynamic_cast<DictExpression *>($9);
|
||||||
aexpr->MakeInline();
|
aexpr->MakeInline();
|
||||||
@ -618,7 +630,7 @@ lterm: type
|
|||||||
free($3);
|
free($3);
|
||||||
free($5);
|
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<DictExpression *>($7);
|
DictExpression *aexpr = dynamic_cast<DictExpression *>($7);
|
||||||
aexpr->MakeInline();
|
aexpr->MakeInline();
|
||||||
@ -658,10 +670,6 @@ lterm: type
|
|||||||
{
|
{
|
||||||
$$ = $1;
|
$$ = $1;
|
||||||
}
|
}
|
||||||
| rterm_no_side_effect
|
|
||||||
{
|
|
||||||
yyerror(&@1, NULL, NULL, "Value computed is not used.");
|
|
||||||
}
|
|
||||||
;
|
;
|
||||||
|
|
||||||
rterm_items: /* empty */
|
rterm_items: /* empty */
|
||||||
@ -710,10 +718,35 @@ rterm_array: '[' newlines rterm_items ']'
|
|||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
rterm_scope_require_side_effect: '{' statements '}'
|
||||||
|
{
|
||||||
|
std::vector<Expression *> dlist;
|
||||||
|
typedef std::pair<Expression *, EItemInfo> 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 '}'
|
rterm_scope: '{' statements '}'
|
||||||
{
|
{
|
||||||
$$ = new DictExpression(*$2, DebugInfoRange(@1, @3));
|
std::vector<Expression *> dlist;
|
||||||
|
typedef std::pair<Expression *, EItemInfo> 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;
|
delete $2;
|
||||||
|
$$ = new DictExpression(dlist, DebugInfoRange(@1, @3));
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
@ -814,7 +847,7 @@ rterm_no_side_effect: T_STRING
|
|||||||
$$ = new GetScopeExpression(ScopeThis);
|
$$ = new GetScopeExpression(ScopeThis);
|
||||||
}
|
}
|
||||||
| rterm_array
|
| rterm_array
|
||||||
| rterm_scope
|
| rterm_scope_require_side_effect
|
||||||
{
|
{
|
||||||
Expression *expr = $1;
|
Expression *expr = $1;
|
||||||
BindToScope(expr, ScopeCurrent);
|
BindToScope(expr, ScopeCurrent);
|
||||||
@ -949,7 +982,7 @@ apply:
|
|||||||
context->m_FVVar.push("");
|
context->m_FVVar.push("");
|
||||||
context->m_FTerm.push(NULL);
|
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();
|
context->m_Apply.pop();
|
||||||
|
|
||||||
|
@ -59,6 +59,12 @@ struct CompilerDebugInfo
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct EItemInfo
|
||||||
|
{
|
||||||
|
bool SideEffect;
|
||||||
|
CompilerDebugInfo DebugInfo;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The configuration compiler can be used to compile a configuration file
|
* The configuration compiler can be used to compile a configuration file
|
||||||
* into a number of configuration items.
|
* into a number of configuration items.
|
||||||
|
@ -39,7 +39,7 @@ BOOST_AUTO_TEST_CASE(simple)
|
|||||||
delete expr;
|
delete expr;
|
||||||
|
|
||||||
expr = ConfigCompiler::CompileText("<test>", "{ 3\n\n5 }");
|
expr = ConfigCompiler::CompileText("<test>", "{ 3\n\n5 }");
|
||||||
BOOST_CHECK(expr->Evaluate(frame) != Empty);
|
BOOST_CHECK_THROW(expr->Evaluate(frame), ScriptError);
|
||||||
delete expr;
|
delete expr;
|
||||||
|
|
||||||
expr = ConfigCompiler::CompileText("<test>", "1 + 3");
|
expr = ConfigCompiler::CompileText("<test>", "1 + 3");
|
||||||
|
Loading…
x
Reference in New Issue
Block a user