| [b87a5ed] | 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 | // | 
|---|
| [4e7171f] | 7 | // StatementNode.cc -- Transform from parse data-structures to AST data-structures, usually deleting the parse | 
|---|
|  | 8 | //     data-structure after the transformation. | 
|---|
| [b87a5ed] | 9 | // | 
|---|
|  | 10 | // Author           : Rodolfo G. Esteves | 
|---|
|  | 11 | // Created On       : Sat May 16 14:59:41 2015 | 
|---|
| [bb7422a] | 12 | // Last Modified By : Andrew Beach | 
|---|
| [6611177] | 13 | // Last Modified On : Tue Apr 11 10:16:00 2023 | 
|---|
|  | 14 | // Update Count     : 428 | 
|---|
| [b87a5ed] | 15 | // | 
|---|
|  | 16 |  | 
|---|
| [c468150] | 17 | #include "StatementNode.h" | 
|---|
|  | 18 |  | 
|---|
| [e3e16bc] | 19 | #include <cassert>                 // for assert, strict_dynamic_cast, assertf | 
|---|
| [d180746] | 20 | #include <memory>                  // for unique_ptr | 
|---|
|  | 21 | #include <string>                  // for string | 
|---|
| [51b73452] | 22 |  | 
|---|
| [bb7422a] | 23 | #include "AST/Label.hpp"           // for Label | 
|---|
|  | 24 | #include "AST/Stmt.hpp"            // for Stmt, AsmStmt, BranchStmt, CaseCla... | 
|---|
| [d180746] | 25 | #include "Common/SemanticError.h"  // for SemanticError | 
|---|
|  | 26 | #include "Common/utility.h"        // for maybeMoveBuild, maybeBuild | 
|---|
| [c468150] | 27 | #include "DeclarationNode.h"       // for DeclarationNode | 
|---|
|  | 28 | #include "ExpressionNode.h"        // for ExpressionNode | 
|---|
| [d180746] | 29 | #include "parserutility.h"         // for notZeroExpr | 
|---|
|  | 30 |  | 
|---|
|  | 31 | class Declaration; | 
|---|
| [51b73452] | 32 |  | 
|---|
|  | 33 | using namespace std; | 
|---|
|  | 34 |  | 
|---|
| [6611177] | 35 | // Some helpers for cases that really want a single node but check for lists. | 
|---|
|  | 36 | static 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 |  | 
|---|
|  | 43 | static 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 |  | 
|---|
| [61fc4f6] | 50 | StatementNode::StatementNode( DeclarationNode * decl ) { | 
|---|
| [c0aa336] | 51 | assert( decl ); | 
|---|
| [61fc4f6] | 52 | DeclarationNode * agg = decl->extractAggregate(); | 
|---|
| [c0aa336] | 53 | if ( agg ) { | 
|---|
| [bb7422a] | 54 | StatementNode * nextStmt = new StatementNode( | 
|---|
|  | 55 | new ast::DeclStmt( decl->location, maybeBuild( decl ) ) ); | 
|---|
| [c0aa336] | 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 ); | 
|---|
| [1d4580a] | 60 | } // if | 
|---|
|  | 61 | } else { | 
|---|
| [c0aa336] | 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; | 
|---|
| [1d4580a] | 67 | } // if | 
|---|
| [bb7422a] | 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 ) ) ); | 
|---|
| [c0aa336] | 71 | } // StatementNode::StatementNode | 
|---|
| [1d4580a] | 72 |  | 
|---|
| [c468150] | 73 | StatementNode * 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 |  | 
|---|
| [6611177] | 86 | ClauseNode * ClauseNode::append_last_case( StatementNode * stmt ) { | 
|---|
|  | 87 | ClauseNode * prev = this; | 
|---|
| [1d4580a] | 88 | // find end of list and maintain previous pointer | 
|---|
| [6611177] | 89 | for ( ClauseNode * curr = prev; curr != nullptr; curr = (ClauseNode *)curr->get_next() ) { | 
|---|
|  | 90 | ClauseNode * node = strict_dynamic_cast< ClauseNode * >(curr); | 
|---|
| [bb7422a] | 91 | assert( dynamic_cast<ast::CaseClause *>( node->clause.get() ) ); | 
|---|
| [8cc5cb0] | 92 | prev = curr; | 
|---|
|  | 93 | } // for | 
|---|
| [6611177] | 94 | ClauseNode * node = dynamic_cast< ClauseNode * >(prev); | 
|---|
| [e82aa9df] | 95 | // convert from StatementNode list to Statement list | 
|---|
| [bb7422a] | 96 | std::vector<ast::ptr<ast::Stmt>> stmts; | 
|---|
| [7ecbb7e] | 97 | buildMoveList( stmt, stmts ); | 
|---|
| [e82aa9df] | 98 | // splice any new Statements to end of current Statements | 
|---|
| [bb7422a] | 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(); | 
|---|
| [8cc5cb0] | 104 | return this; | 
|---|
| [6611177] | 105 | } // ClauseNode::append_last_case | 
|---|
| [8cc5cb0] | 106 |  | 
|---|
| [bb7422a] | 107 | ast::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 | } | 
|---|
| [401e61f] | 113 | } // build_expr | 
|---|
| [8cc5cb0] | 114 |  | 
|---|
| [bb7422a] | 115 | static 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 ); | 
|---|
| [936e9f4] | 120 | } // if | 
|---|
|  | 121 |  | 
|---|
| [bb7422a] | 122 | ast::Expr * cond = nullptr; | 
|---|
| [a01f7c94] | 123 | if ( ctl->condition ) { | 
|---|
|  | 124 | // compare the provided condition against 0 | 
|---|
| [702e826] | 125 | cond = notZeroExpr( maybeMoveBuild( ctl->condition ) ); | 
|---|
| [a01f7c94] | 126 | } else { | 
|---|
| [bb7422a] | 127 | for ( ast::ptr<ast::Stmt> & stmt : inits ) { | 
|---|
| [a01f7c94] | 128 | // build the && of all of the declared variables compared against 0 | 
|---|
| [bb7422a] | 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; | 
|---|
| [a01f7c94] | 133 | } | 
|---|
|  | 134 | } | 
|---|
| [6d49ea3] | 135 | delete ctl; | 
|---|
| [ee3c93d] | 136 | return cond; | 
|---|
| [401e61f] | 137 | } // build_if_control | 
|---|
| [ee3c93d] | 138 |  | 
|---|
| [bb7422a] | 139 | ast::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 | 
|---|
| [436bbe5] | 142 |  | 
|---|
| [5541a44e] | 143 | ast::Stmt const * astthen = buildMoveSingle( then ); | 
|---|
|  | 144 | ast::Stmt const * astelse = buildMoveOptional( else_ ); | 
|---|
| [ee3c93d] | 145 |  | 
|---|
| [bb7422a] | 146 | return new ast::IfStmt( location, astcond, astthen, astelse, | 
|---|
|  | 147 | std::move( astinit ) | 
|---|
|  | 148 | ); | 
|---|
| [401e61f] | 149 | } // build_if | 
|---|
| [2f22cc4] | 150 |  | 
|---|
| [6611177] | 151 | ast::Stmt * build_switch( const CodeLocation & location, bool isSwitch, ExpressionNode * ctl, ClauseNode * stmt ) { | 
|---|
| [bb7422a] | 152 | std::vector<ast::ptr<ast::CaseClause>> aststmt; | 
|---|
| [6611177] | 153 | buildMoveList( stmt, aststmt ); | 
|---|
| [bb7422a] | 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; | 
|---|
| [6a276a0] | 167 | } // if | 
|---|
|  | 168 | } // for | 
|---|
|  | 169 | } // if | 
|---|
| [436bbe5] | 170 | // aststmt.size() == 0 for switch (...) {}, i.e., no declaration or statements | 
|---|
| [bb7422a] | 171 | return new ast::SwitchStmt( location, | 
|---|
|  | 172 | maybeMoveBuild( ctl ), std::move( aststmt ) ); | 
|---|
| [401e61f] | 173 | } // build_switch | 
|---|
|  | 174 |  | 
|---|
| [6611177] | 175 | ast::CaseClause * build_case( const CodeLocation & location, ExpressionNode * ctl ) { | 
|---|
| [bb7422a] | 176 | // stmt starts empty and then added to | 
|---|
|  | 177 | auto expr = maybeMoveBuild( ctl ); | 
|---|
| [6611177] | 178 | return new ast::CaseClause( location, expr, {} ); | 
|---|
| [401e61f] | 179 | } // build_case | 
|---|
|  | 180 |  | 
|---|
| [bb7422a] | 181 | ast::CaseClause * build_default( const CodeLocation & location ) { | 
|---|
|  | 182 | // stmt starts empty and then added to | 
|---|
|  | 183 | return new ast::CaseClause( location, nullptr, {} ); | 
|---|
| [401e61f] | 184 | } // build_default | 
|---|
|  | 185 |  | 
|---|
| [bb7422a] | 186 | ast::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 | 
|---|
| [3b0bc16] | 189 |  | 
|---|
| [bb7422a] | 190 | return new ast::WhileDoStmt( location, | 
|---|
|  | 191 | astcond, | 
|---|
| [6611177] | 192 | buildMoveSingle( stmt ), | 
|---|
|  | 193 | buildMoveOptional( else_ ), | 
|---|
| [bb7422a] | 194 | std::move( astinit ), | 
|---|
| [3e94a23] | 195 | ast::While | 
|---|
| [bb7422a] | 196 | ); | 
|---|
| [401e61f] | 197 | } // build_while | 
|---|
| [2f22cc4] | 198 |  | 
|---|
| [bb7422a] | 199 | ast::Stmt * build_do_while( const CodeLocation & location, ExpressionNode * ctl, StatementNode * stmt, StatementNode * else_ ) { | 
|---|
| [4e7171f] | 200 | // do-while cannot have declarations in the contitional, so init is always empty | 
|---|
| [bb7422a] | 201 | return new ast::WhileDoStmt( location, | 
|---|
|  | 202 | notZeroExpr( maybeMoveBuild( ctl ) ), | 
|---|
| [6611177] | 203 | buildMoveSingle( stmt ), | 
|---|
|  | 204 | buildMoveOptional( else_ ), | 
|---|
| [bb7422a] | 205 | {}, | 
|---|
| [3e94a23] | 206 | ast::DoWhile | 
|---|
| [bb7422a] | 207 | ); | 
|---|
| [401e61f] | 208 | } // build_do_while | 
|---|
| [2f22cc4] | 209 |  | 
|---|
| [bb7422a] | 210 | ast::Stmt * build_for( const CodeLocation & location, ForCtrl * forctl, StatementNode * stmt, StatementNode * else_ ) { | 
|---|
|  | 211 | std::vector<ast::ptr<ast::Stmt>> astinit;                                               // maybe empty | 
|---|
| [436bbe5] | 212 | buildMoveList( forctl->init, astinit ); | 
|---|
| [2f22cc4] | 213 |  | 
|---|
| [bb7422a] | 214 | ast::Expr * astcond = nullptr;                                          // maybe empty | 
|---|
| [702e826] | 215 | astcond = notZeroExpr( maybeMoveBuild( forctl->condition ) ); | 
|---|
| [2f22cc4] | 216 |  | 
|---|
| [bb7422a] | 217 | ast::Expr * astincr = nullptr;                                          // maybe empty | 
|---|
| [702e826] | 218 | astincr = maybeMoveBuild( forctl->change ); | 
|---|
| [436bbe5] | 219 | delete forctl; | 
|---|
| [2f22cc4] | 220 |  | 
|---|
| [bb7422a] | 221 | return new ast::ForStmt( location, | 
|---|
|  | 222 | std::move( astinit ), | 
|---|
|  | 223 | astcond, | 
|---|
|  | 224 | astincr, | 
|---|
| [6611177] | 225 | buildMoveSingle( stmt ), | 
|---|
|  | 226 | buildMoveOptional( else_ ) | 
|---|
| [bb7422a] | 227 | ); | 
|---|
| [401e61f] | 228 | } // build_for | 
|---|
| [2f22cc4] | 229 |  | 
|---|
| [bb7422a] | 230 | ast::Stmt * build_branch( const CodeLocation & location, ast::BranchStmt::Kind kind ) { | 
|---|
|  | 231 | return new ast::BranchStmt( location, | 
|---|
|  | 232 | kind, | 
|---|
|  | 233 | ast::Label( location ) | 
|---|
|  | 234 | ); | 
|---|
| [401e61f] | 235 | } // build_branch | 
|---|
|  | 236 |  | 
|---|
| [bb7422a] | 237 | ast::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 | 
|---|
| [ab57786] | 243 | return ret; | 
|---|
| [401e61f] | 244 | } // build_branch | 
|---|
|  | 245 |  | 
|---|
| [bb7422a] | 246 | ast::Stmt * build_computedgoto( ExpressionNode * ctl ) { | 
|---|
|  | 247 | ast::Expr * expr = maybeMoveBuild( ctl ); | 
|---|
|  | 248 | return new ast::BranchStmt( expr->location, expr ); | 
|---|
| [401e61f] | 249 | } // build_computedgoto | 
|---|
| [8cc5cb0] | 250 |  | 
|---|
| [bb7422a] | 251 | ast::Stmt * build_return( const CodeLocation & location, ExpressionNode * ctl ) { | 
|---|
|  | 252 | std::vector<ast::ptr<ast::Expr>> exps; | 
|---|
| [7ecbb7e] | 253 | buildMoveList( ctl, exps ); | 
|---|
| [bb7422a] | 254 | return new ast::ReturnStmt( location, | 
|---|
|  | 255 | exps.size() > 0 ? exps.back().release() : nullptr | 
|---|
|  | 256 | ); | 
|---|
| [401e61f] | 257 | } // build_return | 
|---|
| [daf1af8] | 258 |  | 
|---|
| [bb7422a] | 259 | static ast::Stmt * build_throw_stmt( | 
|---|
|  | 260 | const CodeLocation & location, | 
|---|
|  | 261 | ExpressionNode * ctl, | 
|---|
|  | 262 | ast::ExceptionKind kind ) { | 
|---|
|  | 263 | std::vector<ast::ptr<ast::Expr>> exps; | 
|---|
| [7ecbb7e] | 264 | buildMoveList( ctl, exps ); | 
|---|
| [436bbe5] | 265 | assertf( exps.size() < 2, "CFA internal error: leaking memory" ); | 
|---|
| [bb7422a] | 266 | return new ast::ThrowStmt( location, | 
|---|
|  | 267 | kind, | 
|---|
|  | 268 | !exps.empty() ? exps.back().release() : nullptr, | 
|---|
|  | 269 | (ast::Expr *)nullptr | 
|---|
|  | 270 | ); | 
|---|
|  | 271 | } | 
|---|
|  | 272 |  | 
|---|
|  | 273 | ast::Stmt * build_throw( const CodeLocation & loc, ExpressionNode * ctl ) { | 
|---|
|  | 274 | return build_throw_stmt( loc, ctl, ast::Terminate ); | 
|---|
| [401e61f] | 275 | } // build_throw | 
|---|
| [daf1af8] | 276 |  | 
|---|
| [bb7422a] | 277 | ast::Stmt * build_resume( const CodeLocation & loc, ExpressionNode * ctl ) { | 
|---|
|  | 278 | return build_throw_stmt( loc, ctl, ast::Resume ); | 
|---|
| [401e61f] | 279 | } // build_resume | 
|---|
| [daf1af8] | 280 |  | 
|---|
| [bb7422a] | 281 | ast::Stmt * build_resume_at( ExpressionNode * ctl, ExpressionNode * target ) { | 
|---|
| [794c15b] | 282 | (void)ctl; | 
|---|
|  | 283 | (void)target; | 
|---|
|  | 284 | assertf( false, "resume at (non-local throw) is not yet supported," ); | 
|---|
| [401e61f] | 285 | } // build_resume_at | 
|---|
| [321f55d] | 286 |  | 
|---|
| [6611177] | 287 | ast::Stmt * build_try( const CodeLocation & location, StatementNode * try_, ClauseNode * catch_, ClauseNode * finally_ ) { | 
|---|
| [bb7422a] | 288 | std::vector<ast::ptr<ast::CatchClause>> aststmt; | 
|---|
| [6611177] | 289 | buildMoveList( catch_, aststmt ); | 
|---|
| [bb7422a] | 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 | ); | 
|---|
| [401e61f] | 300 | } // build_try | 
|---|
|  | 301 |  | 
|---|
| [bb7422a] | 302 | ast::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 ), | 
|---|
| [6611177] | 307 | buildMoveSingle( body ) | 
|---|
| [bb7422a] | 308 | ); | 
|---|
| [401e61f] | 309 | } // build_catch | 
|---|
|  | 310 |  | 
|---|
| [bb7422a] | 311 | ast::FinallyClause * build_finally( const CodeLocation & location, StatementNode * stmt ) { | 
|---|
|  | 312 | return new ast::FinallyClause( location, | 
|---|
| [6611177] | 313 | strict_dynamic_cast<const ast::CompoundStmt *>( | 
|---|
|  | 314 | buildMoveSingle( stmt ) | 
|---|
|  | 315 | ) | 
|---|
| [bb7422a] | 316 | ); | 
|---|
| [401e61f] | 317 | } // build_finally | 
|---|
| [1d4580a] | 318 |  | 
|---|
| [835d6e8] | 319 | ast::SuspendStmt * build_suspend( const CodeLocation & location, StatementNode * then, ast::SuspendStmt::Kind kind ) { | 
|---|
| [6611177] | 320 | return new ast::SuspendStmt( location, | 
|---|
|  | 321 | strict_dynamic_cast<const ast::CompoundStmt *, nullptr>( | 
|---|
|  | 322 | buildMoveOptional( then ) | 
|---|
|  | 323 | ), | 
|---|
|  | 324 | kind | 
|---|
|  | 325 | ); | 
|---|
| [9fd9d015] | 326 | } // build_suspend | 
|---|
| [427854b] | 327 |  | 
|---|
| [bb7422a] | 328 | ast::WaitForStmt * build_waitfor( const CodeLocation & location, ast::WaitForStmt * existing, ExpressionNode * when, ExpressionNode * targetExpr, StatementNode * stmt ) { | 
|---|
|  | 329 | auto clause = new ast::WaitForClause( location ); | 
|---|
| [c86b08d] | 330 | clause->target = maybeBuild( targetExpr ); | 
|---|
| [bb7422a] | 331 | clause->stmt = maybeMoveBuild( stmt ); | 
|---|
| [c86b08d] | 332 | clause->when_cond = notZeroExpr( maybeMoveBuild( when ) ); | 
|---|
| [2065609] | 333 |  | 
|---|
|  | 334 | ExpressionNode * next = dynamic_cast<ExpressionNode *>( targetExpr->get_next() ); | 
|---|
|  | 335 | targetExpr->set_next( nullptr ); | 
|---|
| [bb7422a] | 336 | buildMoveList( next, clause->target_args ); | 
|---|
| [2065609] | 337 |  | 
|---|
| [135b431] | 338 | delete targetExpr; | 
|---|
|  | 339 |  | 
|---|
| [bb7422a] | 340 | existing->clauses.insert( existing->clauses.begin(), clause ); | 
|---|
| [135b431] | 341 |  | 
|---|
| [9fd9d015] | 342 | return existing; | 
|---|
| [401e61f] | 343 | } // build_waitfor | 
|---|
| [135b431] | 344 |  | 
|---|
| [bb7422a] | 345 | ast::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 ) ); | 
|---|
| [135b431] | 348 |  | 
|---|
| [bb7422a] | 349 | (void)location; | 
|---|
| [9fd9d015] | 350 | return existing; | 
|---|
|  | 351 | } // build_waitfor_else | 
|---|
| [135b431] | 352 |  | 
|---|
| [bb7422a] | 353 | ast::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 ) ); | 
|---|
| [135b431] | 357 |  | 
|---|
| [bb7422a] | 358 | (void)location; | 
|---|
| [9fd9d015] | 359 | return existing; | 
|---|
| [401e61f] | 360 | } // build_waitfor_timeout | 
|---|
| [135b431] | 361 |  | 
|---|
| [c86b08d] | 362 | ast::WaitUntilStmt::ClauseNode * build_waituntil_clause( const CodeLocation & loc, ExpressionNode * when, ExpressionNode * targetExpr, StatementNode * stmt ) { | 
|---|
|  | 363 | ast::WhenClause * clause = new ast::WhenClause( loc ); | 
|---|
|  | 364 | clause->when_cond = notZeroExpr( maybeMoveBuild( when ) ); | 
|---|
|  | 365 | clause->stmt = maybeMoveBuild( stmt ); | 
|---|
|  | 366 | clause->target = maybeMoveBuild( targetExpr ); | 
|---|
|  | 367 | return new ast::WaitUntilStmt::ClauseNode( clause ); | 
|---|
|  | 368 | } | 
|---|
|  | 369 | ast::WaitUntilStmt::ClauseNode * build_waituntil_else( const CodeLocation & loc, ExpressionNode * when, StatementNode * stmt ) { | 
|---|
|  | 370 | ast::WhenClause * clause = new ast::WhenClause( loc ); | 
|---|
|  | 371 | clause->when_cond = notZeroExpr( maybeMoveBuild( when ) ); | 
|---|
|  | 372 | clause->stmt = maybeMoveBuild( stmt ); | 
|---|
|  | 373 | return new ast::WaitUntilStmt::ClauseNode( ast::WaitUntilStmt::ClauseNode::Op::ELSE, clause ); | 
|---|
|  | 374 | } | 
|---|
|  | 375 | ast::WaitUntilStmt::ClauseNode * build_waituntil_timeout( const CodeLocation & loc, ExpressionNode * when, ExpressionNode * timeout, StatementNode * stmt ) { | 
|---|
|  | 376 | ast::WhenClause * clause = new ast::WhenClause( loc ); | 
|---|
|  | 377 | clause->when_cond = notZeroExpr( maybeMoveBuild( when ) ); | 
|---|
|  | 378 | clause->stmt = maybeMoveBuild( stmt ); | 
|---|
|  | 379 | clause->target = maybeMoveBuild( timeout ); | 
|---|
|  | 380 | return new ast::WaitUntilStmt::ClauseNode( ast::WaitUntilStmt::ClauseNode::Op::TIMEOUT, clause ); | 
|---|
|  | 381 | } | 
|---|
|  | 382 |  | 
|---|
|  | 383 | ast::WaitUntilStmt * build_waituntil_stmt( const CodeLocation & loc, ast::WaitUntilStmt::ClauseNode * root ) { | 
|---|
|  | 384 | ast::WaitUntilStmt * retStmt = new ast::WaitUntilStmt( loc ); | 
|---|
|  | 385 | retStmt->predicateTree = root; | 
|---|
|  | 386 |  | 
|---|
|  | 387 | // iterative tree traversal | 
|---|
|  | 388 | std::vector<ast::WaitUntilStmt::ClauseNode *> nodeStack; // stack needed for iterative traversal | 
|---|
|  | 389 | ast::WaitUntilStmt::ClauseNode * currNode = nullptr; | 
|---|
|  | 390 | ast::WaitUntilStmt::ClauseNode * lastInternalNode = nullptr; | 
|---|
|  | 391 | ast::WaitUntilStmt::ClauseNode * cleanup = nullptr; // used to cleanup removed else/timeout | 
|---|
|  | 392 | nodeStack.push_back(root); | 
|---|
|  | 393 |  | 
|---|
|  | 394 | do { | 
|---|
|  | 395 | currNode = nodeStack.back(); | 
|---|
|  | 396 | nodeStack.pop_back(); // remove node since it will be processed | 
|---|
|  | 397 |  | 
|---|
|  | 398 | switch (currNode->op) { | 
|---|
|  | 399 | case ast::WaitUntilStmt::ClauseNode::LEAF: | 
|---|
|  | 400 | retStmt->clauses.push_back(currNode->leaf); | 
|---|
|  | 401 | break; | 
|---|
|  | 402 | case ast::WaitUntilStmt::ClauseNode::ELSE: | 
|---|
|  | 403 | retStmt->else_stmt = currNode->leaf->stmt | 
|---|
|  | 404 | ? ast::deepCopy( currNode->leaf->stmt ) | 
|---|
|  | 405 | : nullptr; | 
|---|
|  | 406 |  | 
|---|
|  | 407 | retStmt->else_cond = currNode->leaf->when_cond | 
|---|
|  | 408 | ? ast::deepCopy( currNode->leaf->when_cond ) | 
|---|
|  | 409 | : nullptr; | 
|---|
|  | 410 |  | 
|---|
|  | 411 | delete currNode->leaf; | 
|---|
|  | 412 | break; | 
|---|
|  | 413 | case ast::WaitUntilStmt::ClauseNode::TIMEOUT: | 
|---|
|  | 414 | retStmt->timeout_time = currNode->leaf->target | 
|---|
|  | 415 | ? ast::deepCopy( currNode->leaf->target ) | 
|---|
|  | 416 | : nullptr; | 
|---|
|  | 417 | retStmt->timeout_stmt = currNode->leaf->stmt | 
|---|
|  | 418 | ? ast::deepCopy( currNode->leaf->stmt ) | 
|---|
|  | 419 | : nullptr; | 
|---|
|  | 420 | retStmt->timeout_cond = currNode->leaf->when_cond | 
|---|
|  | 421 | ? ast::deepCopy( currNode->leaf->when_cond ) | 
|---|
|  | 422 | : nullptr; | 
|---|
|  | 423 |  | 
|---|
|  | 424 | delete currNode->leaf; | 
|---|
|  | 425 | break; | 
|---|
|  | 426 | default: | 
|---|
|  | 427 | nodeStack.push_back( currNode->right ); // process right after left | 
|---|
|  | 428 | nodeStack.push_back( currNode->left ); | 
|---|
|  | 429 |  | 
|---|
|  | 430 | // Cut else/timeout out of the tree | 
|---|
|  | 431 | if ( currNode->op == ast::WaitUntilStmt::ClauseNode::LEFT_OR ) { | 
|---|
|  | 432 | if ( lastInternalNode ) | 
|---|
|  | 433 | lastInternalNode->right = currNode->left; | 
|---|
|  | 434 | else    // if not set then root is LEFT_OR | 
|---|
|  | 435 | retStmt->predicateTree = currNode->left; | 
|---|
|  | 436 |  | 
|---|
|  | 437 | currNode->left = nullptr; | 
|---|
|  | 438 | cleanup = currNode; | 
|---|
|  | 439 | } | 
|---|
|  | 440 |  | 
|---|
|  | 441 | lastInternalNode = currNode; | 
|---|
|  | 442 | break; | 
|---|
|  | 443 | } | 
|---|
|  | 444 | } while ( !nodeStack.empty() ); | 
|---|
|  | 445 |  | 
|---|
|  | 446 | if ( cleanup ) delete cleanup; | 
|---|
|  | 447 |  | 
|---|
|  | 448 | return retStmt; | 
|---|
|  | 449 | } | 
|---|
|  | 450 |  | 
|---|
| [bb7422a] | 451 | ast::Stmt * build_with( const CodeLocation & location, ExpressionNode * exprs, StatementNode * stmt ) { | 
|---|
|  | 452 | std::vector<ast::ptr<ast::Expr>> e; | 
|---|
| [a378ca7] | 453 | buildMoveList( exprs, e ); | 
|---|
| [bb7422a] | 454 | ast::Stmt * s = maybeMoveBuild( stmt ); | 
|---|
|  | 455 | return new ast::DeclStmt( location, new ast::WithStmt( location, std::move( e ), s ) ); | 
|---|
| [401e61f] | 456 | } // build_with | 
|---|
| [a378ca7] | 457 |  | 
|---|
| [bb7422a] | 458 | ast::Stmt * build_compound( const CodeLocation & location, StatementNode * first ) { | 
|---|
|  | 459 | auto cs = new ast::CompoundStmt( location ); | 
|---|
|  | 460 | buildMoveList( first, cs->kids ); | 
|---|
| [b87a5ed] | 461 | return cs; | 
|---|
| [401e61f] | 462 | } // build_compound | 
|---|
| [51b73452] | 463 |  | 
|---|
| [a025ea8] | 464 | // A single statement in a control structure is always converted to a compound statement so subsequent generated code | 
|---|
|  | 465 | // can be placed within this compound statement. Otherwise, code generation has to constantly check for a single | 
|---|
|  | 466 | // statement and wrap it into a compound statement to insert additional code. Hence, all control structures have a | 
|---|
|  | 467 | // conical form for code generation. | 
|---|
| [bb7422a] | 468 | StatementNode * maybe_build_compound( const CodeLocation & location, StatementNode * first ) { | 
|---|
| [a025ea8] | 469 | // Optimization: if the control-structure statement is a compound statement, do not wrap it. | 
|---|
|  | 470 | // e.g., if (...) {...} do not wrap the existing compound statement. | 
|---|
| [bb7422a] | 471 | if ( !dynamic_cast<ast::CompoundStmt *>( first->stmt.get() ) ) { // unique_ptr | 
|---|
|  | 472 | return new StatementNode( build_compound( location, first ) ); | 
|---|
| [a025ea8] | 473 | } // if | 
|---|
|  | 474 | return first; | 
|---|
|  | 475 | } // maybe_build_compound | 
|---|
|  | 476 |  | 
|---|
| [f135b50] | 477 | // Question | 
|---|
| [32d6fdc] | 478 | ast::Stmt * build_asm( const CodeLocation & location, bool is_volatile, ExpressionNode * instruction, ExpressionNode * output, ExpressionNode * input, ExpressionNode * clobber, LabelNode * gotolabels ) { | 
|---|
| [bb7422a] | 479 | std::vector<ast::ptr<ast::Expr>> out, in; | 
|---|
|  | 480 | std::vector<ast::ptr<ast::ConstantExpr>> clob; | 
|---|
| [e82aa9df] | 481 |  | 
|---|
| [7ecbb7e] | 482 | buildMoveList( output, out ); | 
|---|
|  | 483 | buildMoveList( input, in ); | 
|---|
|  | 484 | buildMoveList( clobber, clob ); | 
|---|
| [bb7422a] | 485 | return new ast::AsmStmt( location, | 
|---|
| [32d6fdc] | 486 | is_volatile, | 
|---|
|  | 487 | maybeMoveBuild( instruction ), | 
|---|
| [bb7422a] | 488 | std::move( out ), | 
|---|
|  | 489 | std::move( in ), | 
|---|
|  | 490 | std::move( clob ), | 
|---|
|  | 491 | gotolabels ? gotolabels->labels : std::vector<ast::Label>() | 
|---|
|  | 492 | ); | 
|---|
| [401e61f] | 493 | } // build_asm | 
|---|
| [7f5566b] | 494 |  | 
|---|
| [bb7422a] | 495 | ast::Stmt * build_directive( const CodeLocation & location, string * directive ) { | 
|---|
|  | 496 | auto stmt = new ast::DirectiveStmt( location, *directive ); | 
|---|
|  | 497 | delete directive; | 
|---|
|  | 498 | return stmt; | 
|---|
| [401e61f] | 499 | } // build_directive | 
|---|
| [61fc4f6] | 500 |  | 
|---|
| [bb7422a] | 501 | ast::Stmt * build_mutex( const CodeLocation & location, ExpressionNode * exprs, StatementNode * stmt ) { | 
|---|
|  | 502 | std::vector<ast::ptr<ast::Expr>> expList; | 
|---|
| [de52331] | 503 | buildMoveList( exprs, expList ); | 
|---|
| [bb7422a] | 504 | ast::Stmt * body = maybeMoveBuild( stmt ); | 
|---|
|  | 505 | return new ast::MutexStmt( location, body, std::move( expList ) ); | 
|---|
| [de52331] | 506 | } // build_mutex | 
|---|
|  | 507 |  | 
|---|
| [51b73452] | 508 | // Local Variables: // | 
|---|
| [b87a5ed] | 509 | // tab-width: 4 // | 
|---|
|  | 510 | // mode: c++ // | 
|---|
|  | 511 | // compile-command: "make install" // | 
|---|
| [51b73452] | 512 | // End: // | 
|---|