source: src/Parser/StatementNode.cc@ bb7422a

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

Translated parser to the new ast. This incuded a small fix in the resolver so larger expressions can be used in with statements and some updated tests. errors/declaration just is a formatting update. attributes now actually preserves more attributes (unknown if all versions work).

  • Property mode set to 100644
File size: 17.0 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 4 11:40:00 2023
14// Update Count : 427
15//
16
17#include <cassert> // for assert, strict_dynamic_cast, assertf
18#include <memory> // for unique_ptr
19#include <string> // for string
20
21#include "AST/Label.hpp" // for Label
22#include "AST/Stmt.hpp" // for Stmt, AsmStmt, BranchStmt, CaseCla...
23#include "Common/SemanticError.h" // for SemanticError
24#include "Common/utility.h" // for maybeMoveBuild, maybeBuild
25#include "ParseNode.h" // for StatementNode, ExpressionNode, bui...
26#include "parserutility.h" // for notZeroExpr
27
28class Declaration;
29
30using namespace std;
31
32StatementNode::StatementNode( DeclarationNode * decl ) {
33 assert( decl );
34 DeclarationNode * agg = decl->extractAggregate();
35 if ( agg ) {
36 StatementNode * nextStmt = new StatementNode(
37 new ast::DeclStmt( decl->location, maybeBuild( decl ) ) );
38 set_next( nextStmt );
39 if ( decl->get_next() ) {
40 get_next()->set_next( new StatementNode( dynamic_cast< DeclarationNode * >(decl->get_next()) ) );
41 decl->set_next( 0 );
42 } // if
43 } else {
44 if ( decl->get_next() ) {
45 set_next( new StatementNode( dynamic_cast< DeclarationNode * >( decl->get_next() ) ) );
46 decl->set_next( 0 );
47 } // if
48 agg = decl;
49 } // if
50 // Local copy to avoid accessing the pointer after it is moved from.
51 CodeLocation declLocation = agg->location;
52 stmt.reset( new ast::DeclStmt( declLocation, maybeMoveBuild( agg ) ) );
53} // StatementNode::StatementNode
54
55StatementNode * StatementNode::append_last_case( StatementNode * stmt ) {
56 StatementNode * prev = this;
57 // find end of list and maintain previous pointer
58 for ( StatementNode * curr = prev; curr != nullptr; curr = (StatementNode *)curr->get_next() ) {
59 StatementNode * node = strict_dynamic_cast< StatementNode * >(curr);
60 assert( nullptr == node->stmt.get() );
61 assert( dynamic_cast<ast::CaseClause *>( node->clause.get() ) );
62 prev = curr;
63 } // for
64 // convert from StatementNode list to Statement list
65 StatementNode * node = dynamic_cast< StatementNode * >(prev);
66 std::vector<ast::ptr<ast::Stmt>> stmts;
67 buildMoveList( stmt, stmts );
68 // splice any new Statements to end of current Statements
69 auto caseStmt = strict_dynamic_cast<ast::CaseClause *>( node->clause.get() );
70 for ( auto const & newStmt : stmts ) {
71 caseStmt->stmts.emplace_back( newStmt );
72 }
73 stmts.clear();
74 return this;
75} // StatementNode::append_last_case
76
77ast::Stmt * build_expr( CodeLocation const & location, ExpressionNode * ctl ) {
78 if ( ast::Expr * e = maybeMoveBuild( ctl ) ) {
79 return new ast::ExprStmt( location, e );
80 } else {
81 return new ast::NullStmt( location );
82 }
83} // build_expr
84
85static ast::Expr * build_if_control( CondCtl * ctl,
86 std::vector<ast::ptr<ast::Stmt>> & inits ) {
87 assert( inits.empty() );
88 if ( nullptr != ctl->init ) {
89 buildMoveList( ctl->init, inits );
90 } // if
91
92 ast::Expr * cond = nullptr;
93 if ( ctl->condition ) {
94 // compare the provided condition against 0
95 cond = notZeroExpr( maybeMoveBuild( ctl->condition ) );
96 } else {
97 for ( ast::ptr<ast::Stmt> & stmt : inits ) {
98 // build the && of all of the declared variables compared against 0
99 //auto declStmt = strict_dynamic_cast<ast::DeclStmt *>( stmt );
100 auto declStmt = stmt.strict_as<ast::DeclStmt>();
101 //ast::DeclWithType * dwt = strict_dynamic_cast<ast::DeclWithType *>( declStmt->decl );
102 auto dwt = declStmt->decl.strict_as<ast::DeclWithType>();
103 ast::Expr * nze = notZeroExpr( new ast::VariableExpr( dwt->location, dwt ) );
104 cond = cond ? new ast::LogicalExpr( dwt->location, cond, nze, ast::AndExpr ) : nze;
105 }
106 }
107 delete ctl;
108 return cond;
109} // build_if_control
110
111ast::Stmt * build_if( const CodeLocation & location, CondCtl * ctl, StatementNode * then, StatementNode * else_ ) {
112 std::vector<ast::ptr<ast::Stmt>> astinit; // maybe empty
113 ast::Expr * astcond = build_if_control( ctl, astinit ); // ctl deleted, cond/init set
114
115 std::vector<ast::ptr<ast::Stmt>> aststmt;
116 buildMoveList( then, aststmt );
117 assert( aststmt.size() == 1 );
118 ast::Stmt const * astthen = aststmt.front().release();
119
120 ast::Stmt const * astelse = nullptr;
121 if ( else_ ) {
122 std::vector<ast::ptr<ast::Stmt>> aststmt;
123 buildMoveList( else_, aststmt );
124 assert( aststmt.size() == 1 );
125 astelse = aststmt.front().release();
126 } // if
127
128 return new ast::IfStmt( location, astcond, astthen, astelse,
129 std::move( astinit )
130 );
131} // build_if
132
133// Temporary work around. Split StmtClause off from StatementNode.
134template<typename clause_t>
135static void buildMoveClauseList( StatementNode * firstNode,
136 std::vector<ast::ptr<clause_t>> & output ) {
137 SemanticErrorException errors;
138 std::back_insert_iterator<std::vector<ast::ptr<clause_t>>>
139 out( output );
140 StatementNode * cur = firstNode;
141
142 while ( cur ) {
143 try {
144 auto clause = cur->clause.release();
145 if ( auto result = dynamic_cast<clause_t *>( clause ) ) {
146 *out++ = result;
147 } else {
148 assertf(false, __PRETTY_FUNCTION__ );
149 SemanticError( cur->location, "type specifier declaration in forall clause is currently unimplemented." );
150 } // if
151 } catch( SemanticErrorException & e ) {
152 errors.append( e );
153 } // try
154 ParseNode * temp = cur->get_next();
155 // Should not return nullptr, then it is non-homogeneous:
156 cur = dynamic_cast<StatementNode *>( temp );
157 if ( !cur && temp ) {
158 SemanticError( temp->location, "internal error, non-homogeneous nodes founds in buildList processing." );
159 } // if
160 } // while
161 if ( ! errors.isEmpty() ) {
162 throw errors;
163 } // if
164 // Usually in the wrapper.
165 delete firstNode;
166}
167
168ast::Stmt * build_switch( const CodeLocation & location, bool isSwitch, ExpressionNode * ctl, StatementNode * stmt ) {
169 std::vector<ast::ptr<ast::CaseClause>> aststmt;
170 buildMoveClauseList( stmt, aststmt );
171 // If it is not a switch it is a choose statement.
172 if ( ! isSwitch ) {
173 for ( ast::ptr<ast::CaseClause> & stmt : aststmt ) {
174 // Code after "case" is the end of case list.
175 if ( !stmt->stmts.empty() ) {
176 auto mutStmt = ast::mutate( stmt.get() );
177 // I believe the stmts are actually always one block.
178 auto stmts = mutStmt->stmts.front().get_and_mutate();
179 auto block = strict_dynamic_cast<ast::CompoundStmt *>( stmts );
180 block->kids.push_back( new ast::BranchStmt( block->location,
181 ast::BranchStmt::Break,
182 ast::Label( block->location ) ) );
183 stmt = mutStmt;
184 } // if
185 } // for
186 } // if
187 // aststmt.size() == 0 for switch (...) {}, i.e., no declaration or statements
188 return new ast::SwitchStmt( location,
189 maybeMoveBuild( ctl ), std::move( aststmt ) );
190} // build_switch
191
192ast::CaseClause * build_case( ExpressionNode * ctl ) {
193 // stmt starts empty and then added to
194 auto expr = maybeMoveBuild( ctl );
195 return new ast::CaseClause( expr->location, expr, {} );
196} // build_case
197
198ast::CaseClause * build_default( const CodeLocation & location ) {
199 // stmt starts empty and then added to
200 return new ast::CaseClause( location, nullptr, {} );
201} // build_default
202
203ast::Stmt * build_while( const CodeLocation & location, CondCtl * ctl, StatementNode * stmt, StatementNode * else_ ) {
204 std::vector<ast::ptr<ast::Stmt>> astinit; // maybe empty
205 ast::Expr * astcond = build_if_control( ctl, astinit ); // ctl deleted, cond/init set
206
207 std::vector<ast::ptr<ast::Stmt>> aststmt; // loop body, compound created if empty
208 buildMoveList( stmt, aststmt );
209 assert( aststmt.size() == 1 );
210
211 std::vector<ast::ptr<ast::Stmt>> astelse; // else clause, maybe empty
212 buildMoveList( else_, astelse );
213 assert( astelse.size() <= 1 );
214
215 return new ast::WhileDoStmt( location,
216 astcond,
217 aststmt.front(),
218 astelse.empty() ? nullptr : astelse.front().release(),
219 std::move( astinit ),
220 false
221 );
222} // build_while
223
224ast::Stmt * build_do_while( const CodeLocation & location, ExpressionNode * ctl, StatementNode * stmt, StatementNode * else_ ) {
225 std::vector<ast::ptr<ast::Stmt>> aststmt; // loop body, compound created if empty
226 buildMoveList( stmt, aststmt );
227 assert( aststmt.size() == 1 ); // compound created if empty
228
229 std::vector<ast::ptr<ast::Stmt>> astelse; // else clause, maybe empty
230 buildMoveList( else_, astelse );
231 assert( astelse.size() <= 1 );
232
233 // do-while cannot have declarations in the contitional, so init is always empty
234 return new ast::WhileDoStmt( location,
235 notZeroExpr( maybeMoveBuild( ctl ) ),
236 aststmt.front(),
237 astelse.empty() ? nullptr : astelse.front().release(),
238 {},
239 true
240 );
241} // build_do_while
242
243ast::Stmt * build_for( const CodeLocation & location, ForCtrl * forctl, StatementNode * stmt, StatementNode * else_ ) {
244 std::vector<ast::ptr<ast::Stmt>> astinit; // maybe empty
245 buildMoveList( forctl->init, astinit );
246
247 ast::Expr * astcond = nullptr; // maybe empty
248 astcond = notZeroExpr( maybeMoveBuild( forctl->condition ) );
249
250 ast::Expr * astincr = nullptr; // maybe empty
251 astincr = maybeMoveBuild( forctl->change );
252 delete forctl;
253
254 std::vector<ast::ptr<ast::Stmt>> aststmt; // loop body, compound created if empty
255 buildMoveList( stmt, aststmt );
256 assert( aststmt.size() == 1 );
257
258 std::vector<ast::ptr<ast::Stmt>> astelse; // else clause, maybe empty
259 buildMoveList( else_, astelse );
260 assert( astelse.size() <= 1 );
261
262 return new ast::ForStmt( location,
263 std::move( astinit ),
264 astcond,
265 astincr,
266 aststmt.front(),
267 astelse.empty() ? nullptr : astelse.front().release()
268 );
269} // build_for
270
271ast::Stmt * build_branch( const CodeLocation & location, ast::BranchStmt::Kind kind ) {
272 return new ast::BranchStmt( location,
273 kind,
274 ast::Label( location )
275 );
276} // build_branch
277
278ast::Stmt * build_branch( const CodeLocation & location, string * identifier, ast::BranchStmt::Kind kind ) {
279 ast::Stmt * ret = new ast::BranchStmt( location,
280 kind,
281 ast::Label( location, *identifier )
282 );
283 delete identifier; // allocated by lexer
284 return ret;
285} // build_branch
286
287ast::Stmt * build_computedgoto( ExpressionNode * ctl ) {
288 ast::Expr * expr = maybeMoveBuild( ctl );
289 return new ast::BranchStmt( expr->location, expr );
290} // build_computedgoto
291
292ast::Stmt * build_return( const CodeLocation & location, ExpressionNode * ctl ) {
293 std::vector<ast::ptr<ast::Expr>> exps;
294 buildMoveList( ctl, exps );
295 return new ast::ReturnStmt( location,
296 exps.size() > 0 ? exps.back().release() : nullptr
297 );
298} // build_return
299
300static ast::Stmt * build_throw_stmt(
301 const CodeLocation & location,
302 ExpressionNode * ctl,
303 ast::ExceptionKind kind ) {
304 std::vector<ast::ptr<ast::Expr>> exps;
305 buildMoveList( ctl, exps );
306 assertf( exps.size() < 2, "CFA internal error: leaking memory" );
307 return new ast::ThrowStmt( location,
308 kind,
309 !exps.empty() ? exps.back().release() : nullptr,
310 (ast::Expr *)nullptr
311 );
312}
313
314ast::Stmt * build_throw( const CodeLocation & loc, ExpressionNode * ctl ) {
315 return build_throw_stmt( loc, ctl, ast::Terminate );
316} // build_throw
317
318ast::Stmt * build_resume( const CodeLocation & loc, ExpressionNode * ctl ) {
319 return build_throw_stmt( loc, ctl, ast::Resume );
320} // build_resume
321
322ast::Stmt * build_resume_at( ExpressionNode * ctl, ExpressionNode * target ) {
323 (void)ctl;
324 (void)target;
325 assertf( false, "resume at (non-local throw) is not yet supported," );
326} // build_resume_at
327
328ast::Stmt * build_try( const CodeLocation & location, StatementNode * try_, StatementNode * catch_, StatementNode * finally_ ) {
329 std::vector<ast::ptr<ast::CatchClause>> aststmt;
330 buildMoveClauseList( catch_, aststmt );
331 ast::CompoundStmt * tryBlock = strict_dynamic_cast<ast::CompoundStmt *>( maybeMoveBuild( try_ ) );
332 ast::FinallyClause * finallyBlock = nullptr;
333 if ( finally_ ) {
334 finallyBlock = dynamic_cast<ast::FinallyClause *>( finally_->clause.release() );
335 }
336 return new ast::TryStmt( location,
337 tryBlock,
338 std::move( aststmt ),
339 finallyBlock
340 );
341} // build_try
342
343ast::CatchClause * build_catch( const CodeLocation & location, ast::ExceptionKind kind, DeclarationNode * decl, ExpressionNode * cond, StatementNode * body ) {
344 std::vector<ast::ptr<ast::Stmt>> aststmt;
345 buildMoveList( body, aststmt );
346 assert( aststmt.size() == 1 );
347 return new ast::CatchClause( location,
348 kind,
349 maybeMoveBuild( decl ),
350 maybeMoveBuild( cond ),
351 aststmt.front().release()
352 );
353} // build_catch
354
355ast::FinallyClause * build_finally( const CodeLocation & location, StatementNode * stmt ) {
356 std::vector<ast::ptr<ast::Stmt>> aststmt;
357 buildMoveList( stmt, aststmt );
358 assert( aststmt.size() == 1 );
359 return new ast::FinallyClause( location,
360 aststmt.front().strict_as<ast::CompoundStmt>()
361 );
362} // build_finally
363
364ast::SuspendStmt * build_suspend( const CodeLocation & location, StatementNode * then, ast::SuspendStmt::Type type ) {
365 std::vector<ast::ptr<ast::Stmt>> stmts;
366 buildMoveList( then, stmts );
367 ast::CompoundStmt const * then2 = nullptr;
368 if(!stmts.empty()) {
369 assert( stmts.size() == 1 );
370 then2 = stmts.front().strict_as<ast::CompoundStmt>();
371 }
372 auto node = new ast::SuspendStmt( location, then2, ast::SuspendStmt::None );
373 node->type = type;
374 return node;
375} // build_suspend
376
377ast::WaitForStmt * build_waitfor( const CodeLocation & location, ast::WaitForStmt * existing, ExpressionNode * when, ExpressionNode * targetExpr, StatementNode * stmt ) {
378 auto clause = new ast::WaitForClause( location );
379 clause->target_func = maybeBuild( targetExpr );
380 clause->stmt = maybeMoveBuild( stmt );
381 clause->cond = notZeroExpr( maybeMoveBuild( when ) );
382
383 ExpressionNode * next = dynamic_cast<ExpressionNode *>( targetExpr->get_next() );
384 targetExpr->set_next( nullptr );
385 buildMoveList( next, clause->target_args );
386
387 delete targetExpr;
388
389 existing->clauses.insert( existing->clauses.begin(), clause );
390
391 return existing;
392} // build_waitfor
393
394ast::WaitForStmt * build_waitfor_else( const CodeLocation & location, ast::WaitForStmt * existing, ExpressionNode * when, StatementNode * stmt ) {
395 existing->else_stmt = maybeMoveBuild( stmt );
396 existing->else_cond = notZeroExpr( maybeMoveBuild( when ) );
397
398 (void)location;
399 return existing;
400} // build_waitfor_else
401
402ast::WaitForStmt * build_waitfor_timeout( const CodeLocation & location, ast::WaitForStmt * existing, ExpressionNode * when, ExpressionNode * timeout, StatementNode * stmt ) {
403 existing->timeout_time = maybeMoveBuild( timeout );
404 existing->timeout_stmt = maybeMoveBuild( stmt );
405 existing->timeout_cond = notZeroExpr( maybeMoveBuild( when ) );
406
407 (void)location;
408 return existing;
409} // build_waitfor_timeout
410
411ast::Stmt * build_with( const CodeLocation & location, ExpressionNode * exprs, StatementNode * stmt ) {
412 std::vector<ast::ptr<ast::Expr>> e;
413 buildMoveList( exprs, e );
414 ast::Stmt * s = maybeMoveBuild( stmt );
415 return new ast::DeclStmt( location, new ast::WithStmt( location, std::move( e ), s ) );
416} // build_with
417
418ast::Stmt * build_compound( const CodeLocation & location, StatementNode * first ) {
419 auto cs = new ast::CompoundStmt( location );
420 buildMoveList( first, cs->kids );
421 return cs;
422} // build_compound
423
424// A single statement in a control structure is always converted to a compound statement so subsequent generated code
425// can be placed within this compound statement. Otherwise, code generation has to constantly check for a single
426// statement and wrap it into a compound statement to insert additional code. Hence, all control structures have a
427// conical form for code generation.
428StatementNode * maybe_build_compound( const CodeLocation & location, StatementNode * first ) {
429 // Optimization: if the control-structure statement is a compound statement, do not wrap it.
430 // e.g., if (...) {...} do not wrap the existing compound statement.
431 if ( !dynamic_cast<ast::CompoundStmt *>( first->stmt.get() ) ) { // unique_ptr
432 return new StatementNode( build_compound( location, first ) );
433 } // if
434 return first;
435} // maybe_build_compound
436
437// Question
438ast::Stmt * build_asm( const CodeLocation & location, bool voltile, ast::Expr * instruction, ExpressionNode * output, ExpressionNode * input, ExpressionNode * clobber, LabelNode * gotolabels ) {
439 std::vector<ast::ptr<ast::Expr>> out, in;
440 std::vector<ast::ptr<ast::ConstantExpr>> clob;
441
442 buildMoveList( output, out );
443 buildMoveList( input, in );
444 buildMoveList( clobber, clob );
445 return new ast::AsmStmt( location,
446 voltile,
447 instruction,
448 std::move( out ),
449 std::move( in ),
450 std::move( clob ),
451 gotolabels ? gotolabels->labels : std::vector<ast::Label>()
452 );
453} // build_asm
454
455ast::Stmt * build_directive( const CodeLocation & location, string * directive ) {
456 auto stmt = new ast::DirectiveStmt( location, *directive );
457 delete directive;
458 return stmt;
459} // build_directive
460
461ast::Stmt * build_mutex( const CodeLocation & location, ExpressionNode * exprs, StatementNode * stmt ) {
462 std::vector<ast::ptr<ast::Expr>> expList;
463 buildMoveList( exprs, expList );
464 ast::Stmt * body = maybeMoveBuild( stmt );
465 return new ast::MutexStmt( location, body, std::move( expList ) );
466} // build_mutex
467
468// Local Variables: //
469// tab-width: 4 //
470// mode: c++ //
471// compile-command: "make install" //
472// End: //
Note: See TracBrowser for help on using the repository browser.