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
111 %type <array> array_items
112 %type <array> array_items_inner
113 %type <variant> value
114 %type <expr> expression
115 %type <exprl> expressions
116 %type <exprl> expressions_inner
117 %type <exprl> expressionlist
118 %type <variant> typerulelist
121 %type <num> partial_specifier
122 %type <slist> object_inherits_list
123 %type <slist> object_inherits_specifier
124 %type <aexpr> aexpression
125 %type <num> variable_decl
131 %nonassoc T_NOT_EQUAL
140 int yylex(YYSTYPE *lvalp, YYLTYPE *llocp, void *scanner);
142 void yyerror(YYLTYPE *locp, ConfigCompiler *, const char *err)
144 std::ostringstream message;
145 message << *locp << ": " << err;
146 ConfigCompilerContext::GetInstance()->AddMessage(true, message.str());
149 int yyparse(ConfigCompiler *context);
151 static std::stack<Array::Ptr> m_Arrays;
152 static bool m_Abstract;
154 static std::stack<TypeRuleList::Ptr> m_RuleLists;
155 static ConfigType::Ptr m_Type;
157 void ConfigCompiler::Compile(void)
161 } catch (const std::exception& ex) {
162 ConfigCompilerContext::GetInstance()->AddMessage(true, DiagnosticInformation(ex));
166 #define scanner (context->GetScanner())
171 statements: /* empty */
172 | statements statement
175 statement: object | type | include | include_recursive | library | variable | apply
178 include: T_INCLUDE value
180 context->HandleInclude(*$2, false, yylloc);
183 | T_INCLUDE T_STRING_ANGLE
185 context->HandleInclude($2, true, yylloc);
190 include_recursive: T_INCLUDE_RECURSIVE value
192 context->HandleIncludeRecursive(*$2, "*.conf", yylloc);
195 | T_INCLUDE_RECURSIVE value value
197 context->HandleIncludeRecursive(*$2, *$3, yylloc);
203 library: T_LIBRARY T_STRING
205 context->HandleLibrary($2);
210 variable: variable_decl identifier T_SET value
213 if (value->IsObjectType<ExpressionList>()) {
214 Dictionary::Ptr dict = make_shared<Dictionary>();
215 ExpressionList::Ptr exprl = *value;
216 exprl->Execute(dict);
218 value = new Value(dict);
221 ScriptVariable::Ptr sv = ScriptVariable::Set($2, *value);
222 sv->SetConstant(true);
239 identifier: T_IDENTIFIER
246 type: partial_specifier T_TYPE identifier
248 String name = String($3);
251 m_Type = ConfigType::GetByName(name);
255 BOOST_THROW_EXCEPTION(std::invalid_argument("Partial type definition for unknown type '" + name + "'"));
257 m_Type = make_shared<ConfigType>(name, yylloc);
261 type_inherits_specifier typerulelist
263 TypeRuleList::Ptr ruleList = *$6;
264 m_Type->GetRuleList()->AddRules(ruleList);
265 m_Type->GetRuleList()->AddRequires(ruleList);
267 String validator = ruleList->GetValidator();
268 if (!validator.IsEmpty())
269 m_Type->GetRuleList()->SetValidator(validator);
275 partial_specifier: /* Empty */
287 m_RuleLists.push(make_shared<TypeRuleList>());
292 $$ = new Value(m_RuleLists.top());
297 typerules: typerules_inner
298 | typerules_inner ','
300 typerules_inner: /* empty */
302 | typerules_inner ',' typerule
305 typerule: T_REQUIRE T_STRING
307 m_RuleLists.top()->AddRequire($2);
310 | T_VALIDATOR T_STRING
312 m_RuleLists.top()->SetValidator($2);
315 | T_ATTRIBUTE type T_STRING
317 TypeRule rule($2, String(), $3, TypeRuleList::Ptr(), yylloc);
320 m_RuleLists.top()->AddRule(rule);
322 | T_ATTRIBUTE T_TYPE_NAME '(' identifier ')' T_STRING
324 TypeRule rule($2, $4, $6, TypeRuleList::Ptr(), yylloc);
328 m_RuleLists.top()->AddRule(rule);
330 | T_ATTRIBUTE type T_STRING typerulelist
332 TypeRule rule($2, String(), $3, *$4, yylloc);
335 m_RuleLists.top()->AddRule(rule);
339 type_inherits_specifier: /* empty */
340 | T_INHERITS identifier
342 m_Type->SetParent($2);
347 type: T_TYPE_DICTIONARY
363 object_declaration identifier T_STRING object_inherits_specifier expressionlist
365 ConfigItemBuilder::Ptr item = make_shared<ConfigItemBuilder>(yylloc);
369 if (strchr($4, '!') != NULL) {
370 std::ostringstream msgbuf;
371 msgbuf << "Name for object '" << $4 << "' of type '" << $3 << "' is invalid: Object names may not contain '!'";
373 BOOST_THROW_EXCEPTION(std::invalid_argument(msgbuf.str()));
382 BOOST_FOREACH(const String& parent, *$5) {
383 item->AddParent(parent);
390 ExpressionList::Ptr exprl = ExpressionList::Ptr($6);
391 item->AddExpressionList(exprl);
394 item->SetAbstract(m_Abstract);
396 item->Compile()->Register();
401 object_declaration: T_OBJECT
407 object_inherits_list:
413 $$ = new std::vector<String>();
417 | object_inherits_list ',' T_STRING
422 $$ = new std::vector<String>();
429 object_inherits_specifier:
433 | T_INHERITS object_inherits_list
439 expressionlist: '{' expressions '}'
444 $$ = new ExpressionList();
448 expressions: expressions_inner
452 | expressions_inner ','
457 expressions_inner: /* empty */
463 $$ = new ExpressionList();
464 $$->AddExpression(*$1);
467 | expressions_inner ',' expression
472 $$ = new ExpressionList();
474 $$->AddExpression(*$3);
479 expression: identifier operator value
481 $$ = new Expression($1, $2, *$3, yylloc);
485 | identifier '[' T_STRING ']' operator value
487 Expression subexpr($3, $5, *$6, yylloc);
491 ExpressionList::Ptr subexprl = make_shared<ExpressionList>();
492 subexprl->AddExpression(subexpr);
494 $$ = new Expression($1, OperatorPlus, subexprl, yylloc);
509 array_items: array_items_inner
513 | array_items_inner ','
518 array_items_inner: /* empty */
528 | array_items_inner ',' aexpression
540 aexpression: T_STRING
542 $$ = new Value(make_shared<AExpression>(AEReturn, AValue(ATSimple, $1), yylloc));
547 $$ = new Value(make_shared<AExpression>(AEReturn, AValue(ATSimple, $1), yylloc));
551 $$ = new Value(make_shared<AExpression>(AEReturn, AValue(ATSimple, Empty), yylloc));
553 | T_IDENTIFIER '(' array_items ')'
555 Array::Ptr arguments = Array::Ptr($3);
556 $$ = new Value(make_shared<AExpression>(AEFunctionCall, AValue(ATSimple, $1), AValue(ATSimple, arguments), yylloc));
561 $$ = new Value(make_shared<AExpression>(AEReturn, AValue(ATVariable, $1), yylloc));
566 $$ = new Value(make_shared<AExpression>(AENegate, static_cast<AExpression::Ptr>(*$2), yylloc));
571 $$ = new Value(make_shared<AExpression>(AENegate, static_cast<AExpression::Ptr>(*$2), yylloc));
574 | '[' array_items ']'
576 $$ = new Value(make_shared<AExpression>(AEArray, AValue(ATSimple, Array::Ptr($2)), yylloc));
578 | '(' aexpression ')'
582 | aexpression '+' aexpression
584 $$ = new Value(make_shared<AExpression>(AEAdd, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3), yylloc));
588 | aexpression '-' aexpression
590 $$ = new Value(make_shared<AExpression>(AESubtract, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3), yylloc));
594 | aexpression '*' aexpression
596 $$ = new Value(make_shared<AExpression>(AEMultiply, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3), yylloc));
600 | aexpression '/' aexpression
602 $$ = new Value(make_shared<AExpression>(AEDivide, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3), yylloc));
606 | aexpression '&' aexpression
608 $$ = new Value(make_shared<AExpression>(AEBinaryAnd, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3), yylloc));
612 | aexpression '|' aexpression
614 $$ = new Value(make_shared<AExpression>(AEBinaryOr, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3), yylloc));
618 | aexpression T_IN aexpression
620 $$ = new Value(make_shared<AExpression>(AEIn, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3), yylloc));
624 | aexpression T_NOT_IN aexpression
626 $$ = new Value(make_shared<AExpression>(AENotIn, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3), yylloc));
630 | aexpression T_EQUAL aexpression
632 $$ = new Value(make_shared<AExpression>(AEEqual, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3), yylloc));
636 | aexpression T_NOT_EQUAL aexpression
638 $$ = new Value(make_shared<AExpression>(AENotEqual, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3), yylloc));
642 | aexpression T_SHIFT_LEFT aexpression
644 $$ = new Value(make_shared<AExpression>(AEShiftLeft, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3), yylloc));
648 | aexpression T_SHIFT_RIGHT aexpression
650 $$ = new Value(make_shared<AExpression>(AEShiftRight, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3), yylloc));
654 | aexpression T_LOGICAL_AND aexpression
656 $$ = new Value(make_shared<AExpression>(AELogicalAnd, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3), yylloc));
660 | aexpression T_LOGICAL_OR aexpression
662 $$ = new Value(make_shared<AExpression>(AELogicalOr, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3), yylloc));
668 value: expressionlist
670 ExpressionList::Ptr exprl = ExpressionList::Ptr($1);
671 $$ = new Value(exprl);
675 AExpression::Ptr aexpr = *$1;
676 $$ = new Value(aexpr->Evaluate(Dictionary::Ptr()));
681 optional_template: /* empty */
685 apply: T_APPLY optional_template identifier identifier T_TO identifier T_WHERE aexpression
687 if (!ApplyRule::IsValidCombination($3, $6)) {
688 BOOST_THROW_EXCEPTION(std::invalid_argument("'apply' cannot be used with types '" + String($3) + "' and '" + String($6) + "'."));
691 ApplyRule::AddRule($3, $4, $6, *$8, yylloc);