source: src/Parser/StatementNode.cc@ fb4dc28

ADT ast-experimental
Last change on this file since fb4dc28 was 32d6fdc, checked in by Andrew Beach <ajbeach@…>, 2 years ago

Clean-up in the parser %union.

  • Property mode set to 100644
File size: 15.1 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.cc -- 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 : Andrew Beach
13// Last Modified On : Tue Apr 11 10:16:00 2023
14// Update Count : 428
15//
16
17#include "StatementNode.h"
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.h" // for SemanticError
26#include "Common/utility.h" // for maybeMoveBuild, maybeBuild
27#include "DeclarationNode.h" // for DeclarationNode
28#include "ExpressionNode.h" // for ExpressionNode
29#include "parserutility.h" // 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 set_next( nextStmt );
57 if ( decl->get_next() ) {
58 get_next()->set_next( new StatementNode( dynamic_cast< DeclarationNode * >(decl->get_next()) ) );
59 decl->set_next( 0 );
60 } // if
61 } else {
62 if ( decl->get_next() ) {
63 set_next( new StatementNode( dynamic_cast< DeclarationNode * >( decl->get_next() ) ) );
64 decl->set_next( 0 );
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 = (ClauseNode *)curr->get_next() ) {
90 ClauseNode * node = strict_dynamic_cast< ClauseNode * >(curr);
91 assert( dynamic_cast<ast::CaseClause *>( node->clause.get() ) );
92 prev = curr;
93 } // for
94 ClauseNode * node = dynamic_cast< ClauseNode * >(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 // compare the provided condition against 0
125 cond = notZeroExpr( maybeMoveBuild( ctl->condition ) );
126 } else {
127 for ( ast::ptr<ast::Stmt> & stmt : inits ) {
128 // build the && of all of the declared variables compared against 0
129 auto declStmt = stmt.strict_as<ast::DeclStmt>();
130 auto dwt = declStmt->decl.strict_as<ast::DeclWithType>();
131 ast::Expr * nze = notZeroExpr( new ast::VariableExpr( dwt->location, dwt ) );
132 cond = cond ? new ast::LogicalExpr( dwt->location, cond, nze, ast::AndExpr ) : nze;
133 }
134 }
135 delete ctl;
136 return cond;
137} // build_if_control
138
139ast::Stmt * build_if( const CodeLocation & location, CondCtl * ctl, StatementNode * then, StatementNode * else_ ) {
140 std::vector<ast::ptr<ast::Stmt>> astinit; // maybe empty
141 ast::Expr * astcond = build_if_control( ctl, astinit ); // ctl deleted, cond/init set
142
143 ast::Stmt const * astthen = buildMoveSingle( then );
144 ast::Stmt const * astelse = buildMoveOptional( else_ );
145
146 return new ast::IfStmt( location, astcond, astthen, astelse,
147 std::move( astinit )
148 );
149} // build_if
150
151ast::Stmt * build_switch( const CodeLocation & location, bool isSwitch, ExpressionNode * ctl, ClauseNode * stmt ) {
152 std::vector<ast::ptr<ast::CaseClause>> aststmt;
153 buildMoveList( stmt, aststmt );
154 // If it is not a switch it is a choose statement.
155 if ( ! isSwitch ) {
156 for ( ast::ptr<ast::CaseClause> & stmt : aststmt ) {
157 // Code after "case" is the end of case list.
158 if ( !stmt->stmts.empty() ) {
159 auto mutStmt = ast::mutate( stmt.get() );
160 // I believe the stmts are actually always one block.
161 auto stmts = mutStmt->stmts.front().get_and_mutate();
162 auto block = strict_dynamic_cast<ast::CompoundStmt *>( stmts );
163 block->kids.push_back( new ast::BranchStmt( block->location,
164 ast::BranchStmt::Break,
165 ast::Label( block->location ) ) );
166 stmt = mutStmt;
167 } // if
168 } // for
169 } // if
170 // aststmt.size() == 0 for switch (...) {}, i.e., no declaration or statements
171 return new ast::SwitchStmt( location,
172 maybeMoveBuild( ctl ), std::move( aststmt ) );
173} // build_switch
174
175ast::CaseClause * build_case( const CodeLocation & location, ExpressionNode * ctl ) {
176 // stmt starts empty and then added to
177 auto expr = maybeMoveBuild( ctl );
178 return new ast::CaseClause( location, expr, {} );
179} // build_case
180
181ast::CaseClause * build_default( const CodeLocation & location ) {
182 // stmt starts empty and then added to
183 return new ast::CaseClause( location, nullptr, {} );
184} // build_default
185
186ast::Stmt * build_while( const CodeLocation & location, CondCtl * ctl, StatementNode * stmt, StatementNode * else_ ) {
187 std::vector<ast::ptr<ast::Stmt>> astinit; // maybe empty
188 ast::Expr * astcond = build_if_control( ctl, astinit ); // ctl deleted, cond/init set
189
190 return new ast::WhileDoStmt( location,
191 astcond,
192 buildMoveSingle( stmt ),
193 buildMoveOptional( else_ ),
194 std::move( astinit ),
195 ast::While
196 );
197} // build_while
198
199ast::Stmt * build_do_while( const CodeLocation & location, ExpressionNode * ctl, StatementNode * stmt, StatementNode * else_ ) {
200 // do-while cannot have declarations in the contitional, so init is always empty
201 return new ast::WhileDoStmt( location,
202 notZeroExpr( maybeMoveBuild( ctl ) ),
203 buildMoveSingle( stmt ),
204 buildMoveOptional( else_ ),
205 {},
206 ast::DoWhile
207 );
208} // build_do_while
209
210ast::Stmt * build_for( const CodeLocation & location, ForCtrl * forctl, StatementNode * stmt, StatementNode * else_ ) {
211 std::vector<ast::ptr<ast::Stmt>> astinit; // maybe empty
212 buildMoveList( forctl->init, astinit );
213
214 ast::Expr * astcond = nullptr; // maybe empty
215 astcond = notZeroExpr( maybeMoveBuild( forctl->condition ) );
216
217 ast::Expr * astincr = nullptr; // maybe empty
218 astincr = maybeMoveBuild( forctl->change );
219 delete forctl;
220
221 return new ast::ForStmt( location,
222 std::move( astinit ),
223 astcond,
224 astincr,
225 buildMoveSingle( stmt ),
226 buildMoveOptional( else_ )
227 );
228} // build_for
229
230ast::Stmt * build_branch( const CodeLocation & location, ast::BranchStmt::Kind kind ) {
231 return new ast::BranchStmt( location,
232 kind,
233 ast::Label( location )
234 );
235} // build_branch
236
237ast::Stmt * build_branch( const CodeLocation & location, string * identifier, ast::BranchStmt::Kind kind ) {
238 ast::Stmt * ret = new ast::BranchStmt( location,
239 kind,
240 ast::Label( location, *identifier )
241 );
242 delete identifier; // allocated by lexer
243 return ret;
244} // build_branch
245
246ast::Stmt * build_computedgoto( ExpressionNode * ctl ) {
247 ast::Expr * expr = maybeMoveBuild( ctl );
248 return new ast::BranchStmt( expr->location, expr );
249} // build_computedgoto
250
251ast::Stmt * build_return( const CodeLocation & location, ExpressionNode * ctl ) {
252 std::vector<ast::ptr<ast::Expr>> exps;
253 buildMoveList( ctl, exps );
254 return new ast::ReturnStmt( location,
255 exps.size() > 0 ? exps.back().release() : nullptr
256 );
257} // build_return
258
259static ast::Stmt * build_throw_stmt(
260 const CodeLocation & location,
261 ExpressionNode * ctl,
262 ast::ExceptionKind kind ) {
263 std::vector<ast::ptr<ast::Expr>> exps;
264 buildMoveList( ctl, exps );
265 assertf( exps.size() < 2, "CFA internal error: leaking memory" );
266 return new ast::ThrowStmt( location,
267 kind,
268 !exps.empty() ? exps.back().release() : nullptr,
269 (ast::Expr *)nullptr
270 );
271}
272
273ast::Stmt * build_throw( const CodeLocation & loc, ExpressionNode * ctl ) {
274 return build_throw_stmt( loc, ctl, ast::Terminate );
275} // build_throw
276
277ast::Stmt * build_resume( const CodeLocation & loc, ExpressionNode * ctl ) {
278 return build_throw_stmt( loc, ctl, ast::Resume );
279} // build_resume
280
281ast::Stmt * build_resume_at( ExpressionNode * ctl, ExpressionNode * target ) {
282 (void)ctl;
283 (void)target;
284 assertf( false, "resume at (non-local throw) is not yet supported," );
285} // build_resume_at
286
287ast::Stmt * build_try( const CodeLocation & location, StatementNode * try_, ClauseNode * catch_, ClauseNode * finally_ ) {
288 std::vector<ast::ptr<ast::CatchClause>> aststmt;
289 buildMoveList( catch_, aststmt );
290 ast::CompoundStmt * tryBlock = strict_dynamic_cast<ast::CompoundStmt *>( maybeMoveBuild( try_ ) );
291 ast::FinallyClause * finallyBlock = nullptr;
292 if ( finally_ ) {
293 finallyBlock = dynamic_cast<ast::FinallyClause *>( finally_->clause.release() );
294 }
295 return new ast::TryStmt( location,
296 tryBlock,
297 std::move( aststmt ),
298 finallyBlock
299 );
300} // build_try
301
302ast::CatchClause * build_catch( const CodeLocation & location, ast::ExceptionKind kind, DeclarationNode * decl, ExpressionNode * cond, StatementNode * body ) {
303 return new ast::CatchClause( location,
304 kind,
305 maybeMoveBuild( decl ),
306 maybeMoveBuild( cond ),
307 buildMoveSingle( body )
308 );
309} // build_catch
310
311ast::FinallyClause * build_finally( const CodeLocation & location, StatementNode * stmt ) {
312 return new ast::FinallyClause( location,
313 strict_dynamic_cast<const ast::CompoundStmt *>(
314 buildMoveSingle( stmt )
315 )
316 );
317} // build_finally
318
319ast::SuspendStmt * build_suspend( const CodeLocation & location, StatementNode * then, ast::SuspendStmt::Kind kind ) {
320 return new ast::SuspendStmt( location,
321 strict_dynamic_cast<const ast::CompoundStmt *, nullptr>(
322 buildMoveOptional( then )
323 ),
324 kind
325 );
326} // build_suspend
327
328ast::WaitForStmt * build_waitfor( const CodeLocation & location, ast::WaitForStmt * existing, ExpressionNode * when, ExpressionNode * targetExpr, StatementNode * stmt ) {
329 auto clause = new ast::WaitForClause( location );
330 clause->target_func = maybeBuild( targetExpr );
331 clause->stmt = maybeMoveBuild( stmt );
332 clause->cond = notZeroExpr( maybeMoveBuild( when ) );
333
334 ExpressionNode * next = dynamic_cast<ExpressionNode *>( targetExpr->get_next() );
335 targetExpr->set_next( nullptr );
336 buildMoveList( next, clause->target_args );
337
338 delete targetExpr;
339
340 existing->clauses.insert( existing->clauses.begin(), clause );
341
342 return existing;
343} // build_waitfor
344
345ast::WaitForStmt * build_waitfor_else( const CodeLocation & location, ast::WaitForStmt * existing, ExpressionNode * when, StatementNode * stmt ) {
346 existing->else_stmt = maybeMoveBuild( stmt );
347 existing->else_cond = notZeroExpr( maybeMoveBuild( when ) );
348
349 (void)location;
350 return existing;
351} // build_waitfor_else
352
353ast::WaitForStmt * build_waitfor_timeout( const CodeLocation & location, ast::WaitForStmt * existing, ExpressionNode * when, ExpressionNode * timeout, StatementNode * stmt ) {
354 existing->timeout_time = maybeMoveBuild( timeout );
355 existing->timeout_stmt = maybeMoveBuild( stmt );
356 existing->timeout_cond = notZeroExpr( maybeMoveBuild( when ) );
357
358 (void)location;
359 return existing;
360} // build_waitfor_timeout
361
362ast::Stmt * build_with( const CodeLocation & location, ExpressionNode * exprs, StatementNode * stmt ) {
363 std::vector<ast::ptr<ast::Expr>> e;
364 buildMoveList( exprs, e );
365 ast::Stmt * s = maybeMoveBuild( stmt );
366 return new ast::DeclStmt( location, new ast::WithStmt( location, std::move( e ), s ) );
367} // build_with
368
369ast::Stmt * build_compound( const CodeLocation & location, StatementNode * first ) {
370 auto cs = new ast::CompoundStmt( location );
371 buildMoveList( first, cs->kids );
372 return cs;
373} // build_compound
374
375// A single statement in a control structure is always converted to a compound statement so subsequent generated code
376// can be placed within this compound statement. Otherwise, code generation has to constantly check for a single
377// statement and wrap it into a compound statement to insert additional code. Hence, all control structures have a
378// conical form for code generation.
379StatementNode * maybe_build_compound( const CodeLocation & location, StatementNode * first ) {
380 // Optimization: if the control-structure statement is a compound statement, do not wrap it.
381 // e.g., if (...) {...} do not wrap the existing compound statement.
382 if ( !dynamic_cast<ast::CompoundStmt *>( first->stmt.get() ) ) { // unique_ptr
383 return new StatementNode( build_compound( location, first ) );
384 } // if
385 return first;
386} // maybe_build_compound
387
388// Question
389ast::Stmt * build_asm( const CodeLocation & location, bool is_volatile, ExpressionNode * instruction, ExpressionNode * output, ExpressionNode * input, ExpressionNode * clobber, LabelNode * gotolabels ) {
390 std::vector<ast::ptr<ast::Expr>> out, in;
391 std::vector<ast::ptr<ast::ConstantExpr>> clob;
392
393 buildMoveList( output, out );
394 buildMoveList( input, in );
395 buildMoveList( clobber, clob );
396 return new ast::AsmStmt( location,
397 is_volatile,
398 maybeMoveBuild( instruction ),
399 std::move( out ),
400 std::move( in ),
401 std::move( clob ),
402 gotolabels ? gotolabels->labels : std::vector<ast::Label>()
403 );
404} // build_asm
405
406ast::Stmt * build_directive( const CodeLocation & location, string * directive ) {
407 auto stmt = new ast::DirectiveStmt( location, *directive );
408 delete directive;
409 return stmt;
410} // build_directive
411
412ast::Stmt * build_mutex( const CodeLocation & location, ExpressionNode * exprs, StatementNode * stmt ) {
413 std::vector<ast::ptr<ast::Expr>> expList;
414 buildMoveList( exprs, expList );
415 ast::Stmt * body = maybeMoveBuild( stmt );
416 return new ast::MutexStmt( location, body, std::move( expList ) );
417} // build_mutex
418
419// Local Variables: //
420// tab-width: 4 //
421// mode: c++ //
422// compile-command: "make install" //
423// End: //
Note: See TracBrowser for help on using the repository browser.