]> granicus.if.org Git - icinga2/blob - lib/config/config_parser.yy
Remove unnecessary includes.
[icinga2] / lib / config / config_parser.yy
1 %{
2  #define YYDEBUG 1
3  
4 /******************************************************************************
5  * Icinga 2                                                                   *
6  * Copyright (C) 2012-2014 Icinga Development Team (http://www.icinga.org)    *
7  *                                                                            *
8  * This program is free software; you can redistribute it and/or              *
9  * modify it under the terms of the GNU General Public License                *
10  * as published by the Free Software Foundation; either version 2             *
11  * of the License, or (at your option) any later version.                     *
12  *                                                                            *
13  * This program is distributed in the hope that it will be useful,            *
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of             *
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the              *
16  * GNU General Public License for more details.                               *
17  *                                                                            *
18  * You should have received a copy of the GNU General Public License          *
19  * along with this program; if not, write to the Free Software Foundation     *
20  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.             *
21  ******************************************************************************/
22
23 #include "i2-config.h"
24 #include "config/configitembuilder.h"
25 #include "config/configtype.h"
26 #include "config/configcompiler.h"
27 #include "config/configcompilercontext.h"
28 #include "config/configerror.h"
29 #include "config/typerule.h"
30 #include "config/typerulelist.h"
31 #include "config/aexpression.h"
32 #include "config/applyrule.h"
33 #include "config/objectrule.h"
34 #include "config/aexpression.h"
35 #include "base/value.h"
36 #include "base/utility.h"
37 #include "base/array.h"
38 #include "base/scriptvariable.h"
39 #include "base/exception.h"
40 #include "base/dynamictype.h"
41 #include <sstream>
42 #include <stack>
43 #include <boost/foreach.hpp>
44
45 #define YYLTYPE icinga::DebugInfo
46 #define YYERROR_VERBOSE
47
48 #define YYLLOC_DEFAULT(Current, Rhs, N)                                 \
49 do {                                                                    \
50         if (N) {                                                        \
51                 (Current).Path = YYRHSLOC(Rhs, 1).Path;                 \
52                 (Current).FirstLine = YYRHSLOC(Rhs, 1).FirstLine;       \
53                 (Current).FirstColumn = YYRHSLOC(Rhs, 1).FirstColumn;   \
54                 (Current).LastLine = YYRHSLOC(Rhs, N).LastLine;         \
55                 (Current).LastColumn = YYRHSLOC(Rhs, N).LastColumn;     \
56         } else {                                                        \
57                 (Current).Path = YYRHSLOC(Rhs, 0).Path;                 \
58                 (Current).FirstLine = (Current).LastLine =              \
59                 YYRHSLOC(Rhs, 0).LastLine;                              \
60                 (Current).FirstColumn = (Current).LastColumn =          \
61                 YYRHSLOC(Rhs, 0).LastColumn;                            \
62         }                                                               \
63 } while (0)
64
65 #define YY_LOCATION_PRINT(file, loc)                    \
66 do {                                                    \
67        std::ostringstream msgbuf;                       \
68        msgbuf << loc;                                   \
69        std::string str = msgbuf.str();                  \
70        fputs(str.c_str(), file);                        \
71 } while (0)
72
73 using namespace icinga;
74
75 int ignore_newlines = 0;
76
77 static void MakeRBinaryOp(Value** result, AExpression::OpCallback& op, Value *left, Value *right, DebugInfo& diLeft, DebugInfo& diRight)
78 {
79         *result = new Value(make_shared<AExpression>(op, *left, *right, DebugInfoRange(diLeft, diRight)));
80         delete left;
81         delete right;
82 }
83
84 %}
85
86 %pure-parser
87
88 %locations
89 %defines
90 %error-verbose
91
92 %parse-param { ConfigCompiler *context }
93 %lex-param { void *scanner }
94
95 %union {
96         char *text;
97         double num;
98         icinga::Value *variant;
99         icinga::AExpression::OpCallback op;
100         icinga::TypeSpecifier type;
101         std::vector<String> *slist;
102         Array *array;
103 }
104
105 %token T_NEWLINE "new-line"
106 %token <text> T_STRING
107 %token <text> T_STRING_ANGLE
108 %token <num> T_NUMBER
109 %token T_NULL
110 %token <text> T_IDENTIFIER
111
112 %token <op> T_SET "= (T_SET)"
113 %token <op> T_SET_PLUS "+= (T_SET_PLUS)"
114 %token <op> T_SET_MINUS "-= (T_SET_MINUS)"
115 %token <op> T_SET_MULTIPLY "*= (T_SET_MULTIPLY)"
116 %token <op> T_SET_DIVIDE "/= (T_SET_DIVIDE)"
117
118 %token <op> T_SHIFT_LEFT "<< (T_SHIFT_LEFT)"
119 %token <op> T_SHIFT_RIGHT ">> (T_SHIFT_RIGHT)"
120 %token <op> T_EQUAL "== (T_EQUAL)"
121 %token <op> T_NOT_EQUAL "!= (T_NOT_EQUAL)"
122 %token <op> T_IN "in (T_IN)"
123 %token <op> T_NOT_IN "!in (T_NOT_IN)"
124 %token <op> T_LOGICAL_AND "&& (T_LOGICAL_AND)"
125 %token <op> T_LOGICAL_OR "|| (T_LOGICAL_OR)"
126 %token <op> T_LESS_THAN_OR_EQUAL "<= (T_LESS_THAN_OR_EQUAL)"
127 %token <op> T_GREATER_THAN_OR_EQUAL ">= (T_GREATER_THAN_OR_EQUAL)"
128 %token <op> T_PLUS "+ (T_PLUS)"
129 %token <op> T_MINUS "- (T_MINUS)"
130 %token <op> T_MULTIPLY "* (T_MULTIPLY)"
131 %token <op> T_DIVIDE_OP "/ (T_DIVIDE_OP)"
132 %token <op> T_BINARY_AND "& (T_BINARY_AND)"
133 %token <op> T_BINARY_OR "| (T_BINARY_OR)"
134 %token <op> T_LESS_THAN "< (T_LESS_THAN)"
135 %token <op> T_GREATER_THAN "> (T_GREATER_THAN)"
136
137 %token T_CONST "const (T_CONST)"
138 %token <type> T_TYPE_DICTIONARY "dictionary (T_TYPE_DICTIONARY)"
139 %token <type> T_TYPE_ARRAY "array (T_TYPE_ARRAY)"
140 %token <type> T_TYPE_NUMBER "number (T_TYPE_NUMBER)"
141 %token <type> T_TYPE_STRING "string (T_TYPE_STRING)"
142 %token <type> T_TYPE_SCALAR "scalar (T_TYPE_SCALAR)"
143 %token <type> T_TYPE_ANY "any (T_TYPE_ANY)"
144 %token <type> T_TYPE_NAME "name (T_TYPE_NAME)"
145 %token T_VALIDATOR "%validator (T_VALIDATOR)"
146 %token T_REQUIRE "%require (T_REQUIRE)"
147 %token T_ATTRIBUTE "%attribute (T_ATTRIBUTE)"
148 %token T_TYPE "type (T_TYPE)"
149 %token T_OBJECT "object (T_OBJECT)"
150 %token T_TEMPLATE "template (T_TEMPLATE)"
151 %token T_INCLUDE "include (T_INCLUDE)"
152 %token T_INCLUDE_RECURSIVE "include_recursive (T_INCLUDE_RECURSIVE)"
153 %token T_LIBRARY "library (T_LIBRARY)"
154 %token T_INHERITS "inherits (T_INHERITS)"
155 %token T_PARTIAL "partial (T_PARTIAL)"
156 %token T_APPLY "apply (T_APPLY)"
157 %token T_TO "to (T_TO)"
158 %token T_WHERE "where (T_WHERE)"
159 %token T_IMPORT "import (T_IMPORT)"
160 %token T_ASSIGN "assign (T_ASSIGN)"
161 %token T_IGNORE "ignore (T_IGNORE)"
162 %token T_FUNCTION "function (T_FUNCTION)"
163 %token T_LAMBDA "lambda (T_LAMBDA)"
164 %token T_RETURN "return (T_RETURN)"
165 %token T_ZONE "zone (T_ZONE)"
166 %token T_FOR "for (T_FOR)"
167
168 %type <text> identifier
169 %type <array> rterm_items
170 %type <array> rterm_items_inner
171 %type <array> identifier_items
172 %type <array> identifier_items_inner
173 %type <array> lterm_items
174 %type <array> lterm_items_inner
175 %type <variant> typerulelist
176 %type <op> lbinary_op
177 %type <type> type
178 %type <num> partial_specifier
179 %type <variant> rterm
180 %type <variant> rterm_array
181 %type <variant> rterm_scope
182 %type <variant> lterm
183 %type <variant> object
184 %type <variant> apply
185 %type <text> target_type_specifier
186
187 %left T_LOGICAL_OR
188 %left T_LOGICAL_AND
189 %left T_BINARY_OR
190 %left T_BINARY_AND
191 %left T_IN
192 %left T_NOT_IN
193 %left T_EQUAL T_NOT_EQUAL
194 %left T_LESS_THAN T_LESS_THAN_OR_EQUAL T_GREATER_THAN T_GREATER_THAN_OR_EQUAL
195 %left T_SHIFT_LEFT T_SHIFT_RIGHT
196 %left T_PLUS T_MINUS
197 %left T_MULTIPLY T_DIVIDE_OP
198 %right '!' '~'
199 %left '.' '(' '['
200 %right ':'
201 %{
202
203 int yylex(YYSTYPE *lvalp, YYLTYPE *llocp, void *scanner);
204
205 void yyerror(YYLTYPE *locp, ConfigCompiler *, const char *err)
206 {
207         std::ostringstream message;
208         message << *locp << ": " << err;
209         ConfigCompilerContext::GetInstance()->AddMessage(true, message.str(), *locp);
210 }
211
212 int yyparse(ConfigCompiler *context);
213
214 static bool m_Abstract;
215
216 static std::stack<TypeRuleList::Ptr> m_RuleLists;
217 static ConfigType::Ptr m_Type;
218
219 static Dictionary::Ptr m_ModuleScope;
220 static String m_Zone;
221 static int m_StatementNum;
222
223 static bool m_Apply;
224 static bool m_ObjectAssign;
225 static bool m_SeenAssign;
226 static AExpression::Ptr m_Assign;
227 static AExpression::Ptr m_Ignore;
228
229 void ConfigCompiler::Compile(void)
230 {
231         m_ModuleScope = make_shared<Dictionary>();
232         
233         String parentZone = m_Zone;
234         int parentStatementNum = m_StatementNum;
235         m_StatementNum = 0;
236
237         try {
238                 yyparse(this);
239         } catch (const ConfigError& ex) {
240                 const DebugInfo *di = boost::get_error_info<errinfo_debuginfo>(ex);
241                 ConfigCompilerContext::GetInstance()->AddMessage(true, ex.what(), di ? *di : DebugInfo());
242         } catch (const std::exception& ex) {
243                 ConfigCompilerContext::GetInstance()->AddMessage(true, DiagnosticInformation(ex));
244         }
245
246         m_Zone = parentZone;
247         m_StatementNum = parentStatementNum;
248 }
249
250 #define scanner (context->GetScanner())
251
252 %}
253
254 %%
255 statements: /* empty */
256         | statements statement
257         ;
258
259 statement: type | zone | include | include_recursive | library | constant
260         {
261                 m_StatementNum++;
262         }
263         | newlines
264         { }
265         | lterm
266         {
267                 AExpression::Ptr aexpr = *$1;
268                 aexpr->Evaluate(m_ModuleScope);
269                 delete $1;
270
271                 m_StatementNum++;
272         }
273         ;
274
275 zone: T_ZONE rterm sep
276         {
277                 AExpression::Ptr aexpr = *$2;
278                 delete $2;
279
280                 if (!m_Zone.IsEmpty())
281                         BOOST_THROW_EXCEPTION(std::invalid_argument("Zone name cannot be changed once it's been set."));
282
283                 if (m_StatementNum != 0)
284                         BOOST_THROW_EXCEPTION(std::invalid_argument("'zone' directive must be the first statement in a file."));
285
286                 m_Zone = aexpr->Evaluate(m_ModuleScope);
287         }
288         | T_ZONE rterm
289         {
290                 AExpression::Ptr aexpr = *$2;
291                 delete $2;
292
293                 if (!m_Zone.IsEmpty())
294                         BOOST_THROW_EXCEPTION(std::invalid_argument("Zone name cannot be changed once it's been set."));
295
296                 m_Zone = aexpr->Evaluate(m_ModuleScope);
297         }
298         rterm_scope sep
299         {
300                 AExpression::Ptr ascope = *$4;
301                 delete $4;
302
303                 try {
304                         ascope->Evaluate(m_ModuleScope);
305                         m_Zone = String();
306                 } catch (...) {
307                         m_Zone = String();
308                 }
309         }
310         ;
311
312 include: T_INCLUDE rterm sep
313         {
314                 AExpression::Ptr aexpr = *$2;
315                 delete $2;
316
317                 context->HandleInclude(aexpr->Evaluate(m_ModuleScope), false, DebugInfoRange(@1, @2));
318         }
319         | T_INCLUDE T_STRING_ANGLE
320         {
321                 context->HandleInclude($2, true, DebugInfoRange(@1, @2));
322                 free($2);
323         }
324         ;
325
326 include_recursive: T_INCLUDE_RECURSIVE rterm
327         {
328                 AExpression::Ptr aexpr = *$2;
329                 delete $2;
330
331                 context->HandleIncludeRecursive(aexpr->Evaluate(m_ModuleScope), "*.conf", DebugInfoRange(@1, @2));
332         }
333         | T_INCLUDE_RECURSIVE rterm ',' rterm
334         {
335                 AExpression::Ptr aexpr1 = *$2;
336                 delete $2;
337
338                 AExpression::Ptr aexpr2 = *$4;
339                 delete $4;
340
341                 context->HandleIncludeRecursive(aexpr1->Evaluate(m_ModuleScope), aexpr2->Evaluate(m_ModuleScope), DebugInfoRange(@1, @4));
342         }
343         ;
344
345 library: T_LIBRARY T_STRING sep
346         {
347                 context->HandleLibrary($2);
348                 free($2);
349         }
350         ;
351
352 constant: T_CONST identifier T_SET rterm sep
353         {
354                 AExpression::Ptr aexpr = *$4;
355                 delete $4;
356
357                 ScriptVariable::Ptr sv = ScriptVariable::Set($2, aexpr->Evaluate(m_ModuleScope));
358                 sv->SetConstant(true);
359
360                 free($2);
361         }
362         ;
363
364 identifier: T_IDENTIFIER
365         | T_STRING
366         {
367                 $$ = $1;
368         }
369         ;
370
371 type: partial_specifier T_TYPE identifier
372         {
373                 String name = String($3);
374                 free($3);
375
376                 m_Type = ConfigType::GetByName(name);
377
378                 if (!m_Type) {
379                         if ($1)
380                                 BOOST_THROW_EXCEPTION(ConfigError("Partial type definition for unknown type '" + name + "'") << errinfo_debuginfo(DebugInfoRange(@1, @3)));
381
382                         m_Type = make_shared<ConfigType>(name, DebugInfoRange(@1, @3));
383                         m_Type->Register();
384                 }
385         }
386         type_inherits_specifier typerulelist sep
387         {
388                 TypeRuleList::Ptr ruleList = *$6;
389                 m_Type->GetRuleList()->AddRules(ruleList);
390                 m_Type->GetRuleList()->AddRequires(ruleList);
391
392                 String validator = ruleList->GetValidator();
393                 if (!validator.IsEmpty())
394                         m_Type->GetRuleList()->SetValidator(validator);
395
396                 delete $6;
397         }
398         ;
399
400 partial_specifier: /* Empty */
401         {
402                 $$ = 0;
403         }
404         | T_PARTIAL
405         {
406                 $$ = 1;
407         }
408         ;
409
410 typerulelist: '{'
411         {
412                 m_RuleLists.push(make_shared<TypeRuleList>());
413         }
414         typerules
415         '}'
416         {
417                 $$ = new Value(m_RuleLists.top());
418                 m_RuleLists.pop();
419         }
420         ;
421
422 typerules: typerules_inner
423         | typerules_inner sep
424
425 typerules_inner: /* empty */
426         | typerule
427         | typerules_inner sep typerule
428         ;
429
430 typerule: T_REQUIRE T_STRING
431         {
432                 m_RuleLists.top()->AddRequire($2);
433                 free($2);
434         }
435         | T_VALIDATOR T_STRING
436         {
437                 m_RuleLists.top()->SetValidator($2);
438                 free($2);
439         }
440         | T_ATTRIBUTE type T_STRING
441         {
442                 TypeRule rule($2, String(), $3, TypeRuleList::Ptr(), DebugInfoRange(@1, @3));
443                 free($3);
444
445                 m_RuleLists.top()->AddRule(rule);
446         }
447         | T_ATTRIBUTE T_TYPE_NAME '(' identifier ')' T_STRING
448         {
449                 TypeRule rule($2, $4, $6, TypeRuleList::Ptr(), DebugInfoRange(@1, @6));
450                 free($4);
451                 free($6);
452
453                 m_RuleLists.top()->AddRule(rule);
454         }
455         | T_ATTRIBUTE type T_STRING typerulelist
456         {
457                 TypeRule rule($2, String(), $3, *$4, DebugInfoRange(@1, @4));
458                 free($3);
459                 delete $4;
460                 m_RuleLists.top()->AddRule(rule);
461         }
462         ;
463
464 type_inherits_specifier: /* empty */
465         | T_INHERITS identifier
466         {
467                 m_Type->SetParent($2);
468                 free($2);
469         }
470         ;
471
472 type: T_TYPE_DICTIONARY
473         | T_TYPE_ARRAY
474         | T_TYPE_NUMBER
475         | T_TYPE_STRING
476         | T_TYPE_SCALAR
477         | T_TYPE_ANY
478         | T_TYPE_NAME
479         {
480                 $$ = $1;
481         }
482         ;
483
484 object:
485         {
486                 m_Abstract = false;
487                 m_ObjectAssign = true;
488                 m_SeenAssign = false;
489                 m_Assign = make_shared<AExpression>(&AExpression::OpLiteral, false, DebugInfo());
490                 m_Ignore = make_shared<AExpression>(&AExpression::OpLiteral, false, DebugInfo());
491         }
492         object_declaration identifier rterm rterm_scope
493         {
494                 m_ObjectAssign = false;
495
496                 Array::Ptr args = make_shared<Array>();
497                 
498                 args->Add(m_Abstract);
499
500                 String type = $3;
501                 args->Add(type);
502                 free($3);
503
504                 args->Add(*$4);
505                 delete $4;
506
507                 AExpression::Ptr exprl = *$5;
508                 delete $5;
509                 exprl->MakeInline();
510
511                 if (m_SeenAssign && !ObjectRule::IsValidSourceType(type))
512                         BOOST_THROW_EXCEPTION(ConfigError("object rule 'assign' cannot be used for type '" + type + "'") << errinfo_debuginfo(DebugInfoRange(@2, @3)));
513
514                 AExpression::Ptr rex = make_shared<AExpression>(&AExpression::OpLogicalNegate, m_Ignore, DebugInfoRange(@2, @5));
515                 AExpression::Ptr filter = make_shared<AExpression>(&AExpression::OpLogicalAnd, m_Assign, rex, DebugInfoRange(@2, @5));
516
517                 args->Add(filter);
518
519                 args->Add(m_Zone);
520
521                 $$ = new Value(make_shared<AExpression>(&AExpression::OpObject, args, exprl, DebugInfoRange(@2, @5)));
522
523                 m_Assign.reset();
524                 m_Ignore.reset();
525         }
526         ;
527
528 object_declaration: T_OBJECT
529         | T_TEMPLATE
530         {
531                 m_Abstract = true;
532         }
533
534 identifier_items: identifier_items_inner
535         {
536                 $$ = $1;
537         }
538         | identifier_items_inner ','
539         {
540                 $$ = $1;
541         }
542         ;
543
544 identifier_items_inner: /* empty */
545         {
546                 $$ = new Array();
547         }
548         | identifier
549         {
550                 $$ = new Array();
551                 $$->Add($1);
552                 free($1);
553         }
554         | identifier_items_inner ',' identifier
555         {
556                 if ($1)
557                         $$ = $1;
558                 else
559                         $$ = new Array();
560
561                 $$->Add($3);
562                 free($3);
563         }
564         ;
565
566 lbinary_op: T_SET
567         | T_SET_PLUS
568         | T_SET_MINUS
569         | T_SET_MULTIPLY
570         | T_SET_DIVIDE
571         {
572                 $$ = $1;
573         }
574         ;
575
576 lterm_items: /* empty */
577         {
578                 $$ = new Array();
579         }
580         | lterm_items_inner
581         {
582                 $$ = $1;
583         }
584         | lterm_items_inner sep
585         {
586                 $$ = $1;
587         }
588
589 lterm_items_inner: lterm
590         {
591                 $$ = new Array();
592                 $$->Add(*$1);
593                 delete $1;
594         }
595         | lterm_items_inner sep lterm
596         {
597                 if ($1)
598                         $$ = $1;
599                 else
600                         $$ = new Array();
601
602                 $$->Add(*$3);
603                 delete $3;
604         }
605         ;
606
607 lterm: identifier lbinary_op rterm
608         {
609                 AExpression::Ptr aindex = make_shared<AExpression>(&AExpression::OpLiteral, $1, @1);
610                 free($1);
611
612                 $$ = new Value(make_shared<AExpression>($2, aindex, *$3, DebugInfoRange(@1, @3)));
613                 delete $3;
614         }
615         | identifier '[' rterm ']' lbinary_op rterm
616         {
617                 AExpression::Ptr subexpr = make_shared<AExpression>($5, *$3, *$6, DebugInfoRange(@1, @6));
618                 delete $3;
619                 delete $6;
620
621                 Array::Ptr subexprl = make_shared<Array>();
622                 subexprl->Add(subexpr);
623                 
624                 AExpression::Ptr aindex = make_shared<AExpression>(&AExpression::OpLiteral, $1, @1);
625                 free($1);
626
627                 AExpression::Ptr expr = make_shared<AExpression>(&AExpression::OpDict, subexprl, DebugInfoRange(@1, @6));
628                 $$ = new Value(make_shared<AExpression>(&AExpression::OpSetPlus, aindex, expr, DebugInfoRange(@1, @6)));
629         }
630         | identifier '.' T_IDENTIFIER lbinary_op rterm
631         {
632                 AExpression::Ptr aindex = make_shared<AExpression>(&AExpression::OpLiteral, $3, @3);
633                 AExpression::Ptr subexpr = make_shared<AExpression>($4, aindex, *$5, DebugInfoRange(@1, @5));
634                 free($3);
635                 delete $5;
636
637                 Array::Ptr subexprl = make_shared<Array>();
638                 subexprl->Add(subexpr);
639
640                 AExpression::Ptr aindexl = make_shared<AExpression>(&AExpression::OpLiteral, $1, @1);
641                 free($1);
642
643                 AExpression::Ptr expr = make_shared<AExpression>(&AExpression::OpDict, subexprl, DebugInfoRange(@1, @5));
644                 $$ = new Value(make_shared<AExpression>(&AExpression::OpSetPlus, aindexl, expr, DebugInfoRange(@1, @5)));
645         }
646         | T_IMPORT rterm
647         {
648                 AExpression::Ptr avar = make_shared<AExpression>(&AExpression::OpVariable, "type", DebugInfoRange(@1, @2));
649                 $$ = new Value(make_shared<AExpression>(&AExpression::OpImport, avar, *$2, DebugInfoRange(@1, @2)));
650                 delete $2;
651         }
652         | T_ASSIGN T_WHERE rterm
653         {
654                 if (!(m_Apply || m_ObjectAssign))
655                         BOOST_THROW_EXCEPTION(ConfigError("'assign' keyword not valid in this context."));
656
657                 m_SeenAssign = true;
658
659                 m_Assign = make_shared<AExpression>(&AExpression::OpLogicalOr, m_Assign, *$3, DebugInfoRange(@1, @3));
660                 delete $3;
661
662                 $$ = new Value(make_shared<AExpression>(&AExpression::OpLiteral, Empty, DebugInfoRange(@1, @3)));
663         }
664         | T_IGNORE T_WHERE rterm
665         {
666                 if (!(m_Apply || m_ObjectAssign))
667                         BOOST_THROW_EXCEPTION(ConfigError("'ignore' keyword not valid in this context."));
668
669                 m_Ignore = make_shared<AExpression>(&AExpression::OpLogicalOr, m_Ignore, *$3, DebugInfoRange(@1, @3));
670
671                 delete $3;
672
673                 $$ = new Value(make_shared<AExpression>(&AExpression::OpLiteral, Empty, DebugInfoRange(@1, @3)));
674         }
675         | T_RETURN rterm
676         {
677                 AExpression::Ptr aname = make_shared<AExpression>(&AExpression::OpLiteral, "__result", @1);
678                 $$ = new Value(make_shared<AExpression>(&AExpression::OpSet, aname, *$2, DebugInfoRange(@1, @2)));
679                 delete $2;
680
681         }
682         | apply
683         {
684                 $$ = $1;
685         }
686         | object
687         {
688                 $$ = $1;
689         }
690         | rterm
691         {
692                 $$ = $1;
693         }
694         ;
695         
696 rterm_items: /* empty */
697         {
698                 $$ = new Array();
699         }
700         | rterm_items_inner
701         {
702                 $$ = $1;
703         }
704         | rterm_items_inner arraysep
705         {
706                 $$ = $1;
707         }
708         ;
709
710 rterm_items_inner: rterm
711         {
712                 $$ = new Array();
713                 $$->Add(*$1);
714                 delete $1;
715         }
716         | rterm_items_inner arraysep rterm
717         {
718                 $$ = $1;
719                 $$->Add(*$3);
720                 delete $3;
721         }
722         ;
723
724 rterm_array: '[' newlines rterm_items newlines ']'
725         {
726                 $$ = new Value(make_shared<AExpression>(&AExpression::OpArray, Array::Ptr($3), DebugInfoRange(@1, @5)));
727         }
728         | '[' newlines rterm_items ']'
729         {
730                 $$ = new Value(make_shared<AExpression>(&AExpression::OpArray, Array::Ptr($3), DebugInfoRange(@1, @4)));
731         }
732         | '[' rterm_items newlines ']'
733         {
734                 $$ = new Value(make_shared<AExpression>(&AExpression::OpArray, Array::Ptr($2), DebugInfoRange(@1, @4)));
735         }
736         | '[' rterm_items ']'
737         {
738                 $$ = new Value(make_shared<AExpression>(&AExpression::OpArray, Array::Ptr($2), DebugInfoRange(@1, @3)));
739         }
740         ;
741
742 rterm_scope: '{' newlines lterm_items newlines '}'
743         {
744                 $$ = new Value(make_shared<AExpression>(&AExpression::OpDict, Array::Ptr($3), DebugInfoRange(@1, @5)));
745         }
746         | '{' newlines lterm_items '}'
747         {
748                 $$ = new Value(make_shared<AExpression>(&AExpression::OpDict, Array::Ptr($3), DebugInfoRange(@1, @4)));
749         }
750         | '{' lterm_items newlines '}'
751         {
752                 $$ = new Value(make_shared<AExpression>(&AExpression::OpDict, Array::Ptr($2), DebugInfoRange(@1, @4)));
753         }
754         | '{' lterm_items '}'
755         {
756                 $$ = new Value(make_shared<AExpression>(&AExpression::OpDict, Array::Ptr($2), DebugInfoRange(@1, @3)));
757         }
758         ;
759
760 rterm: T_STRING
761         {
762                 $$ = new Value(make_shared<AExpression>(&AExpression::OpLiteral, $1, @1));
763                 free($1);
764         }
765         | T_NUMBER
766         {
767                 $$ = new Value(make_shared<AExpression>(&AExpression::OpLiteral, $1, @1));
768         }
769         | T_NULL
770         {
771                 $$ = new Value(make_shared<AExpression>(&AExpression::OpLiteral, Empty, @1));
772         }
773         | rterm '.' T_IDENTIFIER
774         {
775                 $$ = new Value(make_shared<AExpression>(&AExpression::OpIndexer, *$1, make_shared<AExpression>(&AExpression::OpLiteral, $3, @3), DebugInfoRange(@1, @3)));
776                 delete $1;
777                 free($3);
778         }
779         | rterm '(' rterm_items ')'
780         {
781                 Array::Ptr arguments = Array::Ptr($3);
782                 $$ = new Value(make_shared<AExpression>(&AExpression::OpFunctionCall, *$1, make_shared<AExpression>(&AExpression::OpLiteral, arguments, @3), DebugInfoRange(@1, @4)));
783                 delete $1;
784         }
785         | T_IDENTIFIER
786         {
787                 $$ = new Value(make_shared<AExpression>(&AExpression::OpVariable, $1, @1));
788                 free($1);
789         }
790         | '!' rterm
791         {
792                 $$ = new Value(make_shared<AExpression>(&AExpression::OpLogicalNegate, *$2, DebugInfoRange(@1, @2)));
793                 delete $2;
794         }
795         | '~' rterm
796         {
797                 $$ = new Value(make_shared<AExpression>(&AExpression::OpNegate, *$2, DebugInfoRange(@1, @2)));
798                 delete $2;
799         }
800         | rterm '[' rterm ']'
801         {
802                 $$ = new Value(make_shared<AExpression>(&AExpression::OpIndexer, *$1, *$3, DebugInfoRange(@1, @4)));
803                 delete $1;
804                 delete $3;
805         }
806         | rterm_array
807         {
808                 $$ = $1;
809         }
810         | rterm_scope
811         {
812                 $$ = $1;
813         }
814         | '('
815         {
816                 ignore_newlines++;
817         }
818         rterm ')'
819         {
820                 ignore_newlines--;
821                 $$ = $3;
822         }
823         | rterm T_LOGICAL_OR rterm { MakeRBinaryOp(&$$, $2, $1, $3, @1, @3); }
824         | rterm T_LOGICAL_AND rterm { MakeRBinaryOp(&$$, $2, $1, $3, @1, @3); }
825         | rterm T_BINARY_OR rterm { MakeRBinaryOp(&$$, $2, $1, $3, @1, @3); }
826         | rterm T_BINARY_AND rterm { MakeRBinaryOp(&$$, $2, $1, $3, @1, @3); }
827         | rterm T_IN rterm { MakeRBinaryOp(&$$, $2, $1, $3, @1, @3); }
828         | rterm T_NOT_IN rterm { MakeRBinaryOp(&$$, $2, $1, $3, @1, @3); }
829         | rterm T_EQUAL rterm { MakeRBinaryOp(&$$, $2, $1, $3, @1, @3); }
830         | rterm T_NOT_EQUAL rterm { MakeRBinaryOp(&$$, $2, $1, $3, @1, @3); }
831         | rterm T_LESS_THAN rterm { MakeRBinaryOp(&$$, $2, $1, $3, @1, @3); }
832         | rterm T_LESS_THAN_OR_EQUAL rterm { MakeRBinaryOp(&$$, $2, $1, $3, @1, @3); }
833         | rterm T_GREATER_THAN rterm { MakeRBinaryOp(&$$, $2, $1, $3, @1, @3); }
834         | rterm T_GREATER_THAN_OR_EQUAL rterm { MakeRBinaryOp(&$$, $2, $1, $3, @1, @3); }
835         | rterm T_SHIFT_LEFT rterm { MakeRBinaryOp(&$$, $2, $1, $3, @1, @3); }
836         | rterm T_SHIFT_RIGHT rterm { MakeRBinaryOp(&$$, $2, $1, $3, @1, @3); }
837         | rterm T_PLUS rterm { MakeRBinaryOp(&$$, $2, $1, $3, @1, @3); }
838         | rterm T_MINUS rterm { MakeRBinaryOp(&$$, $2, $1, $3, @1, @3); }
839         | rterm T_MULTIPLY rterm { MakeRBinaryOp(&$$, $2, $1, $3, @1, @3); }
840         | rterm T_DIVIDE_OP rterm { MakeRBinaryOp(&$$, $2, $1, $3, @1, @3); }
841         | T_FUNCTION identifier '(' identifier_items ')' rterm_scope
842         {
843                 Array::Ptr arr = make_shared<Array>();
844
845                 arr->Add($2);
846                 free($2);
847
848                 AExpression::Ptr aexpr = *$6;
849                 delete $6;
850                 aexpr->MakeInline();
851                 arr->Add(aexpr);
852
853                 $$ = new Value(make_shared<AExpression>(&AExpression::OpFunction, arr, Array::Ptr($4), DebugInfoRange(@1, @6)));
854         }
855         | T_FUNCTION '(' identifier_items ')' rterm_scope
856         {
857                 Array::Ptr arr = make_shared<Array>();
858
859                 arr->Add(Empty);
860
861                 AExpression::Ptr aexpr = *$5;
862                 delete $5;
863                 aexpr->MakeInline();
864                 arr->Add(aexpr);
865
866                 $$ = new Value(make_shared<AExpression>(&AExpression::OpFunction, arr, Array::Ptr($3), DebugInfoRange(@1, @5)));
867         }
868         | T_LAMBDA identifier_items ':' rterm
869         {
870                 Array::Ptr arr = make_shared<Array>();
871
872                 arr->Add(Empty);
873
874                 Array::Ptr arrex = make_shared<Array>();
875                 arrex->Add(make_shared<AExpression>(&AExpression::OpSet, make_shared<AExpression>(&AExpression::OpLiteral, "__result", @4), *$4, @4));
876                 delete $4;
877                 AExpression::Ptr aexpr = make_shared<AExpression>(&AExpression::OpDict, arrex, true, @4);
878
879                 arr->Add(aexpr);
880
881                 $$ = new Value(make_shared<AExpression>(&AExpression::OpFunction, arr, Array::Ptr($2), DebugInfoRange(@1, @4)));
882         }
883         | T_FOR '(' identifier T_IN rterm ')' rterm_scope
884         {
885                 Array::Ptr arr = make_shared<Array>();
886
887                 arr->Add($3);
888                 free($3);
889
890                 AExpression::Ptr aexpr = *$5;
891                 delete $5;
892                 arr->Add(aexpr);
893
894                 AExpression::Ptr ascope = *$7;
895                 delete $7;
896
897                 $$ = new Value(make_shared<AExpression>(&AExpression::OpFor, arr, ascope, DebugInfoRange(@1, @7)));
898         }
899         ;
900
901 target_type_specifier: /* empty */
902         {
903                 $$ = strdup("");
904         }
905         | T_TO identifier
906         {
907                 $$ = $2;
908         }
909         ;
910
911 apply:
912         {
913                 m_Apply = true;
914                 m_SeenAssign = false;
915                 m_Assign = make_shared<AExpression>(&AExpression::OpLiteral, false, DebugInfo());
916                 m_Ignore = make_shared<AExpression>(&AExpression::OpLiteral, false, DebugInfo());
917         }
918         T_APPLY identifier rterm target_type_specifier rterm
919         {
920                 m_Apply = false;
921
922                 String type = $3;
923                 free($3);
924                 AExpression::Ptr aname = *$4;
925                 delete $4;
926                 String target = $5;
927                 free($5);
928
929                 if (!ApplyRule::IsValidSourceType(type))
930                         BOOST_THROW_EXCEPTION(ConfigError("'apply' cannot be used with type '" + type + "'") << errinfo_debuginfo(DebugInfoRange(@2, @3)));
931
932                 if (!ApplyRule::IsValidTargetType(type, target)) {
933                         if (target == "") {
934                                 std::vector<String> types = ApplyRule::GetTargetTypes(type);
935                                 String typeNames;
936
937                                 for (std::vector<String>::size_type i = 0; i < types.size(); i++) {
938                                         if (typeNames != "") {
939                                                 if (i == types.size() - 1)
940                                                         typeNames += " or ";
941                                                 else
942                                                         typeNames += ", ";
943                                         }
944
945                                         typeNames += "'" + types[i] + "'";
946                                 }
947
948                                 BOOST_THROW_EXCEPTION(ConfigError("'apply' target type is ambiguous (can be one of " + typeNames + "): use 'to' to specify a type") << errinfo_debuginfo(DebugInfoRange(@2, @3)));
949                         } else
950                                 BOOST_THROW_EXCEPTION(ConfigError("'apply' target type '" + target + "' is invalid") << errinfo_debuginfo(DebugInfoRange(@2, @5)));
951                 }
952
953                 AExpression::Ptr exprl = *$6;
954                 delete $6;
955
956                 exprl->MakeInline();
957
958                 // assign && !ignore
959                 if (!m_SeenAssign)
960                         BOOST_THROW_EXCEPTION(ConfigError("'apply' is missing 'assign'") << errinfo_debuginfo(DebugInfoRange(@2, @3)));
961
962                 AExpression::Ptr rex = make_shared<AExpression>(&AExpression::OpLogicalNegate, m_Ignore, DebugInfoRange(@2, @5));
963                 AExpression::Ptr filter = make_shared<AExpression>(&AExpression::OpLogicalAnd, m_Assign, rex, DebugInfoRange(@2, @5));
964
965                 Array::Ptr args = make_shared<Array>();
966                 args->Add(type);
967                 args->Add(target);
968                 args->Add(aname);
969                 args->Add(filter);
970
971                 $$ = new Value(make_shared<AExpression>(&AExpression::OpApply, args, exprl, DebugInfoRange(@2, @5)));
972
973                 m_Assign.reset();
974                 m_Ignore.reset();
975         }
976         ;
977
978 newlines: T_NEWLINE
979         | newlines T_NEWLINE
980         ;
981
982 /* required separator */
983 sep: ',' newlines
984         | ','
985         | ';' newlines
986         | ';'
987         | newlines
988         ;
989
990 arraysep: ',' newlines
991         | ','
992         ;
993
994 %%