2 /******************************************************************************
4 * Copyright (C) 2012-2014 Icinga Development Team (http://www.icinga.org) *
6 * This program is free software; you can redistribute it and/or *
7 * modify it under the terms of the GNU General Public License *
8 * as published by the Free Software Foundation; either version 2 *
9 * of the License, or (at your option) any later version. *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
16 * You should have received a copy of the GNU General Public License *
17 * along with this program; if not, write to the Free Software Foundation *
18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
19 ******************************************************************************/
21 #include "i2-config.h"
22 #include "config/expression.h"
23 #include "config/expressionlist.h"
24 #include "config/configitembuilder.h"
25 #include "config/configcompiler.h"
26 #include "config/configcompilercontext.h"
27 #include "config/typerule.h"
28 #include "config/typerulelist.h"
29 #include "config/aexpression.h"
30 #include "config/applyrule.h"
31 #include "base/value.h"
32 #include "base/utility.h"
33 #include "base/array.h"
34 #include "base/scriptvariable.h"
35 #include "base/exception.h"
36 #include "base/dynamictype.h"
39 #include <boost/foreach.hpp>
41 #define YYLTYPE icinga::DebugInfo
43 using namespace icinga;
53 %parse-param { ConfigCompiler *context }
54 %lex-param { void *scanner }
59 icinga::Value *variant;
60 icinga::ExpressionOperator op;
61 icinga::TypeSpecifier type;
62 std::vector<String> *slist;
64 ExpressionList *exprl;
69 %token <text> T_STRING
70 %token <text> T_STRING_ANGLE
73 %token <text> T_IDENTIFIER
74 %token <op> T_SET "= (T_SET)"
75 %token <op> T_PLUS_EQUAL "+= (T_PLUS_EQUAL)"
76 %token <op> T_MINUS_EQUAL "-= (T_MINUS_EQUAL)"
77 %token <op> T_MULTIPLY_EQUAL "*= (T_MULTIPLY_EQUAL)"
78 %token <op> T_DIVIDE_EQUAL "/= (T_DIVIDE_EQUAL)"
79 %token T_VAR "var (T_VAR)"
80 %token T_CONST "const (T_CONST)"
81 %token T_SHIFT_LEFT "<< (T_SHIFT_LEFT)"
82 %token T_SHIFT_RIGHT ">> (T_SHIFT_RIGHT)"
83 %token T_EQUAL "== (T_EQUAL)"
84 %token T_NOT_EQUAL "!= (T_NOT_EQUAL)"
85 %token T_IN "in (T_IN)"
86 %token T_NOT_IN "!in (T_NOT_IN)"
87 %token T_LOGICAL_AND "&& (T_LOGICAL_AND)"
88 %token T_LOGICAL_OR "|| (T_LOGICAL_OR)"
89 %token <type> T_TYPE_DICTIONARY "dictionary (T_TYPE_DICTIONARY)"
90 %token <type> T_TYPE_ARRAY "array (T_TYPE_ARRAY)"
91 %token <type> T_TYPE_NUMBER "number (T_TYPE_NUMBER)"
92 %token <type> T_TYPE_STRING "string (T_TYPE_STRING)"
93 %token <type> T_TYPE_SCALAR "scalar (T_TYPE_SCALAR)"
94 %token <type> T_TYPE_ANY "any (T_TYPE_ANY)"
95 %token <type> T_TYPE_NAME "name (T_TYPE_NAME)"
96 %token T_VALIDATOR "%validator (T_VALIDATOR)"
97 %token T_REQUIRE "%require (T_REQUIRE)"
98 %token T_ATTRIBUTE "%attribute (T_ATTRIBUTE)"
99 %token T_TYPE "type (T_TYPE)"
100 %token T_OBJECT "object (T_OBJECT)"
101 %token T_TEMPLATE "template (T_TEMPLATE)"
102 %token T_INCLUDE "include (T_INCLUDE)"
103 %token T_INCLUDE_RECURSIVE "include_recursive (T_INCLUDE_RECURSIVE)"
104 %token T_LIBRARY "library (T_LIBRARY)"
105 %token T_INHERITS "inherits (T_INHERITS)"
106 %token T_PARTIAL "partial (T_PARTIAL)"
107 %token T_APPLY "apply (T_APPLY)"
108 %token T_TO "to (T_TO)"
109 %token T_WHERE "where (T_WHERE)"
110 %type <text> identifier
112 %type <array> array_items
113 %type <array> array_items_inner
114 %type <variant> simplevalue
115 %type <variant> value
116 %type <expr> expression
117 %type <exprl> expressions
118 %type <exprl> expressions_inner
119 %type <exprl> expressionlist
120 %type <variant> typerulelist
123 %type <num> partial_specifier
124 %type <slist> object_inherits_list
125 %type <slist> object_inherits_specifier
127 %type <aexpr> aexpression
128 %type <num> variable_decl
134 %nonassoc T_NOT_EQUAL
141 int yylex(YYSTYPE *lvalp, YYLTYPE *llocp, void *scanner);
143 void yyerror(YYLTYPE *locp, ConfigCompiler *, const char *err)
145 std::ostringstream message;
146 message << *locp << ": " << err;
147 ConfigCompilerContext::GetInstance()->AddMessage(true, message.str());
150 int yyparse(ConfigCompiler *context);
152 static std::stack<Array::Ptr> m_Arrays;
153 static bool m_Abstract;
155 static std::stack<TypeRuleList::Ptr> m_RuleLists;
156 static ConfigType::Ptr m_Type;
158 void ConfigCompiler::Compile(void)
162 } catch (const std::exception& ex) {
163 ConfigCompilerContext::GetInstance()->AddMessage(true, DiagnosticInformation(ex));
167 #define scanner (context->GetScanner())
172 statements: /* empty */
173 | statements statement
176 statement: object | type | include | include_recursive | library | variable | apply
179 include: T_INCLUDE value
181 context->HandleInclude(*$2, false, yylloc);
184 | T_INCLUDE T_STRING_ANGLE
186 context->HandleInclude($2, true, yylloc);
191 include_recursive: T_INCLUDE_RECURSIVE value
193 context->HandleIncludeRecursive(*$2, "*.conf", yylloc);
196 | T_INCLUDE_RECURSIVE value value
198 context->HandleIncludeRecursive(*$2, *$3, yylloc);
204 library: T_LIBRARY T_STRING
206 context->HandleLibrary($2);
211 variable: variable_decl identifier T_SET value
214 if (value->IsObjectType<ExpressionList>()) {
215 Dictionary::Ptr dict = make_shared<Dictionary>();
216 ExpressionList::Ptr exprl = *value;
217 exprl->Execute(dict);
219 value = new Value(dict);
222 ScriptVariable::Ptr sv = ScriptVariable::Set($2, *value);
223 sv->SetConstant(true);
240 identifier: T_IDENTIFIER
247 type: partial_specifier T_TYPE identifier
249 String name = String($3);
252 m_Type = ConfigType::GetByName(name);
256 BOOST_THROW_EXCEPTION(std::invalid_argument("Partial type definition for unknown type '" + name + "'"));
258 m_Type = make_shared<ConfigType>(name, yylloc);
262 type_inherits_specifier typerulelist
264 TypeRuleList::Ptr ruleList = *$6;
265 m_Type->GetRuleList()->AddRules(ruleList);
266 m_Type->GetRuleList()->AddRequires(ruleList);
268 String validator = ruleList->GetValidator();
269 if (!validator.IsEmpty())
270 m_Type->GetRuleList()->SetValidator(validator);
276 partial_specifier: /* Empty */
288 m_RuleLists.push(make_shared<TypeRuleList>());
293 $$ = new Value(m_RuleLists.top());
298 typerules: typerules_inner
299 | typerules_inner ','
301 typerules_inner: /* empty */
303 | typerules_inner ',' typerule
306 typerule: T_REQUIRE T_STRING
308 m_RuleLists.top()->AddRequire($2);
311 | T_VALIDATOR T_STRING
313 m_RuleLists.top()->SetValidator($2);
316 | T_ATTRIBUTE type T_STRING
318 TypeRule rule($2, String(), $3, TypeRuleList::Ptr(), yylloc);
321 m_RuleLists.top()->AddRule(rule);
323 | T_ATTRIBUTE T_TYPE_NAME '(' identifier ')' T_STRING
325 TypeRule rule($2, $4, $6, TypeRuleList::Ptr(), yylloc);
329 m_RuleLists.top()->AddRule(rule);
331 | T_ATTRIBUTE type T_STRING typerulelist
333 TypeRule rule($2, String(), $3, *$4, yylloc);
336 m_RuleLists.top()->AddRule(rule);
340 type_inherits_specifier: /* empty */
341 | T_INHERITS identifier
343 m_Type->SetParent($2);
348 type: T_TYPE_DICTIONARY
364 object_declaration identifier T_STRING object_inherits_specifier expressionlist
366 ConfigItemBuilder::Ptr item = make_shared<ConfigItemBuilder>(yylloc);
370 if (strchr($4, '!') != NULL) {
371 std::ostringstream msgbuf;
372 msgbuf << "Name for object '" << $4 << "' of type '" << $3 << "' is invalid: Object names may not contain '!'";
374 BOOST_THROW_EXCEPTION(std::invalid_argument(msgbuf.str()));
383 BOOST_FOREACH(const String& parent, *$5) {
384 item->AddParent(parent);
391 ExpressionList::Ptr exprl = ExpressionList::Ptr($6);
392 item->AddExpressionList(exprl);
395 item->SetAbstract(m_Abstract);
397 item->Compile()->Register();
402 object_declaration: T_OBJECT
408 object_inherits_list:
414 $$ = new std::vector<String>();
418 | object_inherits_list ',' T_STRING
423 $$ = new std::vector<String>();
430 object_inherits_specifier:
434 | T_INHERITS object_inherits_list
440 expressionlist: '{' expressions '}'
445 $$ = new ExpressionList();
449 expressions: expressions_inner
453 | expressions_inner ','
458 expressions_inner: /* empty */
464 $$ = new ExpressionList();
465 $$->AddExpression(*$1);
468 | expressions_inner ',' expression
473 $$ = new ExpressionList();
475 $$->AddExpression(*$3);
480 expression: identifier operator value
482 $$ = new Expression($1, $2, *$3, yylloc);
486 | identifier '[' T_STRING ']' operator value
488 Expression subexpr($3, $5, *$6, yylloc);
492 ExpressionList::Ptr subexprl = make_shared<ExpressionList>();
493 subexprl->AddExpression(subexpr);
495 $$ = new Expression($1, OperatorPlus, subexprl, yylloc);
510 array: '[' array_items ']'
516 array_items: array_items_inner
520 | array_items_inner ','
525 array_items_inner: /* empty */
533 if ($1->IsObjectType<ExpressionList>()) {
534 ExpressionList::Ptr exprl = *$1;
535 Dictionary::Ptr dict = make_shared<Dictionary>();
536 exprl->Execute(dict);
538 $1 = new Value(dict);
544 | array_items_inner ',' value
551 if ($3->IsObjectType<ExpressionList>()) {
552 ExpressionList::Ptr exprl = *$3;
553 Dictionary::Ptr dict = make_shared<Dictionary>();
554 exprl->Execute(dict);
556 $3 = new Value(dict);
564 simplevalue: T_STRING
582 Array::Ptr array = Array::Ptr($1);
583 $$ = new Value(array);
587 aterm: '(' aexpression ')'
592 aexpression: simplevalue
594 $$ = new Value(make_shared<AExpression>(AEReturn, AValue(ATSimple, *$1), yylloc));
599 $$ = new Value(make_shared<AExpression>(AEReturn, AValue(ATVariable, $1), yylloc));
604 $$ = new Value(make_shared<AExpression>(AENegate, static_cast<AExpression::Ptr>(*$2), yylloc));
607 | '(' aexpression ')'
611 | aexpression '+' aexpression
613 $$ = new Value(make_shared<AExpression>(AEAdd, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3), yylloc));
617 | aexpression '-' aexpression
619 $$ = new Value(make_shared<AExpression>(AESubtract, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3), yylloc));
623 | aexpression '*' aexpression
625 $$ = new Value(make_shared<AExpression>(AEMultiply, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3), yylloc));
629 | aexpression '/' aexpression
631 $$ = new Value(make_shared<AExpression>(AEDivide, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3), yylloc));
635 | aexpression '&' aexpression
637 $$ = new Value(make_shared<AExpression>(AEBinaryAnd, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3), yylloc));
641 | aexpression '|' aexpression
643 $$ = new Value(make_shared<AExpression>(AEBinaryOr, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3), yylloc));
647 | aexpression T_IN aexpression
649 $$ = new Value(make_shared<AExpression>(AEIn, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3), yylloc));
653 | aexpression T_NOT_IN aexpression
655 $$ = new Value(make_shared<AExpression>(AENotIn, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3), yylloc));
659 | aexpression T_EQUAL aexpression
661 $$ = new Value(make_shared<AExpression>(AEEqual, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3), yylloc));
665 | aexpression T_NOT_EQUAL aexpression
667 $$ = new Value(make_shared<AExpression>(AENotEqual, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3), yylloc));
671 | aexpression T_SHIFT_LEFT aexpression
673 $$ = new Value(make_shared<AExpression>(AEShiftLeft, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3), yylloc));
677 | aexpression T_SHIFT_RIGHT aexpression
679 $$ = new Value(make_shared<AExpression>(AEShiftRight, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3), yylloc));
683 | aexpression T_LOGICAL_AND aexpression
685 $$ = new Value(make_shared<AExpression>(AELogicalAnd, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3), yylloc));
689 | aexpression T_LOGICAL_OR aexpression
691 $$ = new Value(make_shared<AExpression>(AELogicalOr, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3), yylloc));
700 ExpressionList::Ptr exprl = ExpressionList::Ptr($1);
701 $$ = new Value(exprl);
705 AExpression::Ptr aexpr = *$1;
706 $$ = new Value(aexpr->Evaluate(Dictionary::Ptr()));
711 optional_template: /* empty */
715 apply: T_APPLY optional_template identifier identifier T_TO identifier T_WHERE aterm
717 if (!ApplyRule::IsValidCombination($3, $6)) {
718 BOOST_THROW_EXCEPTION(std::invalid_argument("'apply' cannot be used with types '" + String($3) + "' and '" + String($6) + "'."));
721 ApplyRule::AddRule($3, $4, $6, *$8, yylloc);