1 // =================================
  2 // Copyright (c) 2021 Seppo Laakko
  3 // Distributed under the MIT license
  4 // =================================
  5 
  6 [hpp]#include <sngcm/cmparser/ParserApi.hpp>
  7 [hpp]#include <sngcm/ast/Statement.hpp>
  8 [hpp]#include <sngcm/cmparser/ParsingContext.hpp>
  9 [cpp]#include <sngcm/cmparser/Expression.hpp>
 10 [cpp]#include <sngcm/cmparser/TypeExpr.hpp>
 11 [cpp]#include <sngcm/cmparser/Identifier.hpp>
 12 [cpp]#include <sngcm/cmlexer/CmajorLexer.hpp>
 13 [cpp]#include <sngcm/cmlexer/CmajorTokens.hpp>
 14 
 15 using namespace sngcm::ast;
 16 using namespace CmajorTokens;
 17 
 18 parser api(SNGCM_PARSER_API) StatementParser
 19 {
 20     uselexer CmajorLexer;
 21 
 22     using ExpressionParser.Expression;
 23     using ExpressionParser.ArgumentList;
 24     using TypeExprParser.TypeExpr;
 25     using IdentifierParser.Identifier;
 26 
 27     Statement(boost::uuids::uuid* moduleId, ParsingContext* ctx) : StatementNode*
 28         ::= LabeledStatement(moduleId, ctx):labeledStatement{ return labeledStatement; }
 29         |   ControlStatement(moduleId, ctx):controlStatement{ return controlStatement; }
 30         |   ExpressionStatement(moduleId, ctx):expressionStatement{ return expressionStatement; }
 31         |   AssignmentStatement(moduleId, ctx):assignmentStatement{ return assignmentStatement; }
 32         |   ConstructionStatement(moduleId, ctx):constructionStatement{ return constructionStatement; }
 33         |   DeleteStatement(moduleId, ctx):deleteStatement{ return deleteStatement; }
 34         |   DestroyStatement(moduleId, ctx):destroyStatement{ return destroyStatement; }
 35         |   EmptyStatement(moduleId, ctx):emptyStatement{ return emptyStatement; }
 36         |   ThrowStatement(moduleId, ctx):throwStatement{ return throwStatement; }
 37         |   TryStatement(moduleId, ctx):tryStatement{ return tryStatement; }
 38         |   AssertStatement(moduleId, ctx):assertStatement{ return assertStatement; }
 39         |   ConditionalCompilationStatement(moduleId, ctx):condCompStatement{ return condCompStatement; }
 40         ;
 41 
 42     Label(boost::uuids::uuid* moduleId, var Span s, var std::u32string label) : LabelNode*
 43         ::= (ID{ s = span; label = lexer.GetMatch(span); } COLON{ s.end = span.end; }){ return new LabelNode(s, *moduleId, label); }
 44         ;
 45 
 46     LabeledStatement(boost::uuids::uuid* moduleId, ParsingContext* ctx, var std::unique_ptr stmt) : StatementNode*
 47         ::= Label(moduleId):lbl Statement(moduleId, ctx):s{ stmt.reset(new LabeledStatementNode(span, *moduleId, s)); stmt->SetLabelNode(lbl); return stmt.release(); }
 48         ;
 49 
 50     ControlStatement(boost::uuids::uuid* moduleId, ParsingContext* ctx) : StatementNode*
 51         ::= CompoundStatement(moduleId, ctx):compoundStatement{ return compoundStatement; }
 52         |   ReturnStatement(moduleId, ctx):returnStatement{ return returnStatement; }
 53         |   IfStatement(moduleId, ctx):ifStatement{ return ifStatement; }
 54         |   WhileStatement(moduleId, ctx):whileStatement{ return whileStatement; }
 55         |   DoStatement(moduleId, ctx):doStatement{ return doStatement; }
 56         |   RangeForStatement(moduleId, ctx):rangeForStatement{ return rangeForStatement; }
 57         |   ForStatement(moduleId, ctx):forStatement{ return forStatement; }
 58         |   BreakStatement(moduleId, ctx):breakStatement{ return breakStatement; }
 59         |   ContinueStatement(moduleId, ctx):continueStatement{ return continueStatement; }
 60         |   GotoStatement(moduleId, ctx):gotoStatement{ return gotoStatement; }
 61         |   SwitchStatement(moduleId, ctx):switchStatement{ return switchStatement; }
 62         |   GotoCaseStatement(moduleId, ctx):gotoCaseStatement{ return gotoCaseStatement; }
 63         |   GotoDefaultStatement(moduleId, ctx):gotoDefaultStatement{ return gotoDefaultStatement; }
 64         ;
 65 
 66     CompoundStatement(boost::uuids::uuid* moduleId, ParsingContext* ctx, var std::unique_ptr compoundStatement) : CompoundStatementNode*
 67         ::= LBRACE{ compoundStatement.reset(new CompoundStatementNode(span, *moduleId)); compoundStatement->SetBeginBraceSpan(span); }
 68             (Statement(moduleId, ctx):stmt{ compoundStatement->AddStatement(stmt); })* RBRACE!
 69         {
 70             compoundStatement->SetEndBraceSpan(span);
 71             compoundStatement->SetSpanEnd(span.end);
 72             return compoundStatement.release();
 73         }
 74         ;
 75 
 76     ReturnStatement(boost::uuids::uuid* moduleId, ParsingContext* ctx, var Span s) : StatementNode*
 77         ::= RETURN{ s = span; } Expression(moduleId, ctx):expr? SEMICOLON!{ s.end = span.end; return new ReturnStatementNode(s, *moduleId, expr); }
 78         ;
 79 
 80     IfStatement(boost::uuids::uuid* moduleId, ParsingContext* ctx, var Span s, var Span leftParenSpan, var Span rightParenSpan, var Span elseSpan, var std::unique_ptr condNode) : IfStatementNode*
 81         ::=
 82         (   IF{ s = span; } LPAREN{ leftParenSpan = span; } Expression(moduleId, ctx):cond{ condNode.reset(cond); s.end = condNode->GetSpan().end; }
 83             RPAREN{ rightParenSpan = span; s.end = span.end; }
 84             Statement(moduleId, ctx):thenS (ELSE{ elseSpan = span; } Statement(moduleId, ctx):elseS)?
 85         )
 86         {
 87             IfStatementNode* value = new IfStatementNode(s, *moduleId, condNode.release(), thenS, elseS);
 88             value->SetLeftParenSpan(leftParenSpan);
 89             value->SetRightParenSpan(rightParenSpan);
 90             value->SetElseSpan(elseSpan);
 91             return value;
 92         }
 93         ;
 94 
 95     WhileStatement(boost::uuids::uuid* moduleId, ParsingContext* ctx, var Span s, var Span leftParenSpan, var Span rightParenSpan) : WhileStatementNode*
 96         ::= (WHILE{ s = span; } LPAREN!{ leftParenSpan = span; } Expression(moduleId, ctx):cond! RPAREN!{ rightParenSpan = span; } Statement(moduleId, ctx):stmt!{ s.end = span.end; })
 97         {
 98             WhileStatementNode* value = new WhileStatementNode(s, *moduleId, cond, stmt);
 99             value->SetLeftParenSpan(leftParenSpan);
100             value->SetRightParenSpan(rightParenSpan);
101             return value;
102         }
103         ;
104 
105     DoStatement(boost::uuids::uuid* moduleId, ParsingContext* ctx, var Span s, var Span whileSpan, var Span leftParenSpan, var Span rightParenSpan) : DoStatementNode*
106         ::= (DO{ s = span; } Statement(moduleId, ctx):stmt! WHILE!{ whileSpan = span; } LPAREN!{ leftParenSpan = span; } Expression(moduleId, ctx):cond! RPAREN!{ rightParenSpan = span; } SEMICOLON!{ s.end = span.end; })
107         {
108             DoStatementNode* value = new DoStatementNode(s, *moduleId, stmt, cond);
109             value->SetWhileSpan(whileSpan);
110             value->SetLeftParenSpan(leftParenSpan);
111             value->SetRightParenSpan(rightParenSpan);
112             return value;
113         }
114         ;
115 
116     ForStatement(boost::uuids::uuid* moduleId, ParsingContext* ctx, var Span s, var Span leftParenSpan, var Span rightParenSpan) : ForStatementNode*
117         ::=
118         (
119             FOR{ s = span; } LPAREN{ leftParenSpan = span; } ForInitStatement(moduleId, ctx):init! Expression(moduleId, ctx):cond? SEMICOLON! ForLoopStatementExpr(moduleId, ctx):loop! RPAREN!{ rightParenSpan = span; }
120             Statement(moduleId, ctx):stmt!{ s.end = span.end; }
121         )
122         {
123             ForStatementNode* value = new ForStatementNode(s, *moduleId, init, cond, loop, stmt);
124             value->SetLeftParenSpan(leftParenSpan);
125             value->SetRightParenSpan(rightParenSpan);
126             return value;
127         }
128         ;
129 
130     ForInitStatement(boost::uuids::uuid* moduleId, ParsingContext* ctx) : StatementNode*
131         ::= AssignmentStatement(moduleId, ctx):assignmentStatement{ return assignmentStatement; }
132         |   ConstructionStatement(moduleId, ctx):constructionStatement{ return constructionStatement; }
133         |   EmptyStatement(moduleId, ctx):emptyStatement{ return emptyStatement; }
134         ;
135 
136     ForLoopStatementExpr(boost::uuids::uuid* moduleId, ParsingContext* ctx, var std::unique_ptr exprNode) : StatementNode*
137         ::= AssignmentStatementExpr(moduleId, ctx):assignmentStatementExpr
138         {
139             return assignmentStatementExpr;
140         }
141         |   Expression(moduleId, ctx):expr
142         {
143             exprNode.reset(expr);
144             Span s = exprNode->GetSpan();
145             ExpressionStatementNode* expressionStatementNode = new ExpressionStatementNode(s, *moduleId, exprNode.release());
146             return expressionStatementNode;
147         }
148         |   empty
149         {
150             EmptyStatementNode* emptyStatementNode = new EmptyStatementNode(span, *moduleId);
151             return emptyStatementNode;
152         }
153         ;
154 
155     RangeForStatement(boost::uuids::uuid* moduleId, ParsingContext* ctx, var Span s, var Span leftParenSpan, var Span rightParenSpan, var Span colonSpan) : RangeForStatementNode*
156         ::=
157         (
158             FOR{ s = span; } LPAREN{ leftParenSpan = span; } TypeExpr(moduleId, ctx):type Identifier(moduleId):id COLON{ colonSpan = span; } Expression(moduleId, ctx):container! RPAREN!{ rightParenSpan = span; }
159             Statement(moduleId, ctx):action{ s.end = span.end; }
160         )
161         {
162             RangeForStatementNode* value = new RangeForStatementNode(s, *moduleId, type, id, container, action);
163             value->SetLeftParenSpan(leftParenSpan);
164             value->SetRightParenSpan(rightParenSpan);
165             value->SetColonSpan(colonSpan);
166             return value;
167         }
168         ;
169 
170     BreakStatement(boost::uuids::uuid* moduleId, ParsingContext* ctx, var Span s) : StatementNode*
171         ::= BREAK{ s = span; } SEMICOLON!{ s.end = span.end; return new BreakStatementNode(s, *moduleId); }
172         ;
173 
174     ContinueStatement(boost::uuids::uuid* moduleId, ParsingContext* ctx, var Span s) : StatementNode*
175         ::= CONTINUE{ s = span; } SEMICOLON!{ s.end = span.end; return new ContinueStatementNode(s, *moduleId); }
176         ;
177 
178     GotoStatement(boost::uuids::uuid* moduleId, ParsingContext* ctx, var std::u32string label, var Span s) : StatementNode*
179         ::= GOTO{ s = span; } ID{ label = lexer.GetMatch(span); } SEMICOLON!{ s.end = span.end; return new GotoStatementNode(s, *moduleId, label); }
180         ;
181 
182     SwitchStatement(boost::uuids::uuid* moduleId, ParsingContext* ctx, var std::unique_ptr switchStatement,
183         var Span leftParenSpan, var Span rightParenSpan, var Span beginBraceSpan, var Span endBraceSpan) : SwitchStatementNode*
184         ::= (SWITCH LPAREN!{ leftParenSpan = span; } Expression(moduleId, ctx):cond! RPAREN!)
185             {
186                 rightParenSpan = span;
187                 switchStatement.reset(new SwitchStatementNode(span, *moduleId, cond));
188                 switchStatement->SetLeftParenSpan(leftParenSpan);
189                 switchStatement->SetRightParenSpan(rightParenSpan);
190             }
191             LBRACE!{ beginBraceSpan = span; }
192             (   CaseStatement(moduleId, ctx):caseStatement{ switchStatement->AddCase(caseStatement); }
193             |   DefaultStatement(moduleId, ctx):defaultStatement{ switchStatement->SetDefault(defaultStatement); }
194             )*
195             RBRACE!{ endBraceSpan = span; switchStatement->SetBeginBraceSpan(beginBraceSpan); switchStatement->SetEndBraceSpan(endBraceSpan); return switchStatement.release(); }
196         ;
197 
198     CaseStatement(boost::uuids::uuid* moduleId, ParsingContext* ctx, var std::unique_ptr caseS, var Span s, var Span caseSpan) : CaseStatementNode*
199         ::= empty{ caseS.reset(new CaseStatementNode(span, *moduleId)); s = span; }
200             (((CASE{ caseSpan = span; } Expression(moduleId, ctx):caseExpr{ caseS->AddCaseSpan(caseSpan); caseS->AddCaseExpr(caseExpr); } COLON!)+){ s.end = span.end; caseS->SetSpan(s); }
201             (Statement(moduleId, ctx):stmt{ caseS->AddStatement(stmt); })*
202         )
203         {
204             return caseS.release();
205         }
206         ;
207 
208     DefaultStatement(boost::uuids::uuid* moduleId, ParsingContext* ctx, var std::unique_ptr defaultS, var Span s) : DefaultStatementNode*
209         ::= (DEFAULT{ s = span; } COLON!{ s.end = span.end; defaultS.reset(new DefaultStatementNode(s, *moduleId)); }
210             (Statement(moduleId, ctx):stmt{ defaultS->AddStatement(stmt); })*
211         )
212         {
213             return defaultS.release();
214         }
215         ;
216 
217     GotoCaseStatement(boost::uuids::uuid* moduleId, ParsingContext* ctx, var Span s) : StatementNode*
218         ::= GOTO{ s = span; } CASE Expression(moduleId, ctx):caseExpr SEMICOLON!{ s.end = span.end; return new GotoCaseStatementNode(s, *moduleId, caseExpr); }
219         ;
220 
221     GotoDefaultStatement(boost::uuids::uuid* moduleId, ParsingContext* ctx, var Span s) : StatementNode*
222         ::= GOTO{ s = span; } DEFAULT SEMICOLON!{ s.end = span.end; return new GotoDefaultStatementNode(s, *moduleId); }
223         ;
224 
225     AssignmentStatementExpr(boost::uuids::uuid* moduleId, ParsingContext* ctx, var std::unique_ptr target, var Span s) : StatementNode*
226         ::= empty{ ctx->PushParsingLvalue(true); }
227             Expression(moduleId, ctx):tgt{ target.reset(tgt); s = target->GetSpan(); ctx->PopParsingLvalue(); } / { ctx->PopParsingLvalue(); } ASSIGN Expression(moduleId, ctx):source
228         {
229             s.end = span.end; return new AssignmentStatementNode(s, *moduleId, target.release(), source);
230         }
231         ;
232 
233     AssignmentStatement(boost::uuids::uuid* moduleId, ParsingContext* ctx, var std::unique_ptr statement) : StatementNode*
234         ::= AssignmentStatementExpr(moduleId, ctx):stmt SEMICOLON{ statement.reset(stmt); statement->SetSpanEnd(span.end); return statement.release(); }
235         ;
236 
237     ConstructionStatement(boost::uuids::uuid* moduleId, ParsingContext* ctx, var std::unique_ptr constructionStatement) : ConstructionStatementNode*
238         ::= (TypeExpr(moduleId, ctx):type Identifier(moduleId):id!){ constructionStatement.reset(new ConstructionStatementNode(span, *moduleId, type, id)); }
239             (   ASSIGN Expression(moduleId, ctx):value!{ constructionStatement->AddArgument(value); constructionStatement->SetAssignment(); }
240             |   LPAREN ArgumentList(moduleId, ctx, constructionStatement.get()):argumentList RPAREN!
241             |   empty{ constructionStatement->SetEmpty(); }
242             )
243             SEMICOLON!{ constructionStatement->SetSpanEnd(span.end); return constructionStatement.release(); }
244         ;
245 
246     DeleteStatement(boost::uuids::uuid* moduleId, ParsingContext* ctx, var Span s) : StatementNode*
247         ::= DELETE{ s = span; } Expression(moduleId, ctx):ptr! SEMICOLON!{ s.end = span.end; return new DeleteStatementNode(s, *moduleId, ptr); }
248         ;
249 
250     DestroyStatement(boost::uuids::uuid* moduleId, ParsingContext* ctx, var Span s) : StatementNode*
251         ::= DESTROY{ s = span; } Expression(moduleId, ctx):ptr! SEMICOLON!{ s.end = span.end; return new DestroyStatementNode(s, *moduleId, ptr); }
252         ;
253 
254     ExpressionStatement(boost::uuids::uuid* moduleId, ParsingContext* ctx, var std::unique_ptr exprNode, var Span s) : StatementNode*
255         ::= empty{ ctx->PushParsingExpressionStatement(true); }
256             (Expression(moduleId, ctx):expr{ exprNode.reset(expr); s = span; } SEMICOLON{ s.end = span.end; })
257             {
258                 ctx->PopParsingExpressionStatement();
259                 exprNode->SetSpan(s);
260                 return new ExpressionStatementNode(s, *moduleId, exprNode.release());
261             }
262             /
263             {
264                 ctx->PopParsingExpressionStatement();
265             }
266         ;
267 
268     EmptyStatement(boost::uuids::uuid* moduleId, ParsingContext* ctx) : StatementNode*
269         ::= SEMICOLON{ return new EmptyStatementNode(span, *moduleId); }
270         ;
271 
272     ThrowStatement(boost::uuids::uuid* moduleId, ParsingContext* ctx, var Span s) : StatementNode*
273         ::= THROW{ s = span; } Expression(moduleId, ctx):exception? SEMICOLON!{ s.end = span.end; return new ThrowStatementNode(s, *moduleId, exception); }
274         ;
275 
276     TryStatement(boost::uuids::uuid* moduleId, ParsingContext* ctx, var std::unique_ptr tryStatement) : TryStatementNode*
277         ::=
278         (   (TRY CompoundStatement(moduleId, ctx):tryBlock){ tryStatement.reset(new TryStatementNode(span, *moduleId, tryBlock)); }
279             (Catch(moduleId, ctx):ctch{ tryStatement->AddCatch(ctch); })+
280         )
281         {
282             return tryStatement.release();
283         }
284         ;
285 
286     Catch(boost::uuids::uuid* moduleId, ParsingContext* ctx, var Span s, var Span leftParenSpan, var Span rightParenSpan) : CatchNode*
287         ::= CATCH{ s = span; } LPAREN!{ leftParenSpan = span; } TypeExpr(moduleId, ctx):catchType! Identifier(moduleId):catchId? RPAREN!{ rightParenSpan = span; }
288             CompoundStatement(moduleId, ctx):catchBlock
289             {
290                 s.end = span.end;
291                 CatchNode* value = new CatchNode(s, *moduleId, catchType, catchId, catchBlock);
292                 value->SetLeftParenSpan(leftParenSpan);
293                 value->SetRightParenSpan(rightParenSpan);
294                 return value;
295             }
296         ;
297 
298     AssertStatement(boost::uuids::uuid* moduleId, ParsingContext* ctx, var Span s) : StatementNode*
299         ::= HASH{ s = span; } ASSERT Expression(moduleId, ctx):expr! SEMICOLON!{ s.end = span.end; return new AssertStatementNode(s, *moduleId, expr); }
300         ;
301 
302     ConditionalCompilationStatement(boost::uuids::uuid* moduleId, ParsingContext* ctx, var std::unique_ptr condCompStmt,
303         var Span s, var Span keywordSpan, var Span leftParenSpan, var Span rightParenSpan) : ConditionalCompilationStatementNode*
304         ::= HASH{ s = span; keywordSpan = span; }
305             IF{ keywordSpan.end = span.end; } LPAREN!{ leftParenSpan = span; }
306             ConditionalCompilationExpression(moduleId):ifExpr{ s.end = span.end; condCompStmt.reset(new ConditionalCompilationStatementNode(s, *moduleId, ifExpr)); condCompStmt->IfPart()->SetKeywordSpan(keywordSpan); }
307             RPAREN!{ rightParenSpan = span; condCompStmt->IfPart()->SetLeftParenSpan(leftParenSpan); condCompStmt->IfPart()->SetRightParenSpan(rightParenSpan); }
308             (Statement(moduleId, ctx):ifS{ condCompStmt->AddIfStatement(ifS); })*
309             (
310                 HASH{ keywordSpan = span; } ELIF{ keywordSpan.end = span.end; }
311                 LPAREN!{ leftParenSpan = span; } ConditionalCompilationExpression(moduleId):elifExpr{ condCompStmt->AddElifExpr(span, *moduleId, elifExpr); } RPAREN!
312                 {
313                     rightParenSpan = span;
314                     condCompStmt->SetElifLeftParenSpan(leftParenSpan);
315                     condCompStmt->SetElifRightParenSpan(rightParenSpan);
316                     condCompStmt->SetElifKeywordSpan(keywordSpan); 
317                 }
318                 (Statement(moduleId, ctx):elifS{ condCompStmt->AddElifStatement(elifS); })*
319             )*
320             (
321                 HASH{ keywordSpan = span; } ELSE (Statement(moduleId, ctx):elseS{ condCompStmt->AddElseStatement(span, *moduleId, elseS); })* empty{ condCompStmt->ElsePart()->SetKeywordSpan(keywordSpan); }
322             )?
323             HASH{ keywordSpan = span; } ENDIF!{ keywordSpan.end = span.end; condCompStmt->SetEndIfSpan(keywordSpan); return condCompStmt.release(); }
324         ;
325 
326     ConditionalCompilationExpression(boost::uuids::uuid* moduleId) : ConditionalCompilationExpressionNode*
327         ::= ConditionalCompilationDisjunction(moduleId):disjunction{ return disjunction; }
328         ;
329 
330     ConditionalCompilationDisjunction(boost::uuids::uuid* moduleId, var Span s, var std::unique_ptr condCompExpr) : ConditionalCompilationExpressionNode*
331         ::=
332         (
333             ConditionalCompilationConjunction(moduleId):left{ s = span; condCompExpr.reset(left); }
334             (DISJUNCTION ConditionalCompilationConjunction(moduleId):right{ s.end = span.end; condCompExpr.reset(new ConditionalCompilationDisjunctionNode(s, *moduleId, condCompExpr.release(), right)); })*
335         )
336         {
337             return condCompExpr.release(); 
338         }
339         ;
340 
341     ConditionalCompilationConjunction(boost::uuids::uuid* moduleId, var Span s, var std::unique_ptr condCompExpr) : ConditionalCompilationExpressionNode*
342         ::=
343         (
344             ConditionalCompilationPrefix(moduleId):left{ s = span; condCompExpr.reset(left); }
345             (AMPAMP ConditionalCompilationPrefix(moduleId):right{ s.end = span.end; condCompExpr.reset(new ConditionalCompilationConjunctionNode(s, *moduleId, condCompExpr.release(), right)); })*
346         )
347         {
348             return condCompExpr.release(); 
349         }
350         ;
351 
352     ConditionalCompilationPrefix(boost::uuids::uuid* moduleId, var Span s, var std::unique_ptr condCompExpr) : ConditionalCompilationExpressionNode*
353         ::=
354         (   EXCLAMATION{ s = span; } ConditionalCompilationPrefix(moduleId):prefix{ s.end = span.end; condCompExpr.reset(new ConditionalCompilationNotNode(s, *moduleId, prefix)); } 
355         |   ConditionalCompilationPrimary(moduleId):primary!{ condCompExpr.reset(primary); }
356         )
357         {
358             return condCompExpr.release(); 
359         }
360         ;
361 
362     ConditionalCompilationPrimary(boost::uuids::uuid* moduleId, var std::u32string symbol) : ConditionalCompilationExpressionNode*
363         ::= ID{ symbol = lexer.GetMatch(span); return new ConditionalCompilationPrimaryNode(span, *moduleId, symbol); }
364         |   LPAREN ConditionalCompilationExpression(moduleId):expr RPAREN!{ return new ParenthesizedConditionalCompilationExpressionNode(span, *moduleId, expr); }
365         ;
366 
367     ruleinfo
368     {
369         (Statement, "statement"), (Label, "label"), (LabeledStatement, "labeled statement"), (ControlStatement, "control statement"), (CompoundStatement, "compound statement"),
370         (ReturnStatement, "return statement"), (IfStatement, "if statement"), (WhileStatement, "while statement"), (DoStatement, "do statement"),
371         (ForStatement, "for statement"), (ForInitStatement, "for initialization statement"), (ForLoopStatementExpr, "for loop expression"),
372         (RangeForStatement, "range for statement"), (BreakStatement, "break statement"), (ContinueStatement, "continue statement"), (GotoStatement, "goto statement"),
373         (SwitchStatement, "switch statement"), (CaseStatement, "case statement"), (DefaultStatement, "default statement"), (GotoCaseStatement, "goto case statement"),
374         (GotoDefaultStatement, "goto default statement"), (AssignmentStatementExpr, "assignment expression"), (AssignmentStatement, "assignment statement"),
375         (ConstructionStatement, "construction statement"), (DeleteStatement, "delete statement"), (DestroyStatement, "destroy statement"), (ExpressionStatement, "expression statement"),
376         (EmptyStatement, "empty statement"), (ThrowStatement, "throw statement"), (TryStatement, "try statement"), (Catch, "catch statement"), (AssertStatement, "assert statement"),
377         (ConditionalCompilationStatement, "conditional compilation statement"), (ConditionalCompilationExpression, "conditional compilation expression"),
378         (ConditionalCompilationDisjunction, "conditional compilation disjunction"), (ConditionalCompilationConjunction, "conditional compilation conjunction"),
379         (ConditionalCompilationPrefix, "conditional compilation prefix expression"), (ConditionalCompilationPrimary, "conditional compilation primary expression")
380     }
381 }