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