]> granicus.if.org Git - icinga2/blob - lib/config/config_parser.yy
Rename C++ header files.
[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 "config/i2-config.hpp"
24 #include "config/configitembuilder.hpp"
25 #include "config/configtype.hpp"
26 #include "config/configcompiler.hpp"
27 #include "config/configcompilercontext.hpp"
28 #include "config/configerror.hpp"
29 #include "config/typerule.hpp"
30 #include "config/typerulelist.hpp"
31 #include "config/aexpression.hpp"
32 #include "config/applyrule.hpp"
33 #include "config/objectrule.hpp"
34 #include "config/aexpression.hpp"
35 #include "base/value.hpp"
36 #include "base/utility.hpp"
37 #include "base/array.hpp"
38 #include "base/scriptvariable.hpp"
39 #include "base/exception.hpp"
40 #include "base/dynamictype.hpp"
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_RETURN "return (T_RETURN)"
164 %token T_ZONE "zone (T_ZONE)"
165 %token T_FOR "for (T_FOR)"
166
167 %type <text> identifier
168 %type <array> rterm_items
169 %type <array> rterm_items_inner
170 %type <array> identifier_items
171 %type <array> identifier_items_inner
172 %type <array> lterm_items
173 %type <array> lterm_items_inner
174 %type <variant> typerulelist
175 %type <op> lbinary_op
176 %type <type> type
177 %type <num> partial_specifier
178 %type <variant> rterm
179 %type <variant> rterm_array
180 %type <variant> rterm_scope
181 %type <variant> lterm
182 %type <variant> object
183 %type <variant> apply
184 %type <text> target_type_specifier
185
186 %left T_LOGICAL_OR
187 %left T_LOGICAL_AND
188 %left T_BINARY_OR
189 %left T_BINARY_AND
190 %left T_IN
191 %left T_NOT_IN
192 %left T_EQUAL T_NOT_EQUAL
193 %left T_LESS_THAN T_LESS_THAN_OR_EQUAL T_GREATER_THAN T_GREATER_THAN_OR_EQUAL
194 %left T_SHIFT_LEFT T_SHIFT_RIGHT
195 %left T_PLUS T_MINUS
196 %left T_MULTIPLY T_DIVIDE_OP
197 %right '!' '~'
198 %left '.' '(' '['
199 %right ':'
200 %{
201
202 int yylex(YYSTYPE *lvalp, YYLTYPE *llocp, void *scanner);
203
204 void yyerror(YYLTYPE *locp, ConfigCompiler *, const char *err)
205 {
206         std::ostringstream message;
207         message << *locp << ": " << err;
208         ConfigCompilerContext::GetInstance()->AddMessage(true, message.str(), *locp);
209 }
210
211 int yyparse(ConfigCompiler *context);
212
213 static bool m_Abstract;
214
215 static std::stack<TypeRuleList::Ptr> m_RuleLists;
216 static ConfigType::Ptr m_Type;
217
218 static Dictionary::Ptr m_ModuleScope;
219 static int m_StatementNum;
220
221 static bool m_Apply;
222 static bool m_ObjectAssign;
223 static bool m_SeenAssign;
224 static AExpression::Ptr m_Assign;
225 static AExpression::Ptr m_Ignore;
226
227 void ConfigCompiler::Compile(void)
228 {
229         m_ModuleScope = make_shared<Dictionary>();
230         
231         int parentStatementNum = m_StatementNum;
232         m_StatementNum = 0;
233
234         try {
235                 yyparse(this);
236         } catch (const ConfigError& ex) {
237                 const DebugInfo *di = boost::get_error_info<errinfo_debuginfo>(ex);
238                 ConfigCompilerContext::GetInstance()->AddMessage(true, ex.what(), di ? *di : DebugInfo());
239         } catch (const std::exception& ex) {
240                 ConfigCompilerContext::GetInstance()->AddMessage(true, DiagnosticInformation(ex));
241         }
242
243         m_StatementNum = parentStatementNum;
244 }
245
246 #define scanner (context->GetScanner())
247
248 %}
249
250 %%
251 statements: /* empty */
252         | statements statement
253         ;
254
255 statement: type | zone | include | include_recursive | library | constant
256         {
257                 m_StatementNum++;
258         }
259         | newlines
260         { }
261         | lterm
262         {
263                 AExpression::Ptr aexpr = *$1;
264                 aexpr->Evaluate(m_ModuleScope);
265                 delete $1;
266
267                 m_StatementNum++;
268         }
269         ;
270
271 zone: T_ZONE rterm sep
272         {
273                 AExpression::Ptr aexpr = *$2;
274                 delete $2;
275
276                 if (!context->GetZone().IsEmpty())
277                         BOOST_THROW_EXCEPTION(std::invalid_argument("Zone name cannot be changed once it's been set."));
278
279                 if (m_StatementNum != 0)
280                         BOOST_THROW_EXCEPTION(std::invalid_argument("'zone' directive must be the first statement in a file."));
281
282                 context->SetZone(aexpr->Evaluate(m_ModuleScope));
283         }
284         | T_ZONE rterm
285         {
286                 AExpression::Ptr aexpr = *$2;
287                 delete $2;
288
289                 if (!context->GetZone().IsEmpty())
290                         BOOST_THROW_EXCEPTION(std::invalid_argument("Zone name cannot be changed once it's been set."));
291
292                 context->SetZone(aexpr->Evaluate(m_ModuleScope));
293         }
294         rterm_scope sep
295         {
296                 AExpression::Ptr ascope = *$4;
297                 delete $4;
298
299                 try {
300                         ascope->Evaluate(m_ModuleScope);
301                         context->SetZone(String());
302                 } catch (...) {
303                         context->SetZone(String());
304                 }
305         }
306         ;
307
308 include: T_INCLUDE rterm sep
309         {
310                 AExpression::Ptr aexpr = *$2;
311                 delete $2;
312
313                 context->HandleInclude(aexpr->Evaluate(m_ModuleScope), false, DebugInfoRange(@1, @2));
314         }
315         | T_INCLUDE T_STRING_ANGLE
316         {
317                 context->HandleInclude($2, true, DebugInfoRange(@1, @2));
318                 free($2);
319         }
320         ;
321
322 include_recursive: T_INCLUDE_RECURSIVE rterm
323         {
324                 AExpression::Ptr aexpr = *$2;
325                 delete $2;
326
327                 context->HandleIncludeRecursive(aexpr->Evaluate(m_ModuleScope), "*.conf", DebugInfoRange(@1, @2));
328         }
329         | T_INCLUDE_RECURSIVE rterm ',' rterm
330         {
331                 AExpression::Ptr aexpr1 = *$2;
332                 delete $2;
333
334                 AExpression::Ptr aexpr2 = *$4;
335                 delete $4;
336
337                 context->HandleIncludeRecursive(aexpr1->Evaluate(m_ModuleScope), aexpr2->Evaluate(m_ModuleScope), DebugInfoRange(@1, @4));
338         }
339         ;
340
341 library: T_LIBRARY T_STRING sep
342         {
343                 context->HandleLibrary($2);
344                 free($2);
345         }
346         ;
347
348 constant: T_CONST identifier T_SET rterm sep
349         {
350                 AExpression::Ptr aexpr = *$4;
351                 delete $4;
352
353                 ScriptVariable::Ptr sv = ScriptVariable::Set($2, aexpr->Evaluate(m_ModuleScope));
354                 sv->SetConstant(true);
355
356                 free($2);
357         }
358         ;
359
360 identifier: T_IDENTIFIER
361         | T_STRING
362         {
363                 $$ = $1;
364         }
365         ;
366
367 type: partial_specifier T_TYPE identifier
368         {
369                 String name = String($3);
370                 free($3);
371
372                 m_Type = ConfigType::GetByName(name);
373
374                 if (!m_Type) {
375                         if ($1)
376                                 BOOST_THROW_EXCEPTION(ConfigError("Partial type definition for unknown type '" + name + "'") << errinfo_debuginfo(DebugInfoRange(@1, @3)));
377
378                         m_Type = make_shared<ConfigType>(name, DebugInfoRange(@1, @3));
379                         m_Type->Register();
380                 }
381         }
382         type_inherits_specifier typerulelist sep
383         {
384                 TypeRuleList::Ptr ruleList = *$6;
385                 m_Type->GetRuleList()->AddRules(ruleList);
386                 m_Type->GetRuleList()->AddRequires(ruleList);
387
388                 String validator = ruleList->GetValidator();
389                 if (!validator.IsEmpty())
390                         m_Type->GetRuleList()->SetValidator(validator);
391
392                 delete $6;
393         }
394         ;
395
396 partial_specifier: /* Empty */
397         {
398                 $$ = 0;
399         }
400         | T_PARTIAL
401         {
402                 $$ = 1;
403         }
404         ;
405
406 typerulelist: '{'
407         {
408                 m_RuleLists.push(make_shared<TypeRuleList>());
409         }
410         typerules
411         '}'
412         {
413                 $$ = new Value(m_RuleLists.top());
414                 m_RuleLists.pop();
415         }
416         ;
417
418 typerules: typerules_inner
419         | typerules_inner sep
420
421 typerules_inner: /* empty */
422         | typerule
423         | typerules_inner sep typerule
424         ;
425
426 typerule: T_REQUIRE T_STRING
427         {
428                 m_RuleLists.top()->AddRequire($2);
429                 free($2);
430         }
431         | T_VALIDATOR T_STRING
432         {
433                 m_RuleLists.top()->SetValidator($2);
434                 free($2);
435         }
436         | T_ATTRIBUTE type T_STRING
437         {
438                 TypeRule rule($2, String(), $3, TypeRuleList::Ptr(), DebugInfoRange(@1, @3));
439                 free($3);
440
441                 m_RuleLists.top()->AddRule(rule);
442         }
443         | T_ATTRIBUTE T_TYPE_NAME '(' identifier ')' T_STRING
444         {
445                 TypeRule rule($2, $4, $6, TypeRuleList::Ptr(), DebugInfoRange(@1, @6));
446                 free($4);
447                 free($6);
448
449                 m_RuleLists.top()->AddRule(rule);
450         }
451         | T_ATTRIBUTE type T_STRING typerulelist
452         {
453                 TypeRule rule($2, String(), $3, *$4, DebugInfoRange(@1, @4));
454                 free($3);
455                 delete $4;
456                 m_RuleLists.top()->AddRule(rule);
457         }
458         ;
459
460 type_inherits_specifier: /* empty */
461         | T_INHERITS identifier
462         {
463                 m_Type->SetParent($2);
464                 free($2);
465         }
466         ;
467
468 type: T_TYPE_DICTIONARY
469         | T_TYPE_ARRAY
470         | T_TYPE_NUMBER
471         | T_TYPE_STRING
472         | T_TYPE_SCALAR
473         | T_TYPE_ANY
474         | T_TYPE_NAME
475         {
476                 $$ = $1;
477         }
478         ;
479
480 object:
481         {
482                 m_Abstract = false;
483                 m_ObjectAssign = true;
484                 m_SeenAssign = false;
485                 m_Assign = make_shared<AExpression>(&AExpression::OpLiteral, false, DebugInfo());
486                 m_Ignore = make_shared<AExpression>(&AExpression::OpLiteral, false, DebugInfo());
487         }
488         object_declaration identifier rterm rterm_scope
489         {
490                 m_ObjectAssign = false;
491
492                 Array::Ptr args = make_shared<Array>();
493                 
494                 args->Add(m_Abstract);
495
496                 String type = $3;
497                 args->Add(type);
498                 free($3);
499
500                 args->Add(*$4);
501                 delete $4;
502
503                 AExpression::Ptr exprl = *$5;
504                 delete $5;
505                 exprl->MakeInline();
506
507                 if (m_SeenAssign && !ObjectRule::IsValidSourceType(type))
508                         BOOST_THROW_EXCEPTION(ConfigError("object rule 'assign' cannot be used for type '" + type + "'") << errinfo_debuginfo(DebugInfoRange(@2, @3)));
509
510                 AExpression::Ptr rex = make_shared<AExpression>(&AExpression::OpLogicalNegate, m_Ignore, DebugInfoRange(@2, @5));
511                 AExpression::Ptr filter = make_shared<AExpression>(&AExpression::OpLogicalAnd, m_Assign, rex, DebugInfoRange(@2, @5));
512
513                 args->Add(filter);
514
515                 args->Add(context->GetZone());
516
517                 $$ = new Value(make_shared<AExpression>(&AExpression::OpObject, args, exprl, DebugInfoRange(@2, @5)));
518
519                 m_Assign.reset();
520                 m_Ignore.reset();
521         }
522         ;
523
524 object_declaration: T_OBJECT
525         | T_TEMPLATE
526         {
527                 m_Abstract = true;
528         }
529
530 identifier_items: identifier_items_inner
531         {
532                 $$ = $1;
533         }
534         | identifier_items_inner ','
535         {
536                 $$ = $1;
537         }
538         ;
539
540 identifier_items_inner: /* empty */
541         {
542                 $$ = new Array();
543         }
544         | identifier
545         {
546                 $$ = new Array();
547                 $$->Add($1);
548                 free($1);
549         }
550         | identifier_items_inner ',' identifier
551         {
552                 if ($1)
553                         $$ = $1;
554                 else
555                         $$ = new Array();
556
557                 $$->Add($3);
558                 free($3);
559         }
560         ;
561
562 lbinary_op: T_SET
563         | T_SET_PLUS
564         | T_SET_MINUS
565         | T_SET_MULTIPLY
566         | T_SET_DIVIDE
567         {
568                 $$ = $1;
569         }
570         ;
571
572 lterm_items: /* empty */
573         {
574                 $$ = new Array();
575         }
576         | lterm_items_inner
577         {
578                 $$ = $1;
579         }
580         | lterm_items_inner sep
581         {
582                 $$ = $1;
583         }
584
585 lterm_items_inner: lterm
586         {
587                 $$ = new Array();
588                 $$->Add(*$1);
589                 delete $1;
590         }
591         | lterm_items_inner sep lterm
592         {
593                 if ($1)
594                         $$ = $1;
595                 else
596                         $$ = new Array();
597
598                 $$->Add(*$3);
599                 delete $3;
600         }
601         ;
602
603 lterm: identifier lbinary_op rterm
604         {
605                 AExpression::Ptr aindex = make_shared<AExpression>(&AExpression::OpLiteral, $1, @1);
606                 free($1);
607
608                 $$ = new Value(make_shared<AExpression>($2, aindex, *$3, DebugInfoRange(@1, @3)));
609                 delete $3;
610         }
611         | identifier '[' rterm ']' lbinary_op rterm
612         {
613                 AExpression::Ptr subexpr = make_shared<AExpression>($5, *$3, *$6, DebugInfoRange(@1, @6));
614                 delete $3;
615                 delete $6;
616
617                 Array::Ptr subexprl = make_shared<Array>();
618                 subexprl->Add(subexpr);
619                 
620                 AExpression::Ptr aindex = make_shared<AExpression>(&AExpression::OpLiteral, $1, @1);
621                 free($1);
622
623                 AExpression::Ptr expr = make_shared<AExpression>(&AExpression::OpDict, subexprl, DebugInfoRange(@1, @6));
624                 $$ = new Value(make_shared<AExpression>(&AExpression::OpSetPlus, aindex, expr, DebugInfoRange(@1, @6)));
625         }
626         | identifier '.' T_IDENTIFIER lbinary_op rterm
627         {
628                 AExpression::Ptr aindex = make_shared<AExpression>(&AExpression::OpLiteral, $3, @3);
629                 AExpression::Ptr subexpr = make_shared<AExpression>($4, aindex, *$5, DebugInfoRange(@1, @5));
630                 free($3);
631                 delete $5;
632
633                 Array::Ptr subexprl = make_shared<Array>();
634                 subexprl->Add(subexpr);
635
636                 AExpression::Ptr aindexl = make_shared<AExpression>(&AExpression::OpLiteral, $1, @1);
637                 free($1);
638
639                 AExpression::Ptr expr = make_shared<AExpression>(&AExpression::OpDict, subexprl, DebugInfoRange(@1, @5));
640                 $$ = new Value(make_shared<AExpression>(&AExpression::OpSetPlus, aindexl, expr, DebugInfoRange(@1, @5)));
641         }
642         | T_IMPORT rterm
643         {
644                 AExpression::Ptr avar = make_shared<AExpression>(&AExpression::OpVariable, "type", DebugInfoRange(@1, @2));
645                 $$ = new Value(make_shared<AExpression>(&AExpression::OpImport, avar, *$2, DebugInfoRange(@1, @2)));
646                 delete $2;
647         }
648         | T_ASSIGN T_WHERE rterm
649         {
650                 if (!(m_Apply || m_ObjectAssign))
651                         BOOST_THROW_EXCEPTION(ConfigError("'assign' keyword not valid in this context."));
652
653                 m_SeenAssign = true;
654
655                 m_Assign = make_shared<AExpression>(&AExpression::OpLogicalOr, m_Assign, *$3, DebugInfoRange(@1, @3));
656                 delete $3;
657
658                 $$ = new Value(make_shared<AExpression>(&AExpression::OpLiteral, Empty, DebugInfoRange(@1, @3)));
659         }
660         | T_IGNORE T_WHERE rterm
661         {
662                 if (!(m_Apply || m_ObjectAssign))
663                         BOOST_THROW_EXCEPTION(ConfigError("'ignore' keyword not valid in this context."));
664
665                 m_Ignore = make_shared<AExpression>(&AExpression::OpLogicalOr, m_Ignore, *$3, DebugInfoRange(@1, @3));
666
667                 delete $3;
668
669                 $$ = new Value(make_shared<AExpression>(&AExpression::OpLiteral, Empty, DebugInfoRange(@1, @3)));
670         }
671         | T_RETURN rterm
672         {
673                 AExpression::Ptr aname = make_shared<AExpression>(&AExpression::OpLiteral, "__result", @1);
674                 $$ = new Value(make_shared<AExpression>(&AExpression::OpSet, aname, *$2, DebugInfoRange(@1, @2)));
675                 delete $2;
676
677         }
678         | apply
679         {
680                 $$ = $1;
681         }
682         | object
683         {
684                 $$ = $1;
685         }
686         | rterm
687         {
688                 $$ = $1;
689         }
690         ;
691         
692 rterm_items: /* empty */
693         {
694                 $$ = new Array();
695         }
696         | rterm_items_inner
697         {
698                 $$ = $1;
699         }
700         | rterm_items_inner arraysep
701         {
702                 $$ = $1;
703         }
704         ;
705
706 rterm_items_inner: rterm
707         {
708                 $$ = new Array();
709                 $$->Add(*$1);
710                 delete $1;
711         }
712         | rterm_items_inner arraysep rterm
713         {
714                 $$ = $1;
715                 $$->Add(*$3);
716                 delete $3;
717         }
718         ;
719
720 rterm_array: '[' newlines rterm_items newlines ']'
721         {
722                 $$ = new Value(make_shared<AExpression>(&AExpression::OpArray, Array::Ptr($3), DebugInfoRange(@1, @5)));
723         }
724         | '[' newlines rterm_items ']'
725         {
726                 $$ = new Value(make_shared<AExpression>(&AExpression::OpArray, Array::Ptr($3), DebugInfoRange(@1, @4)));
727         }
728         | '[' rterm_items newlines ']'
729         {
730                 $$ = new Value(make_shared<AExpression>(&AExpression::OpArray, Array::Ptr($2), DebugInfoRange(@1, @4)));
731         }
732         | '[' rterm_items ']'
733         {
734                 $$ = new Value(make_shared<AExpression>(&AExpression::OpArray, Array::Ptr($2), DebugInfoRange(@1, @3)));
735         }
736         ;
737
738 rterm_scope: '{' newlines lterm_items newlines '}'
739         {
740                 $$ = new Value(make_shared<AExpression>(&AExpression::OpDict, Array::Ptr($3), DebugInfoRange(@1, @5)));
741         }
742         | '{' newlines lterm_items '}'
743         {
744                 $$ = new Value(make_shared<AExpression>(&AExpression::OpDict, Array::Ptr($3), DebugInfoRange(@1, @4)));
745         }
746         | '{' lterm_items newlines '}'
747         {
748                 $$ = new Value(make_shared<AExpression>(&AExpression::OpDict, Array::Ptr($2), DebugInfoRange(@1, @4)));
749         }
750         | '{' lterm_items '}'
751         {
752                 $$ = new Value(make_shared<AExpression>(&AExpression::OpDict, Array::Ptr($2), DebugInfoRange(@1, @3)));
753         }
754         ;
755
756 rterm: T_STRING
757         {
758                 $$ = new Value(make_shared<AExpression>(&AExpression::OpLiteral, $1, @1));
759                 free($1);
760         }
761         | T_NUMBER
762         {
763                 $$ = new Value(make_shared<AExpression>(&AExpression::OpLiteral, $1, @1));
764         }
765         | T_NULL
766         {
767                 $$ = new Value(make_shared<AExpression>(&AExpression::OpLiteral, Empty, @1));
768         }
769         | rterm '.' T_IDENTIFIER
770         {
771                 $$ = new Value(make_shared<AExpression>(&AExpression::OpIndexer, *$1, make_shared<AExpression>(&AExpression::OpLiteral, $3, @3), DebugInfoRange(@1, @3)));
772                 delete $1;
773                 free($3);
774         }
775         | rterm '(' rterm_items ')'
776         {
777                 Array::Ptr arguments = Array::Ptr($3);
778                 $$ = new Value(make_shared<AExpression>(&AExpression::OpFunctionCall, *$1, make_shared<AExpression>(&AExpression::OpLiteral, arguments, @3), DebugInfoRange(@1, @4)));
779                 delete $1;
780         }
781         | T_IDENTIFIER
782         {
783                 $$ = new Value(make_shared<AExpression>(&AExpression::OpVariable, $1, @1));
784                 free($1);
785         }
786         | '!' rterm
787         {
788                 $$ = new Value(make_shared<AExpression>(&AExpression::OpLogicalNegate, *$2, DebugInfoRange(@1, @2)));
789                 delete $2;
790         }
791         | '~' rterm
792         {
793                 $$ = new Value(make_shared<AExpression>(&AExpression::OpNegate, *$2, DebugInfoRange(@1, @2)));
794                 delete $2;
795         }
796         | rterm '[' rterm ']'
797         {
798                 $$ = new Value(make_shared<AExpression>(&AExpression::OpIndexer, *$1, *$3, DebugInfoRange(@1, @4)));
799                 delete $1;
800                 delete $3;
801         }
802         | rterm_array
803         {
804                 $$ = $1;
805         }
806         | rterm_scope
807         {
808                 $$ = $1;
809         }
810         | '('
811         {
812                 ignore_newlines++;
813         }
814         rterm ')'
815         {
816                 ignore_newlines--;
817                 $$ = $3;
818         }
819         | rterm T_LOGICAL_OR rterm { MakeRBinaryOp(&$$, $2, $1, $3, @1, @3); }
820         | rterm T_LOGICAL_AND rterm { MakeRBinaryOp(&$$, $2, $1, $3, @1, @3); }
821         | rterm T_BINARY_OR rterm { MakeRBinaryOp(&$$, $2, $1, $3, @1, @3); }
822         | rterm T_BINARY_AND rterm { MakeRBinaryOp(&$$, $2, $1, $3, @1, @3); }
823         | rterm T_IN rterm { MakeRBinaryOp(&$$, $2, $1, $3, @1, @3); }
824         | rterm T_NOT_IN rterm { MakeRBinaryOp(&$$, $2, $1, $3, @1, @3); }
825         | rterm T_EQUAL rterm { MakeRBinaryOp(&$$, $2, $1, $3, @1, @3); }
826         | rterm T_NOT_EQUAL rterm { MakeRBinaryOp(&$$, $2, $1, $3, @1, @3); }
827         | rterm T_LESS_THAN rterm { MakeRBinaryOp(&$$, $2, $1, $3, @1, @3); }
828         | rterm T_LESS_THAN_OR_EQUAL rterm { MakeRBinaryOp(&$$, $2, $1, $3, @1, @3); }
829         | rterm T_GREATER_THAN rterm { MakeRBinaryOp(&$$, $2, $1, $3, @1, @3); }
830         | rterm T_GREATER_THAN_OR_EQUAL rterm { MakeRBinaryOp(&$$, $2, $1, $3, @1, @3); }
831         | rterm T_SHIFT_LEFT rterm { MakeRBinaryOp(&$$, $2, $1, $3, @1, @3); }
832         | rterm T_SHIFT_RIGHT rterm { MakeRBinaryOp(&$$, $2, $1, $3, @1, @3); }
833         | rterm T_PLUS rterm { MakeRBinaryOp(&$$, $2, $1, $3, @1, @3); }
834         | rterm T_MINUS rterm { MakeRBinaryOp(&$$, $2, $1, $3, @1, @3); }
835         | rterm T_MULTIPLY rterm { MakeRBinaryOp(&$$, $2, $1, $3, @1, @3); }
836         | rterm T_DIVIDE_OP rterm { MakeRBinaryOp(&$$, $2, $1, $3, @1, @3); }
837         | T_FUNCTION identifier '(' identifier_items ')' rterm_scope
838         {
839                 Array::Ptr arr = make_shared<Array>();
840
841                 arr->Add($2);
842                 free($2);
843
844                 AExpression::Ptr aexpr = *$6;
845                 delete $6;
846                 aexpr->MakeInline();
847                 arr->Add(aexpr);
848
849                 $$ = new Value(make_shared<AExpression>(&AExpression::OpFunction, arr, Array::Ptr($4), DebugInfoRange(@1, @6)));
850         }
851         | T_FUNCTION '(' identifier_items ')' rterm_scope
852         {
853                 Array::Ptr arr = make_shared<Array>();
854
855                 arr->Add(Empty);
856
857                 AExpression::Ptr aexpr = *$5;
858                 delete $5;
859                 aexpr->MakeInline();
860                 arr->Add(aexpr);
861
862                 $$ = new Value(make_shared<AExpression>(&AExpression::OpFunction, arr, Array::Ptr($3), DebugInfoRange(@1, @5)));
863         }
864         | T_FOR '(' identifier T_IN rterm ')' rterm_scope
865         {
866                 Array::Ptr arr = make_shared<Array>();
867
868                 arr->Add($3);
869                 free($3);
870
871                 AExpression::Ptr aexpr = *$5;
872                 delete $5;
873                 arr->Add(aexpr);
874
875                 AExpression::Ptr ascope = *$7;
876                 delete $7;
877
878                 $$ = new Value(make_shared<AExpression>(&AExpression::OpFor, arr, ascope, DebugInfoRange(@1, @7)));
879         }
880         ;
881
882 target_type_specifier: /* empty */
883         {
884                 $$ = strdup("");
885         }
886         | T_TO identifier
887         {
888                 $$ = $2;
889         }
890         ;
891
892 apply:
893         {
894                 m_Apply = true;
895                 m_SeenAssign = false;
896                 m_Assign = make_shared<AExpression>(&AExpression::OpLiteral, false, DebugInfo());
897                 m_Ignore = make_shared<AExpression>(&AExpression::OpLiteral, false, DebugInfo());
898         }
899         T_APPLY identifier rterm target_type_specifier rterm
900         {
901                 m_Apply = false;
902
903                 String type = $3;
904                 free($3);
905                 AExpression::Ptr aname = *$4;
906                 delete $4;
907                 String target = $5;
908                 free($5);
909
910                 if (!ApplyRule::IsValidSourceType(type))
911                         BOOST_THROW_EXCEPTION(ConfigError("'apply' cannot be used with type '" + type + "'") << errinfo_debuginfo(DebugInfoRange(@2, @3)));
912
913                 if (!ApplyRule::IsValidTargetType(type, target)) {
914                         if (target == "") {
915                                 std::vector<String> types = ApplyRule::GetTargetTypes(type);
916                                 String typeNames;
917
918                                 for (std::vector<String>::size_type i = 0; i < types.size(); i++) {
919                                         if (typeNames != "") {
920                                                 if (i == types.size() - 1)
921                                                         typeNames += " or ";
922                                                 else
923                                                         typeNames += ", ";
924                                         }
925
926                                         typeNames += "'" + types[i] + "'";
927                                 }
928
929                                 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)));
930                         } else
931                                 BOOST_THROW_EXCEPTION(ConfigError("'apply' target type '" + target + "' is invalid") << errinfo_debuginfo(DebugInfoRange(@2, @5)));
932                 }
933
934                 AExpression::Ptr exprl = *$6;
935                 delete $6;
936
937                 exprl->MakeInline();
938
939                 // assign && !ignore
940                 if (!m_SeenAssign)
941                         BOOST_THROW_EXCEPTION(ConfigError("'apply' is missing 'assign'") << errinfo_debuginfo(DebugInfoRange(@2, @3)));
942
943                 AExpression::Ptr rex = make_shared<AExpression>(&AExpression::OpLogicalNegate, m_Ignore, DebugInfoRange(@2, @5));
944                 AExpression::Ptr filter = make_shared<AExpression>(&AExpression::OpLogicalAnd, m_Assign, rex, DebugInfoRange(@2, @5));
945
946                 Array::Ptr args = make_shared<Array>();
947                 args->Add(type);
948                 args->Add(target);
949                 args->Add(aname);
950                 args->Add(filter);
951
952                 $$ = new Value(make_shared<AExpression>(&AExpression::OpApply, args, exprl, DebugInfoRange(@2, @5)));
953
954                 m_Assign.reset();
955                 m_Ignore.reset();
956         }
957         ;
958
959 newlines: T_NEWLINE
960         | newlines T_NEWLINE
961         ;
962
963 /* required separator */
964 sep: ',' newlines
965         | ','
966         | ';' newlines
967         | ';'
968         | newlines
969         ;
970
971 arraysep: ',' newlines
972         | ','
973         ;
974
975 %%