]> granicus.if.org Git - icinga2/blob - lib/config/config_parser.yy
Merge branch 'feature/apply-5789' into next
[icinga2] / lib / config / config_parser.yy
1 %{
2 /******************************************************************************
3  * Icinga 2                                                                   *
4  * Copyright (C) 2012-2014 Icinga Development Team (http://www.icinga.org)    *
5  *                                                                            *
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.                     *
10  *                                                                            *
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.                               *
15  *                                                                            *
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  ******************************************************************************/
20
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"
37 #include <sstream>
38 #include <stack>
39 #include <boost/foreach.hpp>
40
41 #define YYLTYPE icinga::DebugInfo
42
43 using namespace icinga;
44
45 %}
46
47 %pure-parser
48
49 %locations
50 %defines
51 %error-verbose
52
53 %parse-param { ConfigCompiler *context }
54 %lex-param { void *scanner }
55
56 %union {
57         char *text;
58         double num;
59         icinga::Value *variant;
60         icinga::ExpressionOperator op;
61         icinga::TypeSpecifier type;
62         std::vector<String> *slist;
63         Expression *expr;
64         ExpressionList *exprl;
65         Array *array;
66         Value *aexpr;
67 }
68
69 %token <text> T_STRING
70 %token <text> T_STRING_ANGLE
71 %token <num> T_NUMBER
72 %token T_NULL
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
119 %type <op> operator
120 %type <type> type
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
126 %left T_LOGICAL_OR
127 %left T_LOGICAL_AND
128 %left T_IN
129 %left T_NOT_IN
130 %nonassoc T_EQUAL
131 %nonassoc T_NOT_EQUAL
132 %left '+' '-'
133 %left '*' '/'
134 %left '&'
135 %left '|'
136 %right '~'
137 %right '!'
138 %{
139
140 int yylex(YYSTYPE *lvalp, YYLTYPE *llocp, void *scanner);
141
142 void yyerror(YYLTYPE *locp, ConfigCompiler *, const char *err)
143 {
144         std::ostringstream message;
145         message << *locp << ": " << err;
146         ConfigCompilerContext::GetInstance()->AddMessage(true, message.str());
147 }
148
149 int yyparse(ConfigCompiler *context);
150
151 static std::stack<Array::Ptr> m_Arrays;
152 static bool m_Abstract;
153
154 static std::stack<TypeRuleList::Ptr> m_RuleLists;
155 static ConfigType::Ptr m_Type;
156
157 void ConfigCompiler::Compile(void)
158 {
159         try {
160                 yyparse(this);
161         } catch (const std::exception& ex) {
162                 ConfigCompilerContext::GetInstance()->AddMessage(true, DiagnosticInformation(ex));
163         }
164 }
165
166 #define scanner (context->GetScanner())
167
168 %}
169
170 %%
171 statements: /* empty */
172         | statements statement
173         ;
174
175 statement: object | type | include | include_recursive | library | variable | apply
176         ;
177
178 include: T_INCLUDE value
179         {
180                 context->HandleInclude(*$2, false, yylloc);
181                 delete $2;
182         }
183         | T_INCLUDE T_STRING_ANGLE
184         {
185                 context->HandleInclude($2, true, yylloc);
186                 free($2);
187         }
188         ;
189
190 include_recursive: T_INCLUDE_RECURSIVE value
191         {
192                 context->HandleIncludeRecursive(*$2, "*.conf", yylloc);
193                 delete $2;
194         }
195         | T_INCLUDE_RECURSIVE value value
196         {
197                 context->HandleIncludeRecursive(*$2, *$3, yylloc);
198                 delete $2;
199                 delete $3;
200         }
201         ;
202
203 library: T_LIBRARY T_STRING
204         {
205                 context->HandleLibrary($2);
206                 free($2);
207         }
208         ;
209
210 variable: variable_decl identifier T_SET value
211         {
212                 Value *value = $4;
213                 if (value->IsObjectType<ExpressionList>()) {
214                         Dictionary::Ptr dict = make_shared<Dictionary>();
215                         ExpressionList::Ptr exprl = *value;
216                         exprl->Execute(dict);
217                         delete value;
218                         value = new Value(dict);
219                 }
220
221                 ScriptVariable::Ptr sv = ScriptVariable::Set($2, *value);
222                 sv->SetConstant(true);
223
224                 free($2);
225                 delete value;
226         }
227         ;
228
229 variable_decl: T_VAR
230         {
231                 $$ = true;
232         }
233         | T_CONST
234         {
235                 $$ = false;
236         }
237         ;
238
239 identifier: T_IDENTIFIER
240         | T_STRING
241         {
242                 $$ = $1;
243         }
244         ;
245
246 type: partial_specifier T_TYPE identifier
247         {
248                 String name = String($3);
249                 free($3);
250
251                 m_Type = ConfigType::GetByName(name);
252
253                 if (!m_Type) {
254                         if ($1)
255                                 BOOST_THROW_EXCEPTION(std::invalid_argument("Partial type definition for unknown type '" + name + "'"));
256
257                         m_Type = make_shared<ConfigType>(name, yylloc);
258                         m_Type->Register();
259                 }
260         }
261         type_inherits_specifier typerulelist
262         {
263                 TypeRuleList::Ptr ruleList = *$6;
264                 m_Type->GetRuleList()->AddRules(ruleList);
265                 m_Type->GetRuleList()->AddRequires(ruleList);
266
267                 String validator = ruleList->GetValidator();
268                 if (!validator.IsEmpty())
269                         m_Type->GetRuleList()->SetValidator(validator);
270
271                 delete $6;
272         }
273         ;
274
275 partial_specifier: /* Empty */
276         {
277                 $$ = 0;
278         }
279         | T_PARTIAL
280         {
281                 $$ = 1;
282         }
283         ;
284
285 typerulelist: '{'
286         {
287                 m_RuleLists.push(make_shared<TypeRuleList>());
288         }
289         typerules
290         '}'
291         {
292                 $$ = new Value(m_RuleLists.top());
293                 m_RuleLists.pop();
294         }
295         ;
296
297 typerules: typerules_inner
298         | typerules_inner ','
299
300 typerules_inner: /* empty */
301         | typerule
302         | typerules_inner ',' typerule
303         ;
304
305 typerule: T_REQUIRE T_STRING
306         {
307                 m_RuleLists.top()->AddRequire($2);
308                 free($2);
309         }
310         | T_VALIDATOR T_STRING
311         {
312                 m_RuleLists.top()->SetValidator($2);
313                 free($2);
314         }
315         | T_ATTRIBUTE type T_STRING
316         {
317                 TypeRule rule($2, String(), $3, TypeRuleList::Ptr(), yylloc);
318                 free($3);
319
320                 m_RuleLists.top()->AddRule(rule);
321         }
322         | T_ATTRIBUTE T_TYPE_NAME '(' identifier ')' T_STRING
323         {
324                 TypeRule rule($2, $4, $6, TypeRuleList::Ptr(), yylloc);
325                 free($4);
326                 free($6);
327
328                 m_RuleLists.top()->AddRule(rule);
329         }
330         | T_ATTRIBUTE type T_STRING typerulelist
331         {
332                 TypeRule rule($2, String(), $3, *$4, yylloc);
333                 free($3);
334                 delete $4;
335                 m_RuleLists.top()->AddRule(rule);
336         }
337         ;
338
339 type_inherits_specifier: /* empty */
340         | T_INHERITS identifier
341         {
342                 m_Type->SetParent($2);
343                 free($2);
344         }
345         ;
346
347 type: T_TYPE_DICTIONARY
348         | T_TYPE_ARRAY
349         | T_TYPE_NUMBER
350         | T_TYPE_STRING
351         | T_TYPE_SCALAR
352         | T_TYPE_ANY
353         | T_TYPE_NAME
354         {
355                 $$ = $1;
356         }
357         ;
358
359 object:
360         {
361                 m_Abstract = false;
362         }
363 object_declaration identifier T_STRING object_inherits_specifier expressionlist
364         {
365                 ConfigItemBuilder::Ptr item = make_shared<ConfigItemBuilder>(yylloc);
366
367                 item->SetType($3);
368
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 '!'";
372                         free($3);
373                         BOOST_THROW_EXCEPTION(std::invalid_argument(msgbuf.str()));
374                 }
375
376                 free($3);
377
378                 item->SetName($4);
379                 free($4);
380
381                 if ($5) {
382                         BOOST_FOREACH(const String& parent, *$5) {
383                                 item->AddParent(parent);
384                         }
385
386                         delete $5;
387                 }
388
389                 if ($6) {
390                         ExpressionList::Ptr exprl = ExpressionList::Ptr($6);
391                         item->AddExpressionList(exprl);
392                 }
393
394                 item->SetAbstract(m_Abstract);
395
396                 item->Compile()->Register();
397                 item.reset();
398         }
399         ;
400
401 object_declaration: T_OBJECT
402         | T_TEMPLATE
403         {
404                 m_Abstract = true;
405         }
406
407 object_inherits_list:
408         {
409                 $$ = NULL;
410         }
411         | T_STRING
412         {
413                 $$ = new std::vector<String>();
414                 $$->push_back($1);
415                 free($1);
416         }
417         | object_inherits_list ',' T_STRING
418         {
419                 if ($1)
420                         $$ = $1;
421                 else
422                         $$ = new std::vector<String>();
423
424                 $$->push_back($3);
425                 free($3);
426         }
427         ;
428
429 object_inherits_specifier:
430         {
431                 $$ = NULL;
432         }
433         | T_INHERITS object_inherits_list
434         {
435                 $$ = $2;
436         }
437         ;
438
439 expressionlist: '{' expressions '}'
440         {
441                 if ($2)
442                         $$ = $2;
443                 else
444                         $$ = new ExpressionList();
445         }
446         ;
447
448 expressions: expressions_inner
449         {
450                 $$ = $1;
451         }
452         | expressions_inner ','
453         {
454                 $$ = $1;
455         }
456
457 expressions_inner: /* empty */
458         {
459                 $$ = NULL;
460         }
461         | expression
462         {
463                 $$ = new ExpressionList();
464                 $$->AddExpression(*$1);
465                 delete $1;
466         }
467         | expressions_inner ',' expression
468         {
469                 if ($1)
470                         $$ = $1;
471                 else
472                         $$ = new ExpressionList();
473
474                 $$->AddExpression(*$3);
475                 delete $3;
476         }
477         ;
478
479 expression: identifier operator value
480         {
481                 $$ = new Expression($1, $2, *$3, yylloc);
482                 free($1);
483                 delete $3;
484         }
485         | identifier '[' T_STRING ']' operator value
486         {
487                 Expression subexpr($3, $5, *$6, yylloc);
488                 free($3);
489                 delete $6;
490
491                 ExpressionList::Ptr subexprl = make_shared<ExpressionList>();
492                 subexprl->AddExpression(subexpr);
493
494                 $$ = new Expression($1, OperatorPlus, subexprl, yylloc);
495                 free($1);
496         }
497         ;
498
499 operator: T_SET
500         | T_PLUS_EQUAL
501         | T_MINUS_EQUAL
502         | T_MULTIPLY_EQUAL
503         | T_DIVIDE_EQUAL
504         {
505                 $$ = $1;
506         }
507         ;
508
509 array_items: array_items_inner
510         {
511                 $$ = $1;
512         }
513         | array_items_inner ','
514         {
515                 $$ = $1;
516         }
517
518 array_items_inner: /* empty */
519         {
520                 $$ = NULL;
521         }
522         | aexpression
523         {
524                 $$ = new Array();
525                 $$->Add(*$1);
526                 delete $1;
527         }
528         | array_items_inner ',' aexpression
529         {
530                 if ($1)
531                         $$ = $1;
532                 else
533                         $$ = new Array();
534
535                 $$->Add(*$3);
536                 delete $3;
537         }
538         ;
539
540 aexpression: T_STRING
541         {
542                 $$ = new Value(make_shared<AExpression>(AEReturn, AValue(ATSimple, $1), yylloc));
543                 free($1);
544         }
545         | T_NUMBER
546         {
547                 $$ = new Value(make_shared<AExpression>(AEReturn, AValue(ATSimple, $1), yylloc));
548         }
549         | T_NULL
550         {
551                 $$ = new Value(make_shared<AExpression>(AEReturn, AValue(ATSimple, Empty), yylloc));
552         }
553         | T_IDENTIFIER '(' array_items ')'
554         {
555                 Array::Ptr arguments = Array::Ptr($3);
556                 $$ = new Value(make_shared<AExpression>(AEFunctionCall, AValue(ATSimple, $1), AValue(ATSimple, arguments), yylloc));
557                 free($1);
558         }
559         | T_IDENTIFIER
560         {
561                 $$ = new Value(make_shared<AExpression>(AEReturn, AValue(ATVariable, $1), yylloc));
562                 free($1);
563         }
564         | '!' aexpression
565         {
566                 $$ = new Value(make_shared<AExpression>(AENegate, static_cast<AExpression::Ptr>(*$2), yylloc));
567                 delete $2;
568         }
569         | '~' aexpression
570         {
571                 $$ = new Value(make_shared<AExpression>(AENegate, static_cast<AExpression::Ptr>(*$2), yylloc));
572                 delete $2;
573         }
574         | '[' array_items ']'
575         {
576                 $$ = new Value(make_shared<AExpression>(AEArray, AValue(ATSimple, Array::Ptr($2)), yylloc));
577         }
578         | '(' aexpression ')'
579         {
580                 $$ = $2;
581         }
582         | aexpression '+' aexpression
583         {
584                 $$ = new Value(make_shared<AExpression>(AEAdd, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3), yylloc));
585                 delete $1;
586                 delete $3;
587         }
588         | aexpression '-' aexpression
589         {
590                 $$ = new Value(make_shared<AExpression>(AESubtract, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3), yylloc));
591                 delete $1;
592                 delete $3;
593         }
594         | aexpression '*' aexpression
595         {
596                 $$ = new Value(make_shared<AExpression>(AEMultiply, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3), yylloc));
597                 delete $1;
598                 delete $3;
599         }
600         | aexpression '/' aexpression
601         {
602                 $$ = new Value(make_shared<AExpression>(AEDivide, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3), yylloc));
603                 delete $1;
604                 delete $3;
605         }
606         | aexpression '&' aexpression
607         {
608                 $$ = new Value(make_shared<AExpression>(AEBinaryAnd, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3), yylloc));
609                 delete $1;
610                 delete $3;
611         }
612         | aexpression '|' aexpression
613         {
614                 $$ = new Value(make_shared<AExpression>(AEBinaryOr, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3), yylloc));
615                 delete $1;
616                 delete $3;
617         }
618         | aexpression T_IN aexpression
619         {
620                 $$ = new Value(make_shared<AExpression>(AEIn, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3), yylloc));
621                 delete $1;
622                 delete $3;
623         }
624         | aexpression T_NOT_IN aexpression
625         {
626                 $$ = new Value(make_shared<AExpression>(AENotIn, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3), yylloc));
627                 delete $1;
628                 delete $3;
629         }
630         | aexpression T_EQUAL aexpression
631         {
632                 $$ = new Value(make_shared<AExpression>(AEEqual, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3), yylloc));
633                 delete $1;
634                 delete $3;
635         }
636         | aexpression T_NOT_EQUAL aexpression
637         {
638                 $$ = new Value(make_shared<AExpression>(AENotEqual, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3), yylloc));
639                 delete $1;
640                 delete $3;
641         }
642         | aexpression T_SHIFT_LEFT aexpression
643         {
644                 $$ = new Value(make_shared<AExpression>(AEShiftLeft, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3), yylloc));
645                 delete $1;
646                 delete $3;
647         }
648         | aexpression T_SHIFT_RIGHT aexpression
649         {
650                 $$ = new Value(make_shared<AExpression>(AEShiftRight, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3), yylloc));
651                 delete $1;
652                 delete $3;
653         }
654         | aexpression T_LOGICAL_AND aexpression
655         {
656                 $$ = new Value(make_shared<AExpression>(AELogicalAnd, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3), yylloc));
657                 delete $1;
658                 delete $3;
659         }
660         | aexpression T_LOGICAL_OR aexpression
661         {
662                 $$ = new Value(make_shared<AExpression>(AELogicalOr, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3), yylloc));
663                 delete $1;
664                 delete $3;
665         }
666         ;
667
668 value: expressionlist
669         {
670                 ExpressionList::Ptr exprl = ExpressionList::Ptr($1);
671                 $$ = new Value(exprl);
672         }
673         | aexpression
674         {
675                 AExpression::Ptr aexpr = *$1;
676                 $$ = new Value(aexpr->Evaluate(Dictionary::Ptr()));
677                 delete $1;
678         }
679         ;
680
681 optional_template: /* empty */
682         | T_TEMPLATE
683         ;
684
685 apply: T_APPLY optional_template identifier identifier T_TO identifier T_WHERE aexpression
686         {
687                 if (!ApplyRule::IsValidCombination($3, $6)) {
688                         BOOST_THROW_EXCEPTION(std::invalid_argument("'apply' cannot be used with types '" + String($3) + "' and '" + String($6) + "'."));
689                 }
690
691                 ApplyRule::AddRule($3, $4, $6, *$8, yylloc);
692                 delete $8;
693         }
694 %%