source: src/Parser/StatementNode.cpp@ 115ac1ce

Last change on this file since 115ac1ce was d3aa55e9, checked in by JiadaL <j82liang@…>, 15 months ago
  1. Disallow implicit conversion from cfa enum to int during on the function call site; 2. implement the reverse enum loop
  • Property mode set to 100644
File size: 18.5 KB
Line 
1//
2// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
3//
4// The contents of this file are covered under the licence agreement in the
5// file "LICENCE" distributed with Cforall.
6//
7// StatementNode.cpp -- Transform from parse data-structures to AST data-structures, usually deleting the parse
8// data-structure after the transformation.
9//
10// Author : Rodolfo G. Esteves
11// Created On : Sat May 16 14:59:41 2015
12// Last Modified By : Peter A. Buhr
13// Last Modified On : Fri Aug 11 11:44:15 2023
14// Update Count : 429
15//
16
17#include "StatementNode.hpp"
18
19#include <cassert> // for assert, strict_dynamic_cast, assertf
20#include <memory> // for unique_ptr
21#include <string> // for string
22
23#include "AST/Label.hpp" // for Label
24#include "AST/Stmt.hpp" // for Stmt, AsmStmt, BranchStmt, CaseCla...
25#include "Common/SemanticError.hpp"// for SemanticError
26#include "Common/Utility.hpp" // for maybeMoveBuild, maybeBuild
27#include "DeclarationNode.hpp" // for DeclarationNode
28#include "ExpressionNode.hpp" // for ExpressionNode
29#include "ParserUtility.hpp" // for notZeroExpr
30
31class Declaration;
32
33using namespace std;
34
35// Some helpers for cases that really want a single node but check for lists.
36static const ast::Stmt * buildMoveSingle( StatementNode * node ) {
37 std::vector<ast::ptr<ast::Stmt>> list;
38 buildMoveList( node, list );
39 assertf( list.size() == 1, "CFA Internal Error: Extra/Missing Nodes" );
40 return list.front().release();
41}
42
43static const ast::Stmt * buildMoveOptional( StatementNode * node ) {
44 std::vector<ast::ptr<ast::Stmt>> list;
45 buildMoveList( node, list );
46 assertf( list.size() <= 1, "CFA Internal Error: Extra Nodes" );
47 return list.empty() ? nullptr : list.front().release();
48}
49
50StatementNode::StatementNode( DeclarationNode * decl ) {
51 assert( decl );
52 DeclarationNode * agg = decl->extractAggregate();
53 if ( agg ) {
54 StatementNode * nextStmt = new StatementNode(
55 new ast::DeclStmt( decl->location, maybeBuild( decl ) ) );
56 next = nextStmt;
57 if ( decl->next ) {
58 next->next = new StatementNode( decl->next );
59 decl->next = nullptr;
60 } // if
61 } else {
62 if ( decl->next ) {
63 next = new StatementNode( decl->next );
64 decl->next = nullptr;
65 } // if
66 agg = decl;
67 } // if
68 // Local copy to avoid accessing the pointer after it is moved from.
69 CodeLocation declLocation = agg->location;
70 stmt.reset( new ast::DeclStmt( declLocation, maybeMoveBuild( agg ) ) );
71} // StatementNode::StatementNode
72
73StatementNode * StatementNode::add_label(
74 const CodeLocation & location,
75 const std::string * name,
76 DeclarationNode * attr ) {
77 stmt->labels.emplace_back( location,
78 *name,
79 attr ? std::move( attr->attributes )
80 : std::vector<ast::ptr<ast::Attribute>>{} );
81 delete attr;
82 delete name;
83 return this;
84}
85
86ClauseNode * ClauseNode::append_last_case( StatementNode * stmt ) {
87 ClauseNode * prev = this;
88 // find end of list and maintain previous pointer
89 for ( ClauseNode * curr = prev; curr != nullptr; curr = curr->next ) {
90 ClauseNode * node = curr;
91 assert( dynamic_cast<ast::CaseClause *>( node->clause.get() ) );
92 prev = curr;
93 } // for
94 ClauseNode * node = prev;
95 // convert from StatementNode list to Statement list
96 std::vector<ast::ptr<ast::Stmt>> stmts;
97 buildMoveList( stmt, stmts );
98 // splice any new Statements to end of current Statements
99 auto caseStmt = strict_dynamic_cast<ast::CaseClause *>( node->clause.get() );
100 for ( auto const & newStmt : stmts ) {
101 caseStmt->stmts.emplace_back( newStmt );
102 }
103 stmts.clear();
104 return this;
105} // ClauseNode::append_last_case
106
107ast::Stmt * build_expr( CodeLocation const & location, ExpressionNode * ctl ) {
108 if ( ast::Expr * e = maybeMoveBuild( ctl ) ) {
109 return new ast::ExprStmt( location, e );
110 } else {
111 return new ast::NullStmt( location );
112 }
113} // build_expr
114
115static ast::Expr * build_if_control( CondCtl * ctl,
116 std::vector<ast::ptr<ast::Stmt>> & inits ) {
117 assert( inits.empty() );
118 if ( nullptr != ctl->init ) {
119 buildMoveList( ctl->init, inits );
120 } // if
121
122 ast::Expr * cond = nullptr;
123 if ( ctl->condition ) {
124 cond = maybeMoveBuild( ctl->condition );
125 } else {
126 for ( ast::ptr<ast::Stmt> & stmt : inits ) {
127 // build the && of all of the declared variables compared against 0
128 auto declStmt = stmt.strict_as<ast::DeclStmt>();
129 auto dwt = declStmt->decl.strict_as<ast::DeclWithType>();
130 ast::Expr * nze = new ast::VariableExpr( dwt->location, dwt );
131 cond = cond ? new ast::LogicalExpr( dwt->location, cond, nze, ast::AndExpr ) : nze;
132 }
133 }
134 delete ctl;
135 return cond;
136} // build_if_control
137
138ast::Stmt * build_if( const CodeLocation & location, CondCtl * ctl, StatementNode * then, StatementNode * else_ ) {
139 std::vector<ast::ptr<ast::Stmt>> astinit; // maybe empty
140 ast::Expr * astcond = build_if_control( ctl, astinit ); // ctl deleted, cond/init set
141
142 ast::Stmt const * astthen = buildMoveSingle( then );
143 ast::Stmt const * astelse = buildMoveOptional( else_ );
144
145 return new ast::IfStmt( location, astcond, astthen, astelse,
146 std::move( astinit )
147 );
148} // build_if
149
150ast::Stmt * build_switch( const CodeLocation & location, bool isSwitch, ExpressionNode * ctl, ClauseNode * stmt ) {
151 std::vector<ast::ptr<ast::CaseClause>> aststmt;
152 buildMoveList( stmt, aststmt );
153 // If it is not a switch it is a choose statement.
154 if ( ! isSwitch ) {
155 for ( ast::ptr<ast::CaseClause> & stmt : aststmt ) {
156 // Code after "case" is the end of case list.
157 if ( !stmt->stmts.empty() ) {
158 auto mutStmt = ast::mutate( stmt.get() );
159 // I believe the stmts are actually always one block.
160 auto stmts = mutStmt->stmts.front().get_and_mutate();
161 auto block = strict_dynamic_cast<ast::CompoundStmt *>( stmts );
162 block->kids.push_back( new ast::BranchStmt( block->location,
163 ast::BranchStmt::Break,
164 ast::Label( block->location ) ) );
165 stmt = mutStmt;
166 } // if
167 } // for
168 } // if
169 // aststmt.size() == 0 for switch (...) {}, i.e., no declaration or statements
170 return new ast::SwitchStmt( location,
171 maybeMoveBuild( ctl ), std::move( aststmt ) );
172} // build_switch
173
174ast::CaseClause * build_case( const CodeLocation & location, ExpressionNode * ctl ) {
175 // stmt starts empty and then added to
176 auto expr = maybeMoveBuild( ctl );
177 return new ast::CaseClause( location, expr, {} );
178} // build_case
179
180ast::CaseClause * build_default( const CodeLocation & location ) {
181 // stmt starts empty and then added to
182 return new ast::CaseClause( location, nullptr, {} );
183} // build_default
184
185ast::Stmt * build_while( const CodeLocation & location, CondCtl * ctl, StatementNode * stmt, StatementNode * else_ ) {
186 std::vector<ast::ptr<ast::Stmt>> astinit; // maybe empty
187 ast::Expr * astcond = build_if_control( ctl, astinit ); // ctl deleted, cond/init set
188
189 return new ast::WhileDoStmt( location,
190 astcond,
191 buildMoveSingle( stmt ),
192 buildMoveOptional( else_ ),
193 std::move( astinit ),
194 ast::While
195 );
196} // build_while
197
198ast::Stmt * build_do_while( const CodeLocation & location, ExpressionNode * ctl, StatementNode * stmt, StatementNode * else_ ) {
199 // do-while cannot have declarations in the contitional, so init is always empty
200 return new ast::WhileDoStmt( location,
201 maybeMoveBuild( ctl ),
202 buildMoveSingle( stmt ),
203 buildMoveOptional( else_ ),
204 {},
205 ast::DoWhile
206 );
207} // build_do_while
208
209ast::Stmt * build_for( const CodeLocation & location, ForCtrl * forctl, StatementNode * stmt, StatementNode * else_ ) {
210 std::vector<ast::ptr<ast::Stmt>> astinit; // maybe empty
211 buildMoveList( forctl->init, astinit );
212
213 if ( forctl->range_over ) {
214 ast::Expr * range_over = maybeMoveBuild( forctl->range_over );
215 delete forctl;
216 return new ast::ForStmt( location,
217 std::move( astinit ),
218 range_over, forctl->kind == OperKinds::LThan,
219 buildMoveSingle( stmt ),
220 buildMoveOptional( else_ )
221 );
222 }
223
224 ast::Expr * astcond = nullptr; // maybe empty
225 astcond = maybeMoveBuild( forctl->condition );
226
227 ast::Expr * astincr = nullptr; // maybe empty
228 astincr = maybeMoveBuild( forctl->change );
229 delete forctl;
230
231 return new ast::ForStmt( location,
232 std::move( astinit ),
233 astcond,
234 astincr,
235 buildMoveSingle( stmt ),
236 buildMoveOptional( else_ )
237 );
238} // build_for
239
240ast::Stmt * build_branch( const CodeLocation & location, ast::BranchStmt::Kind kind ) {
241 return new ast::BranchStmt( location,
242 kind,
243 ast::Label( location )
244 );
245} // build_branch
246
247ast::Stmt * build_branch( const CodeLocation & location, string * identifier, ast::BranchStmt::Kind kind ) {
248 ast::Stmt * ret = new ast::BranchStmt( location,
249 kind,
250 ast::Label( location, *identifier )
251 );
252 delete identifier; // allocated by lexer
253 return ret;
254} // build_branch
255
256ast::Stmt * build_computedgoto( ExpressionNode * ctl ) {
257 ast::Expr * expr = maybeMoveBuild( ctl );
258 return new ast::BranchStmt( expr->location, expr );
259} // build_computedgoto
260
261ast::Stmt * build_return( const CodeLocation & location, ExpressionNode * ctl ) {
262 std::vector<ast::ptr<ast::Expr>> exps;
263 buildMoveList( ctl, exps );
264 return new ast::ReturnStmt( location,
265 exps.size() > 0 ? exps.back().release() : nullptr
266 );
267} // build_return
268
269static ast::Stmt * build_throw_stmt(
270 const CodeLocation & location,
271 ExpressionNode * ctl,
272 ast::ExceptionKind kind ) {
273 std::vector<ast::ptr<ast::Expr>> exps;
274 buildMoveList( ctl, exps );
275 assertf( exps.size() < 2, "CFA internal error: leaking memory" );
276 return new ast::ThrowStmt( location,
277 kind,
278 !exps.empty() ? exps.back().release() : nullptr,
279 (ast::Expr *)nullptr
280 );
281}
282
283ast::Stmt * build_throw( const CodeLocation & loc, ExpressionNode * ctl ) {
284 return build_throw_stmt( loc, ctl, ast::Terminate );
285} // build_throw
286
287ast::Stmt * build_resume( const CodeLocation & loc, ExpressionNode * ctl ) {
288 return build_throw_stmt( loc, ctl, ast::Resume );
289} // build_resume
290
291ast::Stmt * build_resume_at( ExpressionNode * ctl, ExpressionNode * target ) {
292 (void)ctl;
293 (void)target;
294 assertf( false, "resume at (non-local throw) is not yet supported," );
295} // build_resume_at
296
297ast::Stmt * build_try( const CodeLocation & location, StatementNode * try_, ClauseNode * catch_, ClauseNode * finally_ ) {
298 std::vector<ast::ptr<ast::CatchClause>> aststmt;
299 buildMoveList( catch_, aststmt );
300 ast::CompoundStmt * tryBlock = strict_dynamic_cast<ast::CompoundStmt *>( maybeMoveBuild( try_ ) );
301 ast::FinallyClause * finallyBlock = nullptr;
302 if ( finally_ ) {
303 finallyBlock = dynamic_cast<ast::FinallyClause *>( finally_->clause.release() );
304 }
305 return new ast::TryStmt( location,
306 tryBlock,
307 std::move( aststmt ),
308 finallyBlock
309 );
310} // build_try
311
312ast::CatchClause * build_catch( const CodeLocation & location, ast::ExceptionKind kind, DeclarationNode * decl, ExpressionNode * cond, StatementNode * body ) {
313 return new ast::CatchClause( location,
314 kind,
315 maybeMoveBuild( decl ),
316 maybeMoveBuild( cond ),
317 buildMoveSingle( body )
318 );
319} // build_catch
320
321ast::FinallyClause * build_finally( const CodeLocation & location, StatementNode * stmt ) {
322 return new ast::FinallyClause( location,
323 strict_dynamic_cast<const ast::CompoundStmt *>(
324 buildMoveSingle( stmt )
325 )
326 );
327} // build_finally
328
329ast::SuspendStmt * build_suspend( const CodeLocation & location, StatementNode * then, ast::SuspendStmt::Kind kind ) {
330 return new ast::SuspendStmt( location,
331 strict_dynamic_cast<const ast::CompoundStmt *, nullptr>(
332 buildMoveOptional( then )
333 ),
334 kind
335 );
336} // build_suspend
337
338ast::WaitForStmt * build_waitfor( const CodeLocation & location, ast::WaitForStmt * existing, ExpressionNode * when, ExpressionNode * targetExpr, StatementNode * stmt ) {
339 auto clause = new ast::WaitForClause( location );
340 clause->target = maybeBuild( targetExpr );
341 clause->stmt = maybeMoveBuild( stmt );
342 clause->when_cond = maybeMoveBuild( when );
343
344 ExpressionNode * next = targetExpr->next;
345 targetExpr->next = nullptr;
346 buildMoveList( next, clause->target_args );
347
348 delete targetExpr;
349
350 existing->clauses.insert( existing->clauses.begin(), clause );
351
352 return existing;
353} // build_waitfor
354
355ast::WaitForStmt * build_waitfor_else( const CodeLocation & location, ast::WaitForStmt * existing, ExpressionNode * when, StatementNode * stmt ) {
356 existing->else_stmt = maybeMoveBuild( stmt );
357 existing->else_cond = maybeMoveBuild( when );
358
359 (void)location;
360 return existing;
361} // build_waitfor_else
362
363ast::WaitForStmt * build_waitfor_timeout( const CodeLocation & location, ast::WaitForStmt * existing, ExpressionNode * when, ExpressionNode * timeout, StatementNode * stmt ) {
364 existing->timeout_time = maybeMoveBuild( timeout );
365 existing->timeout_stmt = maybeMoveBuild( stmt );
366 existing->timeout_cond = maybeMoveBuild( when );
367
368 (void)location;
369 return existing;
370} // build_waitfor_timeout
371
372ast::WaitUntilStmt::ClauseNode * build_waituntil_clause( const CodeLocation & loc, ExpressionNode * when, ExpressionNode * targetExpr, StatementNode * stmt ) {
373 ast::WhenClause * clause = new ast::WhenClause( loc );
374 clause->when_cond = maybeMoveBuild( when );
375 clause->stmt = maybeMoveBuild( stmt );
376 clause->target = maybeMoveBuild( targetExpr );
377 return new ast::WaitUntilStmt::ClauseNode( clause );
378}
379ast::WaitUntilStmt::ClauseNode * build_waituntil_else( const CodeLocation & loc, ExpressionNode * when, StatementNode * stmt ) {
380 ast::WhenClause * clause = new ast::WhenClause( loc );
381 clause->when_cond = maybeMoveBuild( when );
382 clause->stmt = maybeMoveBuild( stmt );
383 return new ast::WaitUntilStmt::ClauseNode( ast::WaitUntilStmt::ClauseNode::Op::ELSE, clause );
384}
385
386ast::WaitUntilStmt * build_waituntil_stmt( const CodeLocation & loc, ast::WaitUntilStmt::ClauseNode * root ) {
387 ast::WaitUntilStmt * retStmt = new ast::WaitUntilStmt( loc );
388 retStmt->predicateTree = root;
389
390 // iterative tree traversal
391 std::vector<ast::WaitUntilStmt::ClauseNode *> nodeStack; // stack needed for iterative traversal
392 ast::WaitUntilStmt::ClauseNode * currNode = nullptr;
393 ast::WaitUntilStmt::ClauseNode * lastInternalNode = nullptr;
394 ast::WaitUntilStmt::ClauseNode * cleanup = nullptr; // used to cleanup removed else/timeout
395 nodeStack.push_back(root);
396
397 do {
398 currNode = nodeStack.back();
399 nodeStack.pop_back(); // remove node since it will be processed
400
401 switch (currNode->op) {
402 case ast::WaitUntilStmt::ClauseNode::LEAF:
403 retStmt->clauses.push_back(currNode->leaf);
404 break;
405 case ast::WaitUntilStmt::ClauseNode::ELSE:
406 retStmt->else_stmt = currNode->leaf->stmt
407 ? ast::deepCopy( currNode->leaf->stmt )
408 : nullptr;
409 retStmt->else_cond = currNode->leaf->when_cond
410 ? ast::deepCopy( currNode->leaf->when_cond )
411 : nullptr;
412
413 delete currNode->leaf;
414 break;
415 case ast::WaitUntilStmt::ClauseNode::TIMEOUT:
416 retStmt->timeout_time = currNode->leaf->target
417 ? ast::deepCopy( currNode->leaf->target )
418 : nullptr;
419 retStmt->timeout_stmt = currNode->leaf->stmt
420 ? ast::deepCopy( currNode->leaf->stmt )
421 : nullptr;
422 retStmt->timeout_cond = currNode->leaf->when_cond
423 ? ast::deepCopy( currNode->leaf->when_cond )
424 : nullptr;
425
426 delete currNode->leaf;
427 break;
428 default:
429 nodeStack.push_back( currNode->right ); // process right after left
430 nodeStack.push_back( currNode->left );
431
432 // Cut else/timeout out of the tree
433 if ( currNode->op == ast::WaitUntilStmt::ClauseNode::LEFT_OR ) {
434 if ( lastInternalNode )
435 lastInternalNode->right = currNode->left;
436 else // if not set then root is LEFT_OR
437 retStmt->predicateTree = currNode->left;
438
439 currNode->left = nullptr;
440 cleanup = currNode;
441 }
442
443 lastInternalNode = currNode;
444 break;
445 }
446 } while ( !nodeStack.empty() );
447
448 if ( cleanup ) delete cleanup;
449
450 return retStmt;
451}
452
453ast::Stmt * build_with( const CodeLocation & location, ExpressionNode * exprs, StatementNode * stmt ) {
454 std::vector<ast::ptr<ast::Expr>> e;
455 buildMoveList( exprs, e );
456 ast::Stmt * s = maybeMoveBuild( stmt );
457 return new ast::DeclStmt( location, new ast::WithStmt( location, std::move( e ), s ) );
458} // build_with
459
460ast::Stmt * build_compound( const CodeLocation & location, StatementNode * first ) {
461 auto cs = new ast::CompoundStmt( location );
462 buildMoveList( first, cs->kids );
463 return cs;
464} // build_compound
465
466// A single statement in a control structure is always converted to a compound statement so subsequent generated code
467// can be placed within this compound statement. Otherwise, code generation has to constantly check for a single
468// statement and wrap it into a compound statement to insert additional code. Hence, all control structures have a
469// conical form for code generation.
470StatementNode * maybe_build_compound( const CodeLocation & location, StatementNode * first ) {
471 // Optimization: if the control-structure statement is a compound statement, do not wrap it.
472 // e.g., if (...) {...} do not wrap the existing compound statement.
473 if ( !dynamic_cast<ast::CompoundStmt *>( first->stmt.get() ) ) { // unique_ptr
474 return new StatementNode( build_compound( location, first ) );
475 } // if
476 return first;
477} // maybe_build_compound
478
479// Question
480ast::Stmt * build_asm( const CodeLocation & location, bool is_volatile, ExpressionNode * instruction, ExpressionNode * output, ExpressionNode * input, ExpressionNode * clobber, LabelNode * gotolabels ) {
481 std::vector<ast::ptr<ast::Expr>> out, in;
482 std::vector<ast::ptr<ast::ConstantExpr>> clob;
483
484 buildMoveList( output, out );
485 buildMoveList( input, in );
486 buildMoveList( clobber, clob );
487 return new ast::AsmStmt( location,
488 is_volatile,
489 maybeMoveBuild( instruction ),
490 std::move( out ),
491 std::move( in ),
492 std::move( clob ),
493 gotolabels ? gotolabels->labels : std::vector<ast::Label>()
494 );
495} // build_asm
496
497ast::Stmt * build_directive( const CodeLocation & location, string * directive ) {
498 auto stmt = new ast::DirectiveStmt( location, *directive );
499 delete directive;
500 return stmt;
501} // build_directive
502
503ast::Stmt * build_mutex( const CodeLocation & location, ExpressionNode * exprs, StatementNode * stmt ) {
504 std::vector<ast::ptr<ast::Expr>> expList;
505 buildMoveList( exprs, expList );
506 ast::Stmt * body = maybeMoveBuild( stmt );
507 return new ast::MutexStmt( location, body, std::move( expList ) );
508} // build_mutex
509
510ast::Stmt * build_corun( const CodeLocation & location, StatementNode * stmt ) {
511 ast::Stmt * body = maybeMoveBuild( stmt );
512 return new ast::CorunStmt( location, body );
513} // build_corun
514
515ast::Stmt * build_cofor( const CodeLocation & location, ForCtrl * forctl, StatementNode * stmt ) {
516 std::vector<ast::ptr<ast::Stmt>> astinit; // maybe empty
517 buildMoveList( forctl->init, astinit );
518
519 ast::Expr * astcond = nullptr; // maybe empty
520 astcond = maybeMoveBuild( forctl->condition );
521
522 ast::Expr * astincr = nullptr; // maybe empty
523 astincr = maybeMoveBuild( forctl->change );
524 delete forctl;
525
526 return new ast::CoforStmt( location,
527 std::move( astinit ),
528 astcond,
529 astincr,
530 buildMoveSingle( stmt )
531 );
532} // build_cofor
533
534// Local Variables: //
535// tab-width: 4 //
536// mode: c++ //
537// compile-command: "make install" //
538// End: //
Note: See TracBrowser for help on using the repository browser.