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