1%{
2#define YYDEBUG 1
3
4/* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */
5
6#include "config/i2-config.hpp"
7#include "config/configcompiler.hpp"
8#include "config/expression.hpp"
9#include "config/applyrule.hpp"
10#include "config/objectrule.hpp"
11#include "base/value.hpp"
12#include "base/utility.hpp"
13#include "base/exception.hpp"
14#include "base/configtype.hpp"
15#include "base/exception.hpp"
16#include <sstream>
17#include <stack>
18
19#define YYLTYPE icinga::CompilerDebugInfo
20#define YYERROR_VERBOSE
21
22#define YYLLOC_DEFAULT(Current, Rhs, N)					\
23do {									\
24	if (N) {							\
25		(Current).Path = YYRHSLOC(Rhs, 1).Path;			\
26		(Current).FirstLine = YYRHSLOC(Rhs, 1).FirstLine;	\
27		(Current).FirstColumn = YYRHSLOC(Rhs, 1).FirstColumn;	\
28		(Current).LastLine = YYRHSLOC(Rhs, N).LastLine;		\
29		(Current).LastColumn = YYRHSLOC(Rhs, N).LastColumn;	\
30	} else {							\
31		(Current).Path = YYRHSLOC(Rhs, 0).Path;			\
32		(Current).FirstLine = (Current).LastLine =		\
33		YYRHSLOC(Rhs, 0).LastLine;				\
34		(Current).FirstColumn = (Current).LastColumn =		\
35		YYRHSLOC(Rhs, 0).LastColumn;				\
36	}								\
37} while (0)
38
39#define YY_LOCATION_PRINT(file, loc)			\
40do {							\
41	std::ostringstream msgbuf;			\
42	msgbuf << loc;					\
43	std::string str = msgbuf.str();			\
44	fputs(str.c_str(), file);			\
45} while (0)
46
47#define YYINITDEPTH 10000
48
49using namespace icinga;
50
51template<typename T>
52static void MakeRBinaryOp(Expression** result, Expression *left, Expression *right, const DebugInfo& diLeft, const DebugInfo& diRight)
53{
54	*result = new T(std::unique_ptr<Expression>(left), std::unique_ptr<Expression>(right), DebugInfoRange(diLeft, diRight));
55}
56
57%}
58
59%pure-parser
60
61%locations
62%defines
63%error-verbose
64%glr-parser
65
66%parse-param { std::vector<std::pair<std::unique_ptr<Expression>, EItemInfo> > *llist }
67%parse-param { ConfigCompiler *context }
68%lex-param { void *scanner }
69
70%union {
71	String *text;
72	double num;
73	bool boolean;
74	icinga::Expression *expr;
75	icinga::DictExpression *dexpr;
76	CombinedSetOp csop;
77	std::vector<String> *slist;
78	std::vector<std::pair<std::unique_ptr<Expression>, EItemInfo> > *llist;
79	std::vector<std::unique_ptr<Expression> > *elist;
80	std::vector<std::pair<std::unique_ptr<Expression>, std::unique_ptr<Expression> > > *ebranchlist;
81	std::pair<std::unique_ptr<Expression>, std::unique_ptr<Expression> > *ebranch;
82	std::pair<String, std::unique_ptr<Expression> > *cvitem;
83	std::map<String, std::unique_ptr<Expression> > *cvlist;
84	icinga::ScopeSpecifier scope;
85}
86
87%token T_NEWLINE "new-line"
88%token <text> T_STRING
89%token <text> T_STRING_ANGLE
90%token <num> T_NUMBER
91%token <boolean> T_BOOLEAN
92%token T_NULL
93%token <text> T_IDENTIFIER
94
95%token <csop> T_SET "= (T_SET)"
96%token <csop> T_SET_ADD "+= (T_SET_ADD)"
97%token <csop> T_SET_SUBTRACT "-= (T_SET_SUBTRACT)"
98%token <csop> T_SET_MULTIPLY "*= (T_SET_MULTIPLY)"
99%token <csop> T_SET_DIVIDE "/= (T_SET_DIVIDE)"
100%token <csop> T_SET_MODULO "%= (T_SET_MODULO)"
101%token <csop> T_SET_XOR "^= (T_SET_XOR)"
102%token <csop> T_SET_BINARY_AND "&= (T_SET_BINARY_AND)"
103%token <csop> T_SET_BINARY_OR "|= (T_SET_BINARY_OR)"
104
105%token T_SHIFT_LEFT "<< (T_SHIFT_LEFT)"
106%token T_SHIFT_RIGHT ">> (T_SHIFT_RIGHT)"
107%token T_EQUAL "== (T_EQUAL)"
108%token T_NOT_EQUAL "!= (T_NOT_EQUAL)"
109%token T_IN "in (T_IN)"
110%token T_NOT_IN "!in (T_NOT_IN)"
111%token T_LOGICAL_AND "&& (T_LOGICAL_AND)"
112%token T_LOGICAL_OR "|| (T_LOGICAL_OR)"
113%token T_LESS_THAN_OR_EQUAL "<= (T_LESS_THAN_OR_EQUAL)"
114%token T_GREATER_THAN_OR_EQUAL ">= (T_GREATER_THAN_OR_EQUAL)"
115%token T_PLUS "+ (T_PLUS)"
116%token T_MINUS "- (T_MINUS)"
117%token T_MULTIPLY "* (T_MULTIPLY)"
118%token T_DIVIDE_OP "/ (T_DIVIDE_OP)"
119%token T_MODULO "% (T_MODULO)"
120%token T_XOR "^ (T_XOR)"
121%token T_BINARY_AND "& (T_BINARY_AND)"
122%token T_BINARY_OR "| (T_BINARY_OR)"
123%token T_LESS_THAN "< (T_LESS_THAN)"
124%token T_GREATER_THAN "> (T_GREATER_THAN)"
125
126%token T_VAR "var (T_VAR)"
127%token T_GLOBALS "globals (T_GLOBALS)"
128%token T_LOCALS "locals (T_LOCALS)"
129%token T_CONST "const (T_CONST)"
130%token T_DEFAULT "default (T_DEFAULT)"
131%token T_IGNORE_ON_ERROR "ignore_on_error (T_IGNORE_ON_ERROR)"
132%token T_CURRENT_FILENAME "current_filename (T_CURRENT_FILENAME)"
133%token T_CURRENT_LINE "current_line (T_CURRENT_LINE)"
134%token T_DEBUGGER "debugger (T_DEBUGGER)"
135%token T_NAMESPACE "namespace (T_NAMESPACE)"
136%token T_USE "use (T_USE)"
137%token T_USING "using (T_USING)"
138%token T_OBJECT "object (T_OBJECT)"
139%token T_TEMPLATE "template (T_TEMPLATE)"
140%token T_INCLUDE "include (T_INCLUDE)"
141%token T_INCLUDE_RECURSIVE "include_recursive (T_INCLUDE_RECURSIVE)"
142%token T_INCLUDE_ZONES "include_zones (T_INCLUDE_ZONES)"
143%token T_LIBRARY "library (T_LIBRARY)"
144%token T_APPLY "apply (T_APPLY)"
145%token T_TO "to (T_TO)"
146%token T_WHERE "where (T_WHERE)"
147%token T_IMPORT "import (T_IMPORT)"
148%token T_ASSIGN "assign (T_ASSIGN)"
149%token T_IGNORE "ignore (T_IGNORE)"
150%token T_FUNCTION "function (T_FUNCTION)"
151%token T_RETURN "return (T_RETURN)"
152%token T_BREAK "break (T_BREAK)"
153%token T_CONTINUE "continue (T_CONTINUE)"
154%token T_FOR "for (T_FOR)"
155%token T_IF "if (T_IF)"
156%token T_ELSE "else (T_ELSE)"
157%token T_WHILE "while (T_WHILE)"
158%token T_THROW "throw (T_THROW)"
159%token T_TRY "try (T_TRY)"
160%token T_EXCEPT "except (T_EXCEPT)"
161%token T_FOLLOWS "=> (T_FOLLOWS)"
162%token T_NULLARY_LAMBDA_BEGIN "{{ (T_NULLARY_LAMBDA_BEGIN)"
163%token T_NULLARY_LAMBDA_END "}} (T_NULLARY_LAMBDA_END)"
164
165%type <text> identifier
166%type <elist> rterm_items
167%type <elist> rterm_items_inner
168%type <slist> identifier_items
169%type <slist> identifier_items_inner
170%type <csop> combined_set_op
171%type <llist> statements
172%type <llist> lterm_items
173%type <llist> lterm_items_inner
174%type <expr> rterm
175%type <expr> rterm_array
176%type <dexpr> rterm_dict
177%type <dexpr> rterm_scope_require_side_effect
178%type <dexpr> rterm_scope
179%type <ebranchlist> else_if_branches
180%type <ebranch> else_if_branch
181%type <expr> rterm_side_effect
182%type <expr> rterm_no_side_effect
183%type <expr> rterm_no_side_effect_no_dict
184%type <expr> lterm
185%type <expr> object
186%type <expr> apply
187%type <expr> optional_rterm
188%type <text> target_type_specifier
189%type <boolean> default_specifier
190%type <boolean> ignore_specifier
191%type <cvlist> use_specifier
192%type <cvlist> use_specifier_items
193%type <cvitem> use_specifier_item
194%type <num> object_declaration
195
196%right T_FOLLOWS
197%right T_INCLUDE T_INCLUDE_RECURSIVE T_INCLUDE_ZONES T_OBJECT T_TEMPLATE T_APPLY T_IMPORT T_ASSIGN T_IGNORE T_WHERE
198%right T_FUNCTION T_FOR
199%left T_SET T_SET_ADD T_SET_SUBTRACT T_SET_MULTIPLY T_SET_DIVIDE T_SET_MODULO T_SET_XOR T_SET_BINARY_AND T_SET_BINARY_OR
200%right '?' ':'
201%left T_LOGICAL_OR
202%left T_LOGICAL_AND
203%left T_RETURN T_BREAK T_CONTINUE
204%left T_IDENTIFIER
205%left T_BINARY_OR
206%left T_XOR
207%left T_BINARY_AND
208%nonassoc T_EQUAL T_NOT_EQUAL
209%left T_IN T_NOT_IN
210%nonassoc T_LESS_THAN T_LESS_THAN_OR_EQUAL T_GREATER_THAN T_GREATER_THAN_OR_EQUAL
211%left T_SHIFT_LEFT T_SHIFT_RIGHT
212%left T_PLUS T_MINUS
213%left T_MULTIPLY T_DIVIDE_OP T_MODULO
214%left UNARY_MINUS UNARY_PLUS
215%right REF_OP DEREF_OP
216%right '!' '~'
217%left '.' '(' '['
218%left T_VAR T_THIS T_GLOBALS T_LOCALS
219%right ';' ','
220%right T_NEWLINE
221%{
222
223int yylex(YYSTYPE *lvalp, YYLTYPE *llocp, void *scanner);
224
225extern int yydebug;
226
227void yyerror(const YYLTYPE *locp, std::vector<std::pair<std::unique_ptr<Expression>, EItemInfo> > *, ConfigCompiler *context, const char *err)
228{
229	bool incomplete = context && context->m_Eof && (context->m_OpenBraces > 0);
230	BOOST_THROW_EXCEPTION(ScriptError(err, *locp, incomplete));
231}
232
233int yyparse(std::vector<std::pair<std::unique_ptr<Expression>, EItemInfo> > *llist, ConfigCompiler *context);
234
235static void BeginFlowControlBlock(ConfigCompiler *compiler, int allowedTypes, bool inherit)
236{
237	if (inherit)
238		allowedTypes |= compiler->m_FlowControlInfo.top();
239
240	compiler->m_FlowControlInfo.push(allowedTypes);
241}
242
243static void EndFlowControlBlock(ConfigCompiler *compiler)
244{
245	compiler->m_FlowControlInfo.pop();
246}
247
248static void UseFlowControl(ConfigCompiler *compiler, FlowControlType type, const CompilerDebugInfo& location)
249{
250	int fci = compiler->m_FlowControlInfo.top();
251
252	if ((type & fci) != type)
253		BOOST_THROW_EXCEPTION(ScriptError("Invalid flow control statement.", location));
254}
255
256std::unique_ptr<Expression> ConfigCompiler::Compile()
257{
258	std::vector<std::pair<std::unique_ptr<Expression>, EItemInfo> > llist;
259
260	//yydebug = 1;
261
262	m_IgnoreNewlines.push(false);
263	BeginFlowControlBlock(this, 0, false);
264
265	if (yyparse(&llist, this) != 0)
266		return NULL;
267
268	EndFlowControlBlock(this);
269	m_IgnoreNewlines.pop();
270
271	std::vector<std::unique_ptr<Expression> > dlist;
272	decltype(llist.size()) num = 0;
273	for (auto& litem : llist) {
274		if (!litem.second.SideEffect && num != llist.size() - 1) {
275			yyerror(&litem.second.DebugInfo, NULL, NULL, "Value computed is not used.");
276		}
277		dlist.emplace_back(std::move(litem.first));
278		num++;
279	}
280
281	std::unique_ptr<DictExpression> expr{new DictExpression(std::move(dlist))};
282	expr->MakeInline();
283	return std::move(expr);
284}
285
286#define scanner (context->GetScanner())
287
288%}
289
290%%
291script: statements
292	{
293		llist->swap(*$1);
294		delete $1;
295	}
296	;
297
298statements: optional_newlines lterm_items
299	{
300		$$ = $2;
301	}
302	;
303
304lterm_items: /* empty */
305	{
306		$$ = new std::vector<std::pair<std::unique_ptr<Expression>, EItemInfo> >();
307	}
308	| lterm_items_inner
309	| lterm_items_inner sep
310	;
311
312lterm_items_inner: lterm %dprec 2
313	{
314		$$ = new std::vector<std::pair<std::unique_ptr<Expression>, EItemInfo> >();
315		$$->emplace_back(std::unique_ptr<Expression>($1), EItemInfo{true, @1});
316	}
317	| rterm_no_side_effect
318	{
319		$$ = new std::vector<std::pair<std::unique_ptr<Expression>, EItemInfo> >();
320		$$->emplace_back(std::unique_ptr<Expression>($1), EItemInfo{false, @1});
321	}
322	| lterm_items_inner sep lterm %dprec 1
323	{
324		if ($1)
325			$$ = $1;
326		else
327			$$ = new std::vector<std::pair<std::unique_ptr<Expression>, EItemInfo> >();
328
329		if ($3) {
330			$$->emplace_back(std::unique_ptr<Expression>($3), EItemInfo{true, @3});
331		}
332	}
333	| lterm_items_inner sep rterm_no_side_effect %dprec 1
334	{
335		if ($1)
336			$$ = $1;
337		else
338			$$ = new std::vector<std::pair<std::unique_ptr<Expression>, EItemInfo> >();
339
340		if ($3) {
341			$$->emplace_back(std::unique_ptr<Expression>($3), EItemInfo{false, @3});
342		}
343	}
344	;
345
346identifier: T_IDENTIFIER
347	| T_STRING
348	;
349
350object:
351	{
352		context->m_ObjectAssign.push(true);
353		context->m_SeenAssign.push(false);
354		context->m_SeenIgnore.push(false);
355		context->m_Assign.push(0);
356		context->m_Ignore.push(0);
357	}
358	object_declaration rterm optional_rterm use_specifier default_specifier ignore_specifier
359	{
360		BeginFlowControlBlock(context, FlowControlReturn, false);
361	}
362	rterm_scope_require_side_effect
363	{
364		EndFlowControlBlock(context);
365
366		context->m_ObjectAssign.pop();
367
368		bool abstract = $2;
369		bool defaultTmpl = $6;
370
371		if (!abstract && defaultTmpl)
372			BOOST_THROW_EXCEPTION(ScriptError("'default' keyword is invalid for object definitions", @6));
373
374		bool seen_assign = context->m_SeenAssign.top();
375		context->m_SeenAssign.pop();
376
377		bool seen_ignore = context->m_SeenIgnore.top();
378		context->m_SeenIgnore.pop();
379
380		std::unique_ptr<Expression> ignore{std::move(context->m_Ignore.top())};
381		context->m_Ignore.pop();
382
383		std::unique_ptr<Expression> assign{std::move(context->m_Assign.top())};
384		context->m_Assign.pop();
385
386		std::unique_ptr<Expression> filter;
387
388		if (seen_assign) {
389			if (ignore) {
390				std::unique_ptr<Expression> rex{new LogicalNegateExpression(std::move(ignore), DebugInfoRange(@2, @5))};
391
392				filter.reset(new LogicalAndExpression(std::move(assign), std::move(rex), DebugInfoRange(@2, @5)));
393			} else
394				filter.swap(assign);
395		} else if (seen_ignore) {
396			BOOST_THROW_EXCEPTION(ScriptError("object rule 'ignore where' cannot be used without 'assign where'", DebugInfoRange(@2, @4)));
397		}
398
399		$$ = new ObjectExpression(abstract, std::unique_ptr<Expression>($3), std::unique_ptr<Expression>($4),
400			std::move(filter), context->GetZone(), context->GetPackage(), std::move(*$5), $6, $7,
401			std::unique_ptr<Expression>($9), DebugInfoRange(@2, @7));
402		delete $5;
403	}
404	;
405
406object_declaration: T_OBJECT
407	{
408		$$ = false;
409	}
410	| T_TEMPLATE
411	{
412		$$ = true;
413	}
414	;
415
416identifier_items: /* empty */
417	{
418		$$ = new std::vector<String>();
419	}
420	| identifier_items_inner
421	| identifier_items_inner ','
422	;
423
424identifier_items_inner: identifier
425	{
426		$$ = new std::vector<String>();
427		$$->emplace_back(std::move(*$1));
428		delete $1;
429	}
430	| identifier_items_inner ',' identifier
431	{
432		if ($1)
433			$$ = $1;
434		else
435			$$ = new std::vector<String>();
436
437		$$->emplace_back(std::move(*$3));
438		delete $3;
439	}
440	;
441
442combined_set_op: T_SET
443	| T_SET_ADD
444	| T_SET_SUBTRACT
445	| T_SET_MULTIPLY
446	| T_SET_DIVIDE
447	| T_SET_MODULO
448	| T_SET_XOR
449	| T_SET_BINARY_AND
450	| T_SET_BINARY_OR
451	;
452
453optional_var: /* empty */
454	| T_VAR
455	;
456
457lterm: T_LIBRARY rterm
458	{
459		$$ = new LibraryExpression(std::unique_ptr<Expression>($2), @$);
460	}
461	| rterm combined_set_op rterm
462	{
463		$$ = new SetExpression(std::unique_ptr<Expression>($1), $2, std::unique_ptr<Expression>($3), @$);
464	}
465	| T_INCLUDE rterm
466	{
467		$$ = new IncludeExpression(Utility::DirName(context->GetPath()), std::unique_ptr<Expression>($2), NULL, NULL, IncludeRegular, false, context->GetZone(), context->GetPackage(), @$);
468	}
469	| T_INCLUDE T_STRING_ANGLE
470	{
471		$$ = new IncludeExpression(Utility::DirName(context->GetPath()), MakeLiteral(std::move(*$2)), NULL, NULL, IncludeRegular, true, context->GetZone(), context->GetPackage(), @$);
472		delete $2;
473	}
474	| T_INCLUDE_RECURSIVE rterm
475	{
476		$$ = new IncludeExpression(Utility::DirName(context->GetPath()), std::unique_ptr<Expression>($2), MakeLiteral("*.conf"), NULL, IncludeRecursive, false, context->GetZone(), context->GetPackage(), @$);
477	}
478	| T_INCLUDE_RECURSIVE rterm ',' rterm
479	{
480		$$ = new IncludeExpression(Utility::DirName(context->GetPath()), std::unique_ptr<Expression>($2), std::unique_ptr<Expression>($4), NULL, IncludeRecursive, false, context->GetZone(), context->GetPackage(), @$);
481	}
482	| T_INCLUDE_ZONES rterm ',' rterm
483	{
484		$$ = new IncludeExpression(Utility::DirName(context->GetPath()), std::unique_ptr<Expression>($4), MakeLiteral("*.conf"), std::unique_ptr<Expression>($2), IncludeZones, false, context->GetZone(), context->GetPackage(), @$);
485	}
486	| T_INCLUDE_ZONES rterm ',' rterm ',' rterm
487	{
488		$$ = new IncludeExpression(Utility::DirName(context->GetPath()), std::unique_ptr<Expression>($4), std::unique_ptr<Expression>($6), std::unique_ptr<Expression>($2), IncludeZones, false, context->GetZone(), context->GetPackage(), @$);
489	}
490	| T_IMPORT rterm
491	{
492		$$ = new ImportExpression(std::unique_ptr<Expression>($2), @$);
493	}
494	| T_ASSIGN T_WHERE
495	{
496		BeginFlowControlBlock(context, FlowControlReturn, false);
497	}
498	rterm_scope %dprec 2
499	{
500		EndFlowControlBlock(context);
501
502		if ((context->m_Apply.empty() || !context->m_Apply.top()) && (context->m_ObjectAssign.empty() || !context->m_ObjectAssign.top()))
503			BOOST_THROW_EXCEPTION(ScriptError("'assign' keyword not valid in this context.", @$));
504
505		context->m_SeenAssign.top() = true;
506
507		if (context->m_Assign.top())
508			context->m_Assign.top() = new LogicalOrExpression(std::unique_ptr<Expression>(context->m_Assign.top()), std::unique_ptr<Expression>($4), @$);
509		else
510			context->m_Assign.top() = $4;
511
512		$$ = MakeLiteralRaw();
513	}
514	| T_ASSIGN T_WHERE rterm %dprec 1
515	{
516		ASSERT(!dynamic_cast<DictExpression *>($3));
517
518		if ((context->m_Apply.empty() || !context->m_Apply.top()) && (context->m_ObjectAssign.empty() || !context->m_ObjectAssign.top()))
519			BOOST_THROW_EXCEPTION(ScriptError("'assign' keyword not valid in this context.", @$));
520
521		context->m_SeenAssign.top() = true;
522
523		if (context->m_Assign.top())
524			context->m_Assign.top() = new LogicalOrExpression(std::unique_ptr<Expression>(context->m_Assign.top()), std::unique_ptr<Expression>($3), @$);
525		else
526			context->m_Assign.top() = $3;
527
528		$$ = MakeLiteralRaw();
529	}
530	| T_IGNORE T_WHERE
531	{
532		BeginFlowControlBlock(context, FlowControlReturn, false);
533	}
534	rterm_scope %dprec 2
535	{
536		EndFlowControlBlock(context);
537
538		if ((context->m_Apply.empty() || !context->m_Apply.top()) && (context->m_ObjectAssign.empty() || !context->m_ObjectAssign.top()))
539			BOOST_THROW_EXCEPTION(ScriptError("'ignore' keyword not valid in this context.", @$));
540
541		context->m_SeenIgnore.top() = true;
542
543		if (context->m_Ignore.top())
544			context->m_Ignore.top() = new LogicalOrExpression(std::unique_ptr<Expression>(context->m_Ignore.top()), std::unique_ptr<Expression>($4), @$);
545		else
546			context->m_Ignore.top() = $4;
547
548		$$ = MakeLiteralRaw();
549	}
550	| T_IGNORE T_WHERE rterm %dprec 1
551	{
552		ASSERT(!dynamic_cast<DictExpression *>($3));
553
554		if ((context->m_Apply.empty() || !context->m_Apply.top()) && (context->m_ObjectAssign.empty() || !context->m_ObjectAssign.top()))
555			BOOST_THROW_EXCEPTION(ScriptError("'ignore' keyword not valid in this context.", @$));
556
557		context->m_SeenIgnore.top() = true;
558
559		if (context->m_Ignore.top())
560			context->m_Ignore.top() = new LogicalOrExpression(std::unique_ptr<Expression>(context->m_Ignore.top()), std::unique_ptr<Expression>($3), @$);
561		else
562			context->m_Ignore.top() = $3;
563
564		$$ = MakeLiteralRaw();
565	}
566	| T_RETURN optional_rterm
567	{
568		UseFlowControl(context, FlowControlReturn, @$);
569		$$ = new ReturnExpression(std::unique_ptr<Expression>($2), @$);
570	}
571	| T_BREAK
572	{
573		UseFlowControl(context, FlowControlBreak, @$);
574		$$ = new BreakExpression(@$);
575	}
576	| T_CONTINUE
577	{
578		UseFlowControl(context, FlowControlContinue, @$);
579		$$ = new ContinueExpression(@$);
580	}
581	| T_DEBUGGER
582	{
583		$$ = new BreakpointExpression(@$);
584	}
585	| T_NAMESPACE rterm
586	{
587		BeginFlowControlBlock(context, FlowControlReturn, false);
588	}
589	rterm_scope_require_side_effect
590	{
591		EndFlowControlBlock(context);
592
593		std::unique_ptr<Expression> expr{$2};
594		BindToScope(expr, ScopeGlobal);
595		$$ = new SetExpression(std::move(expr), OpSetLiteral, std::unique_ptr<Expression>(new NamespaceExpression(std::unique_ptr<Expression>($4), @$)), @$);
596	}
597	| T_USING rterm
598	{
599		Expression::Ptr expr{$2};
600		context->AddImport(std::move(expr));
601		$$ = MakeLiteralRaw();
602	}
603	| apply
604	| object
605	| T_FOR '(' optional_var identifier T_FOLLOWS optional_var identifier T_IN rterm ')'
606	{
607		BeginFlowControlBlock(context, FlowControlContinue | FlowControlBreak, true);
608	}
609	rterm_scope_require_side_effect
610	{
611		EndFlowControlBlock(context);
612
613		$$ = new ForExpression(std::move(*$4), std::move(*$7), std::unique_ptr<Expression>($9), std::unique_ptr<Expression>($12), @$);
614		delete $4;
615		delete $7;
616	}
617	| T_FOR '(' optional_var identifier T_IN rterm ')'
618	{
619		BeginFlowControlBlock(context, FlowControlContinue | FlowControlBreak, true);
620	}
621	rterm_scope_require_side_effect
622	{
623		EndFlowControlBlock(context);
624
625		$$ = new ForExpression(std::move(*$4), "", std::unique_ptr<Expression>($6), std::unique_ptr<Expression>($9), @$);
626		delete $4;
627	}
628	| T_FUNCTION identifier '(' identifier_items ')' use_specifier
629	{
630		BeginFlowControlBlock(context, FlowControlReturn, false);
631	}
632	rterm_scope
633	{
634		EndFlowControlBlock(context);
635
636		std::unique_ptr<FunctionExpression> fexpr{new FunctionExpression(*$2, std::move(*$4), std::move(*$6), std::unique_ptr<Expression>($8), @$)};
637		delete $4;
638		delete $6;
639
640		$$ = new SetExpression(MakeIndexer(ScopeThis, std::move(*$2)), OpSetLiteral, std::move(fexpr), @$);
641		delete $2;
642	}
643	| T_CONST T_IDENTIFIER T_SET rterm
644	{
645		$$ = new SetConstExpression(std::move(*$2), std::unique_ptr<Expression>($4), @$);
646		delete $2;
647	}
648	| T_VAR rterm
649	{
650		std::unique_ptr<Expression> expr{$2};
651		BindToScope(expr, ScopeLocal);
652		$$ = new SetExpression(std::move(expr), OpSetLiteral, MakeLiteral(), @$);
653	}
654	| T_VAR rterm combined_set_op rterm
655	{
656		std::unique_ptr<Expression> expr{$2};
657		BindToScope(expr, ScopeLocal);
658		$$ = new SetExpression(std::move(expr), $3, std::unique_ptr<Expression>($4), @$);
659	}
660	| T_WHILE '(' rterm ')'
661	{
662		BeginFlowControlBlock(context, FlowControlContinue | FlowControlBreak, true);
663	}
664	rterm_scope
665	{
666		EndFlowControlBlock(context);
667
668		$$ = new WhileExpression(std::unique_ptr<Expression>($3), std::unique_ptr<Expression>($6), @$);
669	}
670	| T_THROW rterm
671	{
672		$$ = new ThrowExpression(std::unique_ptr<Expression>($2), false, @$);
673	}
674	| T_TRY rterm_scope T_EXCEPT rterm_scope
675	{
676		$$ = new TryExceptExpression(std::unique_ptr<Expression>($2), std::unique_ptr<Expression>($4), @$);
677	}
678	| rterm_side_effect
679	;
680
681rterm_items: /* empty */
682	{
683		$$ = new std::vector<std::unique_ptr<Expression> >();
684	}
685	| rterm_items_inner
686	| rterm_items_inner ',' optional_newlines
687	| rterm_items_inner newlines
688	;
689
690rterm_items_inner: rterm
691	{
692		$$ = new std::vector<std::unique_ptr<Expression> >();
693		$$->emplace_back($1);
694	}
695	| rterm_items_inner ',' optional_newlines rterm
696	{
697		$$ = $1;
698		$$->emplace_back($4);
699	}
700	;
701
702rterm_array: '['
703	{
704		context->m_OpenBraces++;
705	}
706	optional_newlines rterm_items ']'
707	{
708		context->m_OpenBraces--;
709		$$ = new ArrayExpression(std::move(*$4), @$);
710		delete $4;
711	}
712	;
713
714rterm_dict: '{'
715	{
716		BeginFlowControlBlock(context, 0, false);
717		context->m_IgnoreNewlines.push(false);
718		context->m_OpenBraces++;
719	}
720	statements '}'
721	{
722		EndFlowControlBlock(context);
723		context->m_OpenBraces--;
724		context->m_IgnoreNewlines.pop();
725		std::vector<std::unique_ptr<Expression> > dlist;
726		for (auto& litem : *$3) {
727			if (!litem.second.SideEffect)
728				yyerror(&litem.second.DebugInfo, NULL, NULL, "Value computed is not used.");
729			dlist.emplace_back(std::move(litem.first));
730		}
731		delete $3;
732		$$ = new DictExpression(std::move(dlist), @$);
733	}
734	;
735
736rterm_scope_require_side_effect: '{'
737	{
738		context->m_IgnoreNewlines.push(false);
739		context->m_OpenBraces++;
740	}
741	statements '}'
742	{
743		context->m_OpenBraces--;
744		context->m_IgnoreNewlines.pop();
745		std::vector<std::unique_ptr<Expression> > dlist;
746		for (auto& litem : *$3) {
747			if (!litem.second.SideEffect)
748				yyerror(&litem.second.DebugInfo, NULL, NULL, "Value computed is not used.");
749			dlist.emplace_back(std::move(litem.first));
750		}
751		delete $3;
752		$$ = new DictExpression(std::move(dlist), @$);
753		$$->MakeInline();
754	}
755	;
756
757rterm_scope: '{'
758	{
759		context->m_IgnoreNewlines.push(false);
760		context->m_OpenBraces++;
761	}
762	statements '}'
763	{
764		context->m_OpenBraces--;
765		context->m_IgnoreNewlines.pop();
766		std::vector<std::unique_ptr<Expression> > dlist;
767		decltype($3->size()) num = 0;
768		for (auto& litem : *$3) {
769			if (!litem.second.SideEffect && num != $3->size() - 1)
770				yyerror(&litem.second.DebugInfo, NULL, NULL, "Value computed is not used.");
771			dlist.emplace_back(std::move(litem.first));
772			num++;
773		}
774		delete $3;
775		$$ = new DictExpression(std::move(dlist), @$);
776		$$->MakeInline();
777	}
778	;
779
780else_if_branch: T_ELSE T_IF '(' rterm ')' rterm_scope
781	{
782		$$ = new std::pair<std::unique_ptr<Expression>, std::unique_ptr<Expression> >(std::unique_ptr<Expression>($4), std::unique_ptr<Expression>($6));
783	}
784	;
785
786else_if_branches: /* empty */
787	{
788		$$ = new std::vector<std::pair<std::unique_ptr<Expression>, std::unique_ptr<Expression> > >();
789	}
790	| else_if_branches else_if_branch
791	{
792		$$ = $1;
793		$$->emplace_back(std::move(*$2));
794		delete $2;
795	}
796	;
797
798rterm_side_effect: rterm '(' rterm_items ')'
799	{
800		$$ = new FunctionCallExpression(std::unique_ptr<Expression>($1), std::move(*$3), @$);
801		delete $3;
802	}
803	| T_IF '(' rterm ')' rterm_scope else_if_branches
804	{
805		std::vector<std::pair<std::unique_ptr<Expression>, std::unique_ptr<Expression> > > ebranches;
806		$6->swap(ebranches);
807		delete $6;
808
809		std::unique_ptr<Expression> afalse;
810
811		for (int i = ebranches.size() - 1; i >= 0; i--) {
812			auto& ebranch = ebranches[i];
813			afalse.reset(new ConditionalExpression(std::move(ebranch.first), std::move(ebranch.second), std::move(afalse), @6));
814		}
815
816		$$ = new ConditionalExpression(std::unique_ptr<Expression>($3), std::unique_ptr<Expression>($5), std::move(afalse), @$);
817	}
818	| T_IF '(' rterm ')' rterm_scope else_if_branches T_ELSE rterm_scope
819	{
820		std::vector<std::pair<std::unique_ptr<Expression>, std::unique_ptr<Expression> > > ebranches;
821		$6->swap(ebranches);
822		delete $6;
823
824		$8->MakeInline();
825
826		std::unique_ptr<Expression> afalse{$8};
827
828		for (int i = ebranches.size() - 1; i >= 0; i--) {
829			auto& ebranch = ebranches[i];
830			afalse.reset(new ConditionalExpression(std::move(ebranch.first), std::move(ebranch.second), std::move(afalse), @6));
831		}
832
833		$$ = new ConditionalExpression(std::unique_ptr<Expression>($3), std::unique_ptr<Expression>($5), std::move(afalse), @$);
834	}
835	| rterm '?' rterm ':' rterm
836	{
837		$$ = new ConditionalExpression(std::unique_ptr<Expression>($1), std::unique_ptr<Expression>($3), std::unique_ptr<Expression>($5), @$);
838	}
839	;
840
841rterm_no_side_effect_no_dict: T_STRING
842	{
843		$$ = MakeLiteralRaw(std::move(*$1));
844		delete $1;
845	}
846	| T_NUMBER
847	{
848		$$ = MakeLiteralRaw($1);
849	}
850	| T_BOOLEAN
851	{
852		$$ = MakeLiteralRaw($1);
853	}
854	| T_NULL
855	{
856		$$ = MakeLiteralRaw();
857	}
858	| rterm '.' T_IDENTIFIER %dprec 2
859	{
860		$$ = new IndexerExpression(std::unique_ptr<Expression>($1), MakeLiteral(std::move(*$3)), @$);
861		delete $3;
862	}
863	| rterm '[' rterm ']'
864	{
865		$$ = new IndexerExpression(std::unique_ptr<Expression>($1), std::unique_ptr<Expression>($3), @$);
866	}
867	| T_IDENTIFIER
868	{
869		$$ = new VariableExpression(std::move(*$1), context->GetImports(), @1);
870		delete $1;
871	}
872	| T_MULTIPLY rterm %prec DEREF_OP
873	{
874		$$ = new DerefExpression(std::unique_ptr<Expression>($2), @$);
875	}
876	| T_BINARY_AND rterm %prec REF_OP
877	{
878		$$ = new RefExpression(std::unique_ptr<Expression>($2), @$);
879	}
880	| '!' rterm
881	{
882		$$ = new LogicalNegateExpression(std::unique_ptr<Expression>($2), @$);
883	}
884	| '~' rterm
885	{
886		$$ = new NegateExpression(std::unique_ptr<Expression>($2), @$);
887	}
888	| T_PLUS rterm %prec UNARY_PLUS
889	{
890		$$ = $2;
891	}
892	| T_MINUS rterm %prec UNARY_MINUS
893	{
894		$$ = new SubtractExpression(MakeLiteral(0), std::unique_ptr<Expression>($2), @$);
895	}
896	| T_THIS
897	{
898		$$ = new GetScopeExpression(ScopeThis);
899	}
900	| T_GLOBALS
901	{
902		$$ = new GetScopeExpression(ScopeGlobal);
903	}
904	| T_LOCALS
905	{
906		$$ = new GetScopeExpression(ScopeLocal);
907	}
908	| T_CURRENT_FILENAME
909	{
910		$$ = MakeLiteralRaw(@$.Path);
911	}
912	| T_CURRENT_LINE
913	{
914		$$ = MakeLiteralRaw(@$.FirstLine);
915	}
916	| identifier T_FOLLOWS
917	{
918		BeginFlowControlBlock(context, FlowControlReturn, false);
919	}
920	rterm_scope %dprec 2
921	{
922		EndFlowControlBlock(context);
923
924		std::vector<String> args;
925		args.emplace_back(std::move(*$1));
926		delete $1;
927
928		$$ = new FunctionExpression("<anonymous>", std::move(args), {}, std::unique_ptr<Expression>($4), @$);
929	}
930	| identifier T_FOLLOWS rterm %dprec 1
931	{
932		ASSERT(!dynamic_cast<DictExpression *>($3));
933
934		std::vector<String> args;
935		args.emplace_back(std::move(*$1));
936		delete $1;
937
938		$$ = new FunctionExpression("<anonymous>", std::move(args), {}, std::unique_ptr<Expression>($3), @$);
939	}
940	| '(' identifier_items ')' use_specifier T_FOLLOWS
941	{
942		BeginFlowControlBlock(context, FlowControlReturn, false);
943	}
944	rterm_scope %dprec 2
945	{
946		EndFlowControlBlock(context);
947
948		$$ = new FunctionExpression("<anonymous>", std::move(*$2), std::move(*$4), std::unique_ptr<Expression>($7), @$);
949		delete $2;
950		delete $4;
951	}
952	| '(' identifier_items ')' use_specifier T_FOLLOWS rterm %dprec 1
953	{
954		ASSERT(!dynamic_cast<DictExpression *>($6));
955
956		$$ = new FunctionExpression("<anonymous>", std::move(*$2), std::move(*$4), std::unique_ptr<Expression>($6), @$);
957		delete $2;
958		delete $4;
959	}
960	| rterm_array
961	| '('
962	{
963		context->m_OpenBraces++;
964	}
965	rterm ')'
966	{
967		context->m_OpenBraces--;
968		$$ = $3;
969	}
970	| rterm T_LOGICAL_OR rterm { MakeRBinaryOp<LogicalOrExpression>(&$$, $1, $3, @1, @3); }
971	| rterm T_LOGICAL_AND rterm { MakeRBinaryOp<LogicalAndExpression>(&$$, $1, $3, @1, @3); }
972	| rterm T_BINARY_OR rterm { MakeRBinaryOp<BinaryOrExpression>(&$$, $1, $3, @1, @3); }
973	| rterm T_BINARY_AND rterm { MakeRBinaryOp<BinaryAndExpression>(&$$, $1, $3, @1, @3); }
974	| rterm T_IN rterm { MakeRBinaryOp<InExpression>(&$$, $1, $3, @1, @3); }
975	| rterm T_NOT_IN rterm { MakeRBinaryOp<NotInExpression>(&$$, $1, $3, @1, @3); }
976	| rterm T_EQUAL rterm { MakeRBinaryOp<EqualExpression>(&$$, $1, $3, @1, @3); }
977	| rterm T_NOT_EQUAL rterm { MakeRBinaryOp<NotEqualExpression>(&$$, $1, $3, @1, @3); }
978	| rterm T_LESS_THAN rterm { MakeRBinaryOp<LessThanExpression>(&$$, $1, $3, @1, @3); }
979	| rterm T_LESS_THAN_OR_EQUAL rterm { MakeRBinaryOp<LessThanOrEqualExpression>(&$$, $1, $3, @1, @3); }
980	| rterm T_GREATER_THAN rterm { MakeRBinaryOp<GreaterThanExpression>(&$$, $1, $3, @1, @3); }
981	| rterm T_GREATER_THAN_OR_EQUAL rterm { MakeRBinaryOp<GreaterThanOrEqualExpression>(&$$, $1, $3, @1, @3); }
982	| rterm T_SHIFT_LEFT rterm { MakeRBinaryOp<ShiftLeftExpression>(&$$, $1, $3, @1, @3); }
983	| rterm T_SHIFT_RIGHT rterm { MakeRBinaryOp<ShiftRightExpression>(&$$, $1, $3, @1, @3); }
984	| rterm T_PLUS rterm { MakeRBinaryOp<AddExpression>(&$$, $1, $3, @1, @3); }
985	| rterm T_MINUS rterm { MakeRBinaryOp<SubtractExpression>(&$$, $1, $3, @1, @3); }
986	| rterm T_MULTIPLY rterm { MakeRBinaryOp<MultiplyExpression>(&$$, $1, $3, @1, @3); }
987	| rterm T_DIVIDE_OP rterm { MakeRBinaryOp<DivideExpression>(&$$, $1, $3, @1, @3); }
988	| rterm T_MODULO rterm { MakeRBinaryOp<ModuloExpression>(&$$, $1, $3, @1, @3); }
989	| rterm T_XOR rterm { MakeRBinaryOp<XorExpression>(&$$, $1, $3, @1, @3); }
990	| T_FUNCTION '(' identifier_items ')' use_specifier
991	{
992		BeginFlowControlBlock(context, FlowControlReturn, false);
993	}
994	rterm_scope
995	{
996		EndFlowControlBlock(context);
997
998		$$ = new FunctionExpression("<anonymous>", std::move(*$3), std::move(*$5), std::unique_ptr<Expression>($7), @$);
999		delete $3;
1000		delete $5;
1001	}
1002	| T_NULLARY_LAMBDA_BEGIN
1003	{
1004		BeginFlowControlBlock(context, FlowControlReturn, false);
1005	}
1006	statements T_NULLARY_LAMBDA_END
1007	{
1008		EndFlowControlBlock(context);
1009
1010		std::vector<std::unique_ptr<Expression> > dlist;
1011		decltype(dlist.size()) num = 0;
1012		for (auto& litem : *$3) {
1013			if (!litem.second.SideEffect && num != $3->size() - 1)
1014				yyerror(&litem.second.DebugInfo, NULL, NULL, "Value computed is not used.");
1015			dlist.emplace_back(std::move(litem.first));
1016			num++;
1017		}
1018		delete $3;
1019		std::unique_ptr<DictExpression> aexpr{new DictExpression(std::move(dlist), @$)};
1020		aexpr->MakeInline();
1021
1022		$$ = new FunctionExpression("<anonymous>", {}, {}, std::move(aexpr), @$);
1023	}
1024	;
1025
1026rterm_no_side_effect:
1027	rterm_no_side_effect_no_dict %dprec 1
1028	| rterm_dict %dprec 2
1029	{
1030		std::unique_ptr<Expression> expr{$1};
1031		BindToScope(expr, ScopeThis);
1032		$$ = expr.release();
1033	}
1034	;
1035
1036rterm:
1037	rterm_side_effect %dprec 2
1038	| rterm_no_side_effect %dprec 1
1039	;
1040
1041target_type_specifier: /* empty */
1042	{
1043		$$ = new String();
1044	}
1045	| T_TO identifier
1046	{
1047		$$ = $2;
1048	}
1049	;
1050
1051default_specifier: /* empty */
1052	{
1053		$$ = false;
1054	}
1055	| T_DEFAULT
1056	{
1057		$$ = true;
1058	}
1059	;
1060
1061ignore_specifier: /* empty */
1062	{
1063		$$ = false;
1064	}
1065	| T_IGNORE_ON_ERROR
1066	{
1067		$$ = true;
1068	}
1069	;
1070
1071use_specifier: /* empty */
1072	{
1073		$$ = new std::map<String, std::unique_ptr<Expression> >();
1074	}
1075	| T_USE '(' use_specifier_items ')'
1076	{
1077		$$ = $3;
1078	}
1079	;
1080
1081use_specifier_items: use_specifier_item
1082	{
1083		$$ = new std::map<String, std::unique_ptr<Expression> >();
1084		$$->emplace(std::move(*$1));
1085		delete $1;
1086	}
1087	| use_specifier_items ',' use_specifier_item
1088	{
1089		$$ = $1;
1090		$$->emplace(std::move(*$3));
1091		delete $3;
1092	}
1093	;
1094
1095use_specifier_item: identifier
1096	{
1097		std::unique_ptr<Expression> var (new VariableExpression(*$1, context->GetImports(), @1));
1098		$$ = new std::pair<String, std::unique_ptr<Expression> >(std::move(*$1), std::move(var));
1099		delete $1;
1100	}
1101	| identifier T_SET rterm
1102	{
1103		$$ = new std::pair<String, std::unique_ptr<Expression> >(std::move(*$1), std::unique_ptr<Expression>($3));
1104		delete $1;
1105	}
1106	;
1107
1108apply_for_specifier: /* empty */
1109	| T_FOR '(' optional_var identifier T_FOLLOWS optional_var identifier T_IN rterm ')'
1110	{
1111		context->m_FKVar.top() = std::move(*$4);
1112		delete $4;
1113
1114		context->m_FVVar.top() = std::move(*$7);
1115		delete $7;
1116
1117		context->m_FTerm.top() = $9;
1118	}
1119	| T_FOR '(' optional_var identifier T_IN rterm ')'
1120	{
1121		context->m_FKVar.top() = std::move(*$4);
1122		delete $4;
1123
1124		context->m_FVVar.top() = "";
1125
1126		context->m_FTerm.top() = $6;
1127	}
1128	;
1129
1130optional_rterm: /* empty */
1131	{
1132		$$ = MakeLiteralRaw();
1133	}
1134	| rterm
1135	;
1136
1137apply:
1138	{
1139		context->m_Apply.push(true);
1140		context->m_SeenAssign.push(false);
1141		context->m_SeenIgnore.push(false);
1142		context->m_Assign.push(NULL);
1143		context->m_Ignore.push(NULL);
1144		context->m_FKVar.push("");
1145		context->m_FVVar.push("");
1146		context->m_FTerm.push(NULL);
1147	}
1148	T_APPLY identifier optional_rterm apply_for_specifier target_type_specifier use_specifier ignore_specifier
1149	{
1150		BeginFlowControlBlock(context, FlowControlReturn, false);
1151	}
1152	rterm_scope_require_side_effect
1153	{
1154		EndFlowControlBlock(context);
1155
1156		context->m_Apply.pop();
1157
1158		String type = std::move(*$3);
1159		delete $3;
1160		String target = std::move(*$6);
1161		delete $6;
1162
1163		if (!ApplyRule::IsValidSourceType(type))
1164			BOOST_THROW_EXCEPTION(ScriptError("'apply' cannot be used with type '" + type + "'", @3));
1165
1166		if (!ApplyRule::IsValidTargetType(type, target)) {
1167			if (target == "") {
1168				std::vector<String> types = ApplyRule::GetTargetTypes(type);
1169				String typeNames;
1170
1171				for (std::vector<String>::size_type i = 0; i < types.size(); i++) {
1172					if (typeNames != "") {
1173						if (i == types.size() - 1)
1174							typeNames += " or ";
1175						else
1176							typeNames += ", ";
1177					}
1178
1179					typeNames += "'" + types[i] + "'";
1180				}
1181
1182				BOOST_THROW_EXCEPTION(ScriptError("'apply' target type is ambiguous (can be one of " + typeNames + "): use 'to' to specify a type", DebugInfoRange(@2, @3)));
1183			} else
1184				BOOST_THROW_EXCEPTION(ScriptError("'apply' target type '" + target + "' is invalid", @6));
1185		}
1186
1187		bool seen_assign = context->m_SeenAssign.top();
1188		context->m_SeenAssign.pop();
1189
1190		// assign && !ignore
1191		if (!seen_assign && !context->m_FTerm.top())
1192			BOOST_THROW_EXCEPTION(ScriptError("'apply' is missing 'assign'/'for'", DebugInfoRange(@2, @3)));
1193
1194		std::unique_ptr<Expression> ignore{context->m_Ignore.top()};
1195		context->m_Ignore.pop();
1196
1197		std::unique_ptr<Expression> assign;
1198
1199		if (!seen_assign)
1200			assign = MakeLiteral(true);
1201		else
1202			assign.reset(context->m_Assign.top());
1203
1204		context->m_Assign.pop();
1205
1206		std::unique_ptr<Expression> filter;
1207
1208		if (ignore) {
1209			std::unique_ptr<Expression>rex{new LogicalNegateExpression(std::move(ignore), DebugInfoRange(@2, @5))};
1210
1211			filter.reset(new LogicalAndExpression(std::move(assign), std::move(rex), DebugInfoRange(@2, @5)));
1212		} else
1213			filter.swap(assign);
1214
1215		String fkvar = std::move(context->m_FKVar.top());
1216		context->m_FKVar.pop();
1217
1218		String fvvar = std::move(context->m_FVVar.top());
1219		context->m_FVVar.pop();
1220
1221		std::unique_ptr<Expression> fterm{context->m_FTerm.top()};
1222		context->m_FTerm.pop();
1223
1224		$$ = new ApplyExpression(std::move(type), std::move(target), std::unique_ptr<Expression>($4), std::move(filter), context->GetPackage(), std::move(fkvar), std::move(fvvar), std::move(fterm), std::move(*$7), $8, std::unique_ptr<Expression>($10), DebugInfoRange(@2, @8));
1225		delete $7;
1226	}
1227	;
1228
1229newlines: T_NEWLINE
1230	| T_NEWLINE newlines
1231	;
1232
1233optional_newlines: /* empty */
1234	| newlines
1235	;
1236
1237/* required separator */
1238sep: ',' optional_newlines
1239	| ';' optional_newlines
1240	| newlines
1241	;
1242
1243%%
1244