source: src/Parser/StatementNode.cc @ 3d5fba21

ADTast-experimental
Last change on this file since 3d5fba21 was c468150, checked in by Andrew Beach <ajbeach@…>, 18 months ago

Split up ParseNode?.h so that headers match implementation. May have a bit less to include total because of it.

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