source: src/CodeGen/CodeGenerator.cpp@ 56ec508

Last change on this file since 56ec508 was e48aca8, checked in by Andrew Beach <ajbeach@…>, 6 months ago

Added support for code generation of the CountofExpr. This doesn't do anything to final output but is useful for debugging.

  • Property mode set to 100644
File size: 36.8 KB
RevLine 
[8941b6b]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//
[83fd57d]7// CodeGenerator.cpp --
[8941b6b]8//
9// Author : Andrew Beach
10// Created On : Tue Oct 17 15:54:00 2023
[d96f7c4]11// Last Modified By : Peter A. Buhr
12// Last Modified On : Fri Jan 17 14:19:22 2025
13// Update Count : 1
[8941b6b]14//
15
[83fd57d]16#include "CodeGenerator.hpp"
[8941b6b]17
18#include "AST/Print.hpp"
[c92bdcc]19#include "OperatorTable.hpp" // for OperatorInfo, operatorLookup
20#include "CodeGen/GenType.hpp" // for genType
[8941b6b]21#include "Common/ToString.hpp" // for toString
[c92bdcc]22#include "Common/UniqueName.hpp" // for UniqueName
[8941b6b]23
24namespace CodeGen {
25
[0bd3faf]26int CodeGenerator::tabsize = 4;
[8941b6b]27
28// The kinds of statements that should be followed by whitespace.
29static bool wantSpacing( ast::Stmt const * stmt ) {
30 return dynamic_cast<ast::IfStmt const *>( stmt )
31 || dynamic_cast<ast::CompoundStmt const *>( stmt )
32 || dynamic_cast<ast::WhileDoStmt const *>( stmt )
33 || dynamic_cast<ast::ForStmt const *>( stmt )
34 || dynamic_cast<ast::SwitchStmt const *>( stmt );
35}
36
[0bd3faf]37void CodeGenerator::extension( ast::Expr const * expr ) {
[8941b6b]38 if ( expr->extension ) output << "__extension__ ";
39}
40
[0bd3faf]41void CodeGenerator::extension( ast::Decl const * decl ) {
[8941b6b]42 if ( decl->extension ) output << "__extension__ ";
43}
44
[0bd3faf]45void CodeGenerator::asmName( ast::DeclWithType const * decl ) {
[8941b6b]46 if ( auto asmName = decl->asmName.as<ast::ConstantExpr>() ) {
47 output << " asm ( " << asmName->rep << " )";
48 }
49}
50
[0bd3faf]51CodeGenerator::LabelPrinter & CodeGenerator::LabelPrinter::operator()(
[8941b6b]52 std::vector<ast::Label> const & l ) {
53 labels = &l;
54 return *this;
55}
56
[0bd3faf]57std::ostream & CodeGenerator::LabelPrinter::operator()( std::ostream & output ) const {
[8941b6b]58 const std::vector<ast::Label> & labels = *this->labels;
59 for ( const ast::Label & label : labels ) {
60 output << label.name + ": ";
61 this->cg.genAttributes( label.attributes );
62 }
63 return output;
64}
65
66// Using updateLocation at the beginning of a node and endl within a node
67// should become the method of formating.
[0bd3faf]68void CodeGenerator::updateLocation( CodeLocation const & to ) {
[8941b6b]69 // Skip if linemarks shouldn't appear or if location is unset.
70 if ( !options.lineMarks || to.isUnset() ) return;
71
72 if ( currentLocation.followedBy( to, 0 ) ) {
73 return;
74 } else if ( currentLocation.followedBy( to, 1 ) ) {
75 output << "\n" << indent;
76 currentLocation.first_line += 1;
77 } else if ( currentLocation.followedBy( to, 2 ) ) {
78 output << "\n\n" << indent;
79 currentLocation.first_line += 2;
80 } else {
[661e7b0]81 output << "\n# " << to.first_line << " \"" << to.filename.c_str()
[8941b6b]82 << "\"\n" << indent;
83 currentLocation = to;
84 }
85 output << std::flush;
86}
87
[0bd3faf]88void CodeGenerator::updateLocation( ast::ParseNode const * to ) {
[8941b6b]89 updateLocation( to->location );
90}
91
[0bd3faf]92std::ostream & CodeGenerator::LineEnder::operator()( std::ostream & os ) const {
[8941b6b]93 os << "\n" << std::flush;
94 cg.currentLocation.first_line++;
95 return os;
96}
97
[0bd3faf]98CodeGenerator::CodeGenerator( std::ostream & os, const Options & options ) :
99 indent( 0, CodeGenerator::tabsize ), output( os ),
[8941b6b]100 options( options ), printLabels( *this ), endl( *this )
101{}
102
[0bd3faf]103std::string CodeGenerator::mangleName( ast::DeclWithType const * decl ) {
[c7ebbec]104 if ( !options.pretty && decl->linkage.is_mangled && decl->mangleName != "" ) {
[8941b6b]105 return decl->scopedMangleName();
106 } else {
107 return decl->name;
108 }
109}
110
[0bd3faf]111void CodeGenerator::genAttributes(
[8941b6b]112 const std::vector<ast::ptr<ast::Attribute>> & attributes ) {
113 if ( attributes.empty() ) return;
114 output << "__attribute__ ((";
115 for ( auto attr = attributes.begin() ;; ) {
116 output << (*attr)->name;
117 if ( !(*attr)->params.empty() ) {
118 output << "(";
119 genCommaList( (*attr)->params );
120 output << ")";
121 }
122 if ( ++attr == attributes.end() ) break;
123 output << ",";
124 }
125 output << ")) ";
126}
127
[0bd3faf]128void CodeGenerator::previsit( ast::Node const * ) {
[8941b6b]129 // All traversal is manual.
130 // TODO: Which means the ast::Pass is just providing a default no visit?
131 visit_children = false;
[7959e56]132 changeState_ArgToIntrinsic(false);
[8941b6b]133}
134
[0bd3faf]135void CodeGenerator::previsit( ast::ParseNode const * node ) {
[8941b6b]136 previsit( (ast::Node const *)node );
137 updateLocation( node );
138}
139
[0bd3faf]140void CodeGenerator::postvisit( ast::Node const * node ) {
[8941b6b]141 std::stringstream ss;
142 ast::print( ss, node );
143 assertf( false, "Unhandled node reached in CodeGenerator: %s", ss.str().c_str() );
144}
145
[0bd3faf]146void CodeGenerator::previsit( ast::Expr const * expr ) {
[8941b6b]147 previsit( (ast::ParseNode const *)expr );
148 GuardAction( [this, expr](){
149 if ( options.printExprTypes && expr->result ) {
150 output << " /* " << genType( expr->result, "", options ) << " */ ";
151 }
152 } );
153}
154
[0bd3faf]155void CodeGenerator::postvisit( ast::FunctionDecl const * decl ) {
[8941b6b]156 // Deleted decls should never be used, so don't print them in C.
157 if ( decl->isDeleted && options.genC ) return;
158 extension( decl );
159 genAttributes( decl->attributes );
160
161 handleStorageClass( decl );
162 ast::print( output, decl->funcSpec );
163
164 Options subOptions = options;
165 subOptions.anonymousUnused = decl->stmts;
166
167 std::ostringstream acc;
[0bd3faf]168 ast::Pass<CodeGenerator> subCG( acc, subOptions );
[8941b6b]169 // Add the forall clause.
[3c4003b9]170 if ( !decl->type_params.empty() ) {
171 assertf( !options.genC, "FunctionDecl forall should not reach code generation." );
[8941b6b]172 acc << "forall(";
173 subCG.core.genCommaList( decl->type_params );
174 acc << ")" << std::endl;
175 }
[a1fbad0]176 // The forall clause should be printed early as part of the preamble.
177 output << acc.str();
178 acc.str("");
[8941b6b]179
180 acc << mangleName( decl );
181
182 if ( 0 == decl->params.size() ) {
[db19e1d]183 if ( !decl->type->isVarArgs ) {
184 acc << "(void)";
185 } else if ( options.genC ) {
[8941b6b]186 acc << "()";
187 } else {
[db19e1d]188 acc << "(...)";
[8941b6b]189 }
190 } else {
191 acc << "(";
192 subCG.core.genCommaList( decl->params );
193 if ( decl->type->isVarArgs ) {
194 acc << ", ...";
195 }
196 acc << ")";
197 }
198
199 if ( 1 == decl->returns.size() ) {
200 ast::ptr<ast::Type> const & type = decl->returns[0]->get_type();
201 output << genTypeNoAttr( type, acc.str(), subOptions );
[0139351]202 } else if ( 0 == decl->returns.size() ) {
[8941b6b]203 output << "void " + acc.str();
[0139351]204 } else {
205 assertf( !options.genC, "Multi-return should not reach code generation." );
206 ast::ptr<ast::Type> type = new ast::TupleType( copy( decl->type->returns ) );
207 output << genTypeNoAttr( type, acc.str(), subOptions );
[8941b6b]208 }
209
210 asmName( decl );
211
212 if ( decl->stmts ) {
213 decl->stmts->accept( *visitor );
214 }
215 if ( decl->isDeleted ) {
216 output << " = void";
217 }
218}
219
[0bd3faf]220ast::ObjectDecl const * CodeGenerator::postvisit(
[8941b6b]221 ast::ObjectDecl const * decl ) {
222 // Deleted decls should never be used, so don't print them in C.
223 if ( decl->isDeleted && options.genC ) return decl;
224
225 // GCC allows an empty declarator (no name) for bit-fields and C
226 // states: 6.7.2.1 Structure and union specifiers, point 4, page 113:
227 // If the (bit field) value is zero, the declaration shall have no
228 // declarator. For anything else, the anonymous name refers to the
229 // anonymous object for plan9 inheritance.
230 if ( decl->name.empty() && options.genC && !decl->bitfieldWidth ) {
231 // TODO: Should this be changed in a pervious pass?
232 auto mutDecl = ast::mutate( decl );
233 // Only generate an anonymous name when generating C code,
234 // otherwise it clutters the output too much.
235 static UniqueName name = { "__anonymous_object" };
236 mutDecl->name = name.newName();
237 // Stops unused parameter warnings.
238 if ( options.anonymousUnused ) {
239 mutDecl->attributes.push_back( new ast::Attribute( "unused" ) );
240 }
241 decl = mutDecl;
242 }
243
244 extension( decl );
245 genAttributes( decl->attributes );
246
247 handleStorageClass( decl );
248 output << genType( decl->type, mangleName( decl ),
249 Options( options.pretty, options.genC, false, false ) );
250
251 asmName( decl );
252
253 if ( decl->init ) {
[f070ea8]254 bool isGenericInit = options.genC || decl->init->maybeConstructed;
255 output << ( (isGenericInit) ? " = " : " @= " );
[8941b6b]256 decl->init->accept( *visitor );
257 }
258 if ( decl->isDeleted ) {
259 output << " = void";
260 }
261
262 if ( decl->bitfieldWidth ) {
263 output << ":";
264 decl->bitfieldWidth->accept( *visitor );
265 }
266 return decl;
267}
268
[0bd3faf]269void CodeGenerator::handleStorageClass( ast::DeclWithType const * decl ) {
[8941b6b]270 if ( decl->storage.any() ) {
271 ast::print( output, decl->storage );
272 }
273}
274
[0bd3faf]275void CodeGenerator::handleAggregate(
[8941b6b]276 ast::AggregateDecl const * decl, std::string const & kind ) {
277 if ( !decl->params.empty() && !options.genC ) {
278 output << "forall(";
279 genCommaList( decl->params );
280 output << ")\n" << indent << std::flush;
281 }
282
283 output << kind;
284 genAttributes( decl->attributes );
285 output << decl->name;
286
287 if ( decl->body ) {
288 auto & members = decl->members;
289 output << " {" << endl;
290
291 ++indent;
292 for ( auto & member : members ) {
293 output << indent;
294 member->accept( *visitor );
295 output << ";" << endl;
296 }
297 --indent;
298
299 output << indent << "}";
300 }
301}
302
[0bd3faf]303void CodeGenerator::postvisit( ast::StructDecl const * decl ) {
[8941b6b]304 extension( decl );
305 handleAggregate( decl, "struct " );
306}
307
[0bd3faf]308void CodeGenerator::postvisit( ast::UnionDecl const * decl ) {
[8941b6b]309 extension( decl );
310 handleAggregate( decl, "union " );
311}
312
313template<typename pass_type>
314inline void genEnumInitializer( ast::Pass<pass_type> * visitor,
315 ast::Type const * baseType, std::ostream & output,
316 ast::Init const * init, long long * curVal, Options options ) {
317 auto baseTypeAsBasic = dynamic_cast<ast::BasicType const *>( baseType );
318 // Value is provided.
319 if ( init ) {
320 output << " = (" << genType( baseType, "", options ) << ")";
321 init->accept( *visitor );
322 // If it is an integral type and initilizer offered,
323 // need to update the curVal.
324 if ( baseTypeAsBasic && baseTypeAsBasic->isInteger() ) {
325 ast::Expr const * expr = ((ast::SingleInit const *)(init))->value;
326 // Unwrap introduced cast.
327 while ( auto temp = dynamic_cast<ast::CastExpr const *>( expr ) ) {
328 expr = temp->arg;
329 }
330 *curVal = ((ast::ConstantExpr const *)(expr))->intValue() + 1;
331 }
332 // Generate next value from previous value.
333 } else if ( baseTypeAsBasic && baseTypeAsBasic->isInteger() ) {
334 output << " = (" << genType( baseType, "", options ) << ")";
335 output << (*curVal)++;
336 }
337}
338
[0bd3faf]339void CodeGenerator::postvisit( ast::EnumDecl const * decl ) {
[8941b6b]340 extension( decl );
341 auto members = decl->members;
[c75b30a]342 // if ( decl->base && !members.empty() ) {
343 // long long curVal = 0;
344 // for ( auto member : members ) {
345 // auto obj = member.strict_as<ast::ObjectDecl>();
346 // output << "static ";
347 // output << genType( decl->base, mangleName( obj ), options );
348 // genEnumInitializer( visitor, decl->base, output, obj->init, &curVal, options );
349 // output << ";" << endl;
350 // }
351 // } else {
[8941b6b]352 output << "enum ";
353 genAttributes( decl->attributes );
354
355 output << decl->name;
356
357 if ( !members.empty() ) {
358 output << " {" << endl;
359
360 ++indent;
361 for ( auto member : members ) {
362 auto obj = member.strict_as<ast::ObjectDecl>();
363 output << indent << mangleName( obj );
[c75b30a]364 if ( !decl->base && obj->init ) {
[8941b6b]365 output << " = ";
366 obj->init->accept( *visitor );
367 }
368 output << "," << endl;
369 }
370 --indent;
371
372 output << indent << "}";
373 }
[c75b30a]374 // }
[8941b6b]375}
376
[0bd3faf]377void CodeGenerator::postvisit( ast::TraitDecl const * decl ) {
[8941b6b]378 assertf( !options.genC, "TraitDecls should not reach code generation." );
379 extension( decl );
380 handleAggregate( decl, "trait " );
381}
382
[0bd3faf]383void CodeGenerator::postvisit( ast::TypedefDecl const * decl ) {
[8941b6b]384 assertf( !options.genC, "Typedefs should not reach code generation." );
385 output << "typedef " << genType( decl->base, decl->name, options ) << endl;
386}
387
[0bd3faf]388void CodeGenerator::postvisit( ast::TypeDecl const * decl ) {
[8941b6b]389 assertf( !options.genC, "TypeDecls should not reach code generation." );
390 output << decl->genTypeString() << " " << decl->name;
391 if ( decl->sized ) {
392 output << " | sized(" << decl->name << ")";
393 }
394 if ( !decl->assertions.empty() ) {
395 output << " | { ";
396 for ( ast::DeclWithType const * assert : decl->assertions ) {
397 assert->accept( *visitor );
398 output << "; ";
399 }
400 output << " }";
401 }
402}
403
[0bd3faf]404void CodeGenerator::postvisit( ast::StaticAssertDecl const * decl ) {
[8941b6b]405 output << "_Static_assert(";
406 decl->cond->accept( *visitor );
407 output << ", ";
408 decl->msg->accept( *visitor );
409 output << ")";
410}
411
[0bd3faf]412void CodeGenerator::postvisit( ast::Designation const * designation ) {
[8941b6b]413 auto designators = designation->designators;
414 if ( 0 == designators.size() ) return;
415 for ( ast::ptr<ast::Expr> const & des : designators ) {
416 // If the expression is a NameExpr or VariableExpr, then it is a field.
417 if ( des.as<ast::NameExpr>() || des.as<ast::VariableExpr>() ) {
418 output << ".";
419 des->accept( *visitor );
420 // Otherwise, it is a ConstantExpr or CastExpr, then it is an index.
421 } else {
422 output << "[";
423 des->accept( *visitor );
424 output << "]";
425 }
426 }
427 output << " = ";
428}
429
[0bd3faf]430void CodeGenerator::postvisit( ast::SingleInit const * init ) {
[8941b6b]431 init->value->accept( *visitor );
432}
433
[0bd3faf]434void CodeGenerator::postvisit( ast::ListInit const * init ) {
[8941b6b]435 auto initBegin = init->initializers.begin();
436 auto initEnd = init->initializers.end();
437 auto desigBegin = init->designations.begin();
438 auto desigEnd = init->designations.end();
439
440 output << "{ ";
441 if ( initBegin != initEnd ) while (true) {
442 (*desigBegin)->accept( *visitor );
443 (*initBegin)->accept( *visitor );
444 ++initBegin, ++desigBegin;
445 if ( initBegin == initEnd ) break;
446 output << ", ";
447 }
448 output << " }";
449 assertf( initBegin == initEnd && desigBegin == desigEnd,
450 "Initializers and designators not the same length. %s", toCString( init ) );
451}
452
[0bd3faf]453void CodeGenerator::postvisit( ast::ConstructorInit const * init ) {
[8941b6b]454 assertf( !options.genC, "ConstructorInit nodes should not reach code generation." );
455 // This isn't actual code, but labels the constructor/destructor pairs.
456 output << "<ctorinit>{" << endl << ++indent << "ctor: ";
457 if ( init->ctor ) init->ctor->accept( *visitor );
458 output << ", " << endl << indent << "dtor: ";
459 if ( init->dtor ) init->dtor->accept( *visitor );
460 output << endl << --indent << "}";
461}
462
[0bd3faf]463void CodeGenerator::postvisit( ast::ApplicationExpr const * expr ) {
[8941b6b]464 extension( expr );
465 if ( auto var = expr->func.as<ast::VariableExpr>() ) {
466 const OperatorInfo * opInfo;
467 if ( var->var->linkage == ast::Linkage::Intrinsic &&
468 ( opInfo = operatorLookup( var->var->name ) ) ) {
[7959e56]469 changeState_ArgToIntrinsic(true);
[8941b6b]470 auto arg = expr->args.begin();
471 switch ( opInfo->type ) {
472 case OT_INDEX:
473 assert( 2 == expr->args.size() );
474 (*arg++)->accept( *visitor );
475 output << "[";
476 (*arg)->accept( *visitor );
477 output << "]";
478 break;
479
480 // There are no intrinsic definitions of the function call operator.
481 case OT_CALL:
482 assert( false );
483 break;
484
485 case OT_CTOR:
486 case OT_DTOR:
487 // No-op constructor, but run the internal expression.
488 if ( 1 == expr->args.size() ) {
489 output << "(";
490 (*arg++)->accept( *visitor );
491 output << ") /* " << opInfo->inputName << " */";
492 // These are all implemented as some form of assignment.
493 } else if ( 2 == expr->args.size() ) {
494 output << "(";
495 (*arg++)->accept( *visitor );
496 output << opInfo->symbol;
497 (*arg)->accept( *visitor );
498 output << ") /* " << opInfo->inputName << " */";
499 // No constructors with 0 or more than 2 parameters.
500 } else {
501 assert( false );
502 }
503 break;
504
505 case OT_PREFIX:
506 case OT_PREFIXASSIGN:
507 assert( 1 == expr->args.size() );
508 output << "(" << opInfo->symbol;
509 (*arg)->accept( *visitor );
510 output << ")";
511 break;
512
513 case OT_POSTFIX:
514 case OT_POSTFIXASSIGN:
515 assert( 1 == expr->args.size() );
516 (*arg)->accept( *visitor );
517 output << opInfo->symbol;
518 break;
519
520 case OT_INFIX:
521 case OT_INFIXASSIGN:
522 assert( 2 == expr->args.size() );
523 output << "(";
524 (*arg++)->accept( *visitor );
525 output << opInfo->symbol;
526 (*arg)->accept( *visitor );
527 output << ")";
528 break;
529
530 // There are no intrinsic definitions of 0/1 or label address
531 // as function.
532 case OT_CONSTANT:
533 case OT_LABELADDRESS:
534 assert( false );
535 }
536 // TODO: This is a work-around to make it a constant until a proper
537 // constexpr solution is created.
538 } else if ( var->var->linkage == ast::Linkage::BuiltinCFA &&
539 var->var->name == "intptr" ) {
540 output << "((void*)";
541 auto arg = expr->args.begin();
542 (*arg++)->accept( *visitor );
543 output << ")";
544 } else {
545 var->accept( *visitor );
546 output << "(";
547 genCommaList( expr->args );
548 output << ")";
549 }
550 } else {
551 expr->func->accept( *visitor );
552 output << "(";
553 genCommaList( expr->args );
554 output << ")";
555 }
556}
557
[0bd3faf]558void CodeGenerator::postvisit( ast::UntypedExpr const * expr ) {
[8941b6b]559 extension( expr );
560 if ( auto name = expr->func.as<ast::NameExpr>() ) {
561 if ( const OperatorInfo * opInfo = operatorLookup( name->name ) ) {
[7959e56]562 changeState_ArgToIntrinsic(true);
[8941b6b]563 auto arg = expr->args.begin();
564 switch ( opInfo->type ) {
565 case OT_INDEX:
566 assert( 2 == expr->args.size() );
567 (*arg++)->accept( *visitor );
568 output << "[";
569 (*arg)->accept( *visitor );
570 output << "]";
571 break;
572
573 case OT_CALL:
574 assert( false );
575
576 case OT_CTOR:
577 case OT_DTOR:
578 // No-op constructor, but run the internal expression.
579 if ( 1 == expr->args.size() ) {
580 output << "(";
581 (*arg++)->accept( *visitor );
582 output << ")";
583 // These are all implemented as some form of assignment.
584 } else if ( 2 == expr->args.size() ) {
585 output << "(";
586 (*arg++)->accept( *visitor );
587 output << opInfo->symbol;
588 (*arg)->accept( *visitor );
589 output << ") /* " << opInfo->inputName << " */";
590 // No constructors with 0 or more than 2 parameters.
591 } else {
592 assertf( !options.genC, "UntypedExpr constructor/destructor with 0 or more than 2 parameters." );
593 output << "(";
594 (*arg++)->accept( *visitor );
595 output << opInfo->symbol << "{ ";
596 genCommaList( arg, expr->args.end() );
597 output << "}) /* " << opInfo->inputName << " */";
598 }
599 break;
600
601 case OT_PREFIX:
602 case OT_PREFIXASSIGN:
603 case OT_LABELADDRESS:
604 assert( 1 == expr->args.size() );
605 output << "(" << opInfo->symbol;
606 (*arg)->accept( *visitor );
607 output << ")";
608 break;
609
610 case OT_POSTFIX:
611 case OT_POSTFIXASSIGN:
612 assert( 1 == expr->args.size() );
613 (*arg)->accept( *visitor );
614 output << opInfo->symbol;
615 break;
616
617 case OT_INFIX:
618 case OT_INFIXASSIGN:
619 assert( 2 == expr->args.size() );
620 output << "(";
621 (*arg++)->accept( *visitor );
622 output << opInfo->symbol;
623 (*arg)->accept( *visitor );
624 output << ")";
625 break;
626
627 // There are no intrinsic definitions of 0/1 or label address
628 // as function.
629 case OT_CONSTANT:
630 assert( false );
631 }
632 // builtin routines
633 } else {
634 name->accept( *visitor );
635 output << "(";
636 genCommaList( expr->args );
637 output << ")";
638 }
639 } else {
640 expr->func->accept( *visitor );
641 output << "(";
642 genCommaList( expr->args );
643 output << ")";
644 }
645}
646
[0bd3faf]647void CodeGenerator::postvisit( ast::RangeExpr const * expr ) {
[8941b6b]648 expr->low->accept( *visitor );
649 output << " ... ";
650 expr->high->accept( *visitor );
651}
652
[0bd3faf]653void CodeGenerator::postvisit( ast::NameExpr const * expr ) {
[8941b6b]654 extension( expr );
655 if ( const OperatorInfo * opInfo = operatorLookup( expr->name ) ) {
656 if ( OT_CONSTANT == opInfo->type ) {
657 output << opInfo->symbol;
658 } else {
659 output << opInfo->outputName;
660 }
661 } else {
662 output << expr->name;
663 }
664}
665
[0bd3faf]666void CodeGenerator::postvisit( ast::DimensionExpr const * expr ) {
[8941b6b]667 extension( expr );
668 output << "/*non-type*/" << expr->name;
669}
670
[0bd3faf]671void CodeGenerator::postvisit( ast::AddressExpr const * expr ) {
[8941b6b]672 extension( expr );
673 output << "(&";
674 expr->arg->accept( *visitor );
675 output << ")";
676}
677
[0bd3faf]678void CodeGenerator::postvisit( ast::LabelAddressExpr const * expr ) {
[8941b6b]679 extension( expr );
680 output << "(&&" << expr->arg << ")";
681}
682
[0bd3faf]683void CodeGenerator::postvisit( ast::CastExpr const * expr ) {
[8941b6b]684 extension( expr );
685 output << "(";
[ecf3812]686 switch ( expr->kind ) {
687 case ast::CCast:
688 if ( expr->result->isVoid() ) {
689 output << "(void)";
690 } else {
691 output << "(";
692 output << genType( expr->result, "", options );
693 output << ")";
694 }
695 break;
696 case ast::CoerceCast:
697 assertf( ast::CoerceCast != expr->kind, "Coercion cast is not implemented." );
698 // And likely shouldn't reach code generation when it is implemented.
699 break;
700 case ast::ReturnCast:
701 // This should be invisible in the resulting C code.
702 // Can we insert a check here?
703 //assert( ResolvExpr::typesCompatable(???) );
704 if ( options.genC ) break;
705 output << "(return ";
[8941b6b]706 output << genType( expr->result, "", options );
707 output << ")";
[ecf3812]708 break;
[8941b6b]709 }
710 expr->arg->accept( *visitor );
711 output << ")";
712}
713
[0bd3faf]714void CodeGenerator::postvisit( ast::KeywordCastExpr const * expr ) {
[8941b6b]715 assertf( !options.genC, "KeywordCastExpr should not reach code generation." );
716 extension( expr );
717 output << "((" << expr->targetString() << " &)";
718 expr->arg->accept( *visitor );
719 output << ")";
720}
721
[0bd3faf]722void CodeGenerator::postvisit( ast::VirtualCastExpr const * expr ) {
[8941b6b]723 assertf( !options.genC, "VirtualCastExpr should not reach code generation." );
724 extension( expr );
725 // TODO: Is this busted?
726 output << "(virtual ";
727 expr->arg->accept( *visitor );
728 output << ")";
729}
730
[0bd3faf]731void CodeGenerator::postvisit( ast::UntypedMemberExpr const * expr ) {
[8941b6b]732 assertf( !options.genC, "UntypedMemberExpr should not reach code generation." );
733 extension( expr );
734 expr->aggregate->accept( *visitor );
735 output << ".";
736 expr->member->accept( *visitor );
737}
738
[0bd3faf]739void CodeGenerator::postvisit( ast::MemberExpr const * expr ) {
[8941b6b]740 extension( expr );
741 expr->aggregate->accept( *visitor );
742 output << "." << mangleName( expr->member );
743}
744
[0bd3faf]745void CodeGenerator::postvisit( ast::VariableExpr const * expr ) {
[8941b6b]746 extension( expr );
747 const OperatorInfo * opInfo;
[7959e56]748 if ( visitingArgToIntrinsic
749 && options.genC
750 && dynamic_cast<ast::ZeroType const *>( expr->var->get_type() ) ) {
751 // int * p; p = 0; ==> ?=?( p, (zero_t){} ); ==> p = 0;
752 // void f( zero_t z ) { g(z); } ==> g(z); ==> g(z);
753 // (we are at the last '==>')
754 output << "0";
755 } else if ( expr->var->linkage == ast::Linkage::Intrinsic
[8941b6b]756 && ( opInfo = operatorLookup( expr->var->name ) )
757 && opInfo->type == OT_CONSTANT ) {
758 output << opInfo->symbol;
759 } else {
760 output << mangleName( expr->var );
761 }
762}
763
[0bd3faf]764void CodeGenerator::postvisit( ast::ConstantExpr const * expr ) {
[8941b6b]765 extension( expr );
766 output << expr->rep;
767}
768
[0bd3faf]769void CodeGenerator::postvisit( ast::SizeofExpr const * expr ) {
[8941b6b]770 extension( expr );
771 output << "sizeof(";
[b6f2e7ab]772 if ( auto type = expr->type.as<ast::TypeofType>() ) {
773 type->expr->accept( *visitor );
[8941b6b]774 } else {
[b6f2e7ab]775 output << genType( expr->type, "", options );
[8941b6b]776 }
777 output << ")";
778}
779
[0bd3faf]780void CodeGenerator::postvisit( ast::AlignofExpr const * expr ) {
[8941b6b]781 // Using the GCC extension to avoid changing the std to C11.
782 extension( expr );
783 output << "__alignof__(";
[b6f2e7ab]784 if ( auto type = expr->type.as<ast::TypeofType>() ) {
785 type->expr->accept( *visitor );
[8941b6b]786 } else {
[b6f2e7ab]787 output << genType( expr->type, "", options );
[8941b6b]788 }
789 output << ")";
790}
791
[e48aca8]792void CodeGenerator::postvisit( ast::CountofExpr const * expr ) {
793 assertf( !options.genC, "CountofExpr should not reach code generation." );
794 extension( expr );
795 output << "countof(";
796 if ( auto type = expr->type.as<ast::TypeofType>() ) {
797 type->expr->accept( *visitor );
798 } else {
799 output << genType( expr->type, "", options );
800 }
801 output << ")";
802}
803
[0bd3faf]804void CodeGenerator::postvisit( ast::UntypedOffsetofExpr const * expr ) {
[8941b6b]805 assertf( !options.genC, "UntypedOffsetofExpr should not reach code generation." );
806 output << "offsetof(";
807 output << genType( expr->type, "", options );
808 output << ", " << expr->member;
809 output << ")";
810}
811
[0bd3faf]812void CodeGenerator::postvisit( ast::OffsetofExpr const * expr ) {
[8941b6b]813 // Use GCC builtin
814 output << "__builtin_offsetof(";
815 output << genType( expr->type, "", options );
816 output << ", " << mangleName( expr->member );
817 output << ")";
818}
819
[0bd3faf]820void CodeGenerator::postvisit( ast::OffsetPackExpr const * expr ) {
[8941b6b]821 assertf( !options.genC, "OffsetPackExpr should not reach code generation." );
822 output << "__CFA_offsetpack(" << genType( expr->type, "", options ) << ")";
823}
824
[0bd3faf]825void CodeGenerator::postvisit( ast::LogicalExpr const * expr ) {
[8941b6b]826 extension( expr );
827 output << "(";
828 expr->arg1->accept( *visitor );
829 output << ( ( expr->isAnd ) ? " && " : " || " );
830 expr->arg2->accept( *visitor );
831 output << ")";
832}
833
[0bd3faf]834void CodeGenerator::postvisit( ast::ConditionalExpr const * expr ) {
[8941b6b]835 extension( expr );
836 output << "(";
837 expr->arg1->accept( *visitor );
838 output << " ? ";
839 expr->arg2->accept( *visitor );
840 output << " : ";
841 expr->arg3->accept( *visitor );
842 output << ")";
843}
844
[0bd3faf]845void CodeGenerator::postvisit( ast::CommaExpr const * expr ) {
[8941b6b]846 extension( expr );
847 output << "(";
848 if ( options.genC ) {
849 // arg1 of a comma expression is never used, so it can be safely cast
850 // to void to reduce gcc warnings.
851 ast::ptr<ast::Expr> arg1 = new ast::CastExpr( expr->location, expr->arg1 );
852 arg1->accept( *visitor );
853 } else {
854 expr->arg1->accept( *visitor );
855 }
856 output << " , ";
857 expr->arg2->accept( *visitor );
858 output << ")";
859}
860
[0bd3faf]861void CodeGenerator::postvisit( ast::TupleAssignExpr const * expr ) {
[8941b6b]862 assertf( !options.genC, "TupleAssignExpr should not reach code generation." );
863 expr->stmtExpr->accept( *visitor );
864}
865
[0bd3faf]866void CodeGenerator::postvisit( ast::UntypedTupleExpr const * expr ) {
[8941b6b]867 assertf( !options.genC, "UntypedTupleExpr should not reach code generation." );
868 extension( expr );
869 output << "[";
870 genCommaList( expr->exprs );
871 output << "]";
872}
873
[0bd3faf]874void CodeGenerator::postvisit( ast::TupleExpr const * expr ) {
[8941b6b]875 assertf( !options.genC, "TupleExpr should not reach code generation." );
876 extension( expr );
877 output << "[";
878 genCommaList( expr->exprs );
879 output << "]";
880}
881
[0bd3faf]882void CodeGenerator::postvisit( ast::TupleIndexExpr const * expr ) {
[8941b6b]883 assertf( !options.genC, "TupleIndexExpr should not reach code generation." );
884 extension( expr );
885 expr->tuple->accept( *visitor );
886 output << "." << expr->index;
887}
888
[0bd3faf]889void CodeGenerator::postvisit( ast::TypeExpr const * expr ) {
[8941b6b]890 // TODO: Should there be an assertion there?
891 if ( !options.genC ) {
892 output << genType( expr->type, "", options );
893 }
894}
895
[0bd3faf]896void CodeGenerator::postvisit( ast::AsmExpr const * expr ) {
[8941b6b]897 if ( !expr->inout.empty() ) {
898 output << "[ " << expr->inout << " ] ";
899 }
900 expr->constraint->accept( *visitor );
901 output << " ( ";
902 expr->operand->accept( *visitor );
903 output << " )";
904}
905
[0bd3faf]906void CodeGenerator::postvisit( ast::CompoundLiteralExpr const * expr ) {
[8941b6b]907 //assert( expr->result && dynamic_cast<ast::ListInit const *>( expr->init ) );
908 assert( expr->result && expr->init.as<ast::ListInit>() );
909 output << "(" << genType( expr->result, "", options ) << ")";
910 expr->init->accept( *visitor );
911}
912
[0bd3faf]913void CodeGenerator::postvisit( ast::UniqueExpr const * expr ) {
[8941b6b]914 assertf( !options.genC, "UniqueExpr should not reach code generation." );
915 output << "unq<" << expr->id << ">{ ";
916 expr->expr->accept( *visitor );
917 output << " }";
918}
919
[0bd3faf]920void CodeGenerator::postvisit( ast::StmtExpr const * expr ) {
[8941b6b]921 auto stmts = expr->stmts->kids;
922 output << "({" << endl;
923 ++indent;
924 unsigned int numStmts = stmts.size();
925 unsigned int i = 0;
926 for ( ast::ptr<ast::Stmt> const & stmt : stmts ) {
927 output << indent << printLabels( stmt->labels );
928 if ( i + 1 == numStmts ) {
929 // Last statement in a statement expression needs to be handled
930 // specially - cannot cast to void, otherwise the expression
931 // statement has no value.
932 if ( ast::ExprStmt const * exprStmt = stmt.as<ast::ExprStmt>() ) {
933 exprStmt->expr->accept( *visitor );
934 output << ";" << endl;
935 ++i;
936 break;
937 }
938 }
939 stmt->accept( *visitor );
940 output << endl;
941 if ( wantSpacing( stmt ) ) output << endl;
942 ++i;
943 }
944 --indent;
945 output << indent << "})";
946}
947
[0bd3faf]948void CodeGenerator::postvisit( ast::ConstructorExpr const * expr ) {
[8941b6b]949 assertf( !options.genC, "ConstructorExpr should not reach code generation." );
950 expr->callExpr->accept( *visitor );
951}
952
[0bd3faf]953void CodeGenerator::postvisit( ast::DeletedExpr const * expr ) {
[8941b6b]954 assertf( !options.genC, "DeletedExpr should not reach code generation." );
955 expr->expr->accept( *visitor );
956}
957
[0bd3faf]958void CodeGenerator::postvisit( ast::DefaultArgExpr const * expr ) {
[8941b6b]959 assertf( !options.genC, "DefaultArgExpr should not reach code generation." );
960 expr->expr->accept( *visitor );
961}
962
[0bd3faf]963void CodeGenerator::postvisit( ast::GenericExpr const * expr ) {
[8941b6b]964 assertf( !options.genC, "GenericExpr should not reach code generation." );
965 output << "_Generic(";
966 expr->control->accept( *visitor );
967 output << ", ";
968 unsigned int numAssocs = expr->associations.size();
969 unsigned int i = 0;
970 for ( const ast::GenericExpr::Association & assoc : expr->associations ) {
971 if ( nullptr == assoc.type ) {
972 output << "default: ";
973 } else {
974 output << genType( assoc.type, "", options ) << ": ";
975 }
976 assoc.expr->accept( *visitor );
977 ++i;
978 if ( i != numAssocs ) output << ", ";
979 }
980 output << ")";
981}
982
[0bd3faf]983void CodeGenerator::postvisit( ast::CompoundStmt const * stmt ) {
[8941b6b]984 output << "{" << endl;
985
986 ++indent;
987 for ( auto kid : stmt->kids ) {
988 output << indent << printLabels( kid->labels );
989 kid->accept( *visitor );
990 output << endl;
991 if ( wantSpacing( kid ) ) output << endl;
992 }
993 --indent;
994
995 output << indent << "}";
996}
997
[0bd3faf]998void CodeGenerator::postvisit( ast::ExprStmt const * stmt ) {
[8941b6b]999 assert( stmt );
1000 // Cast the top-level expression to void to reduce gcc warnings.
1001 if ( options.genC ) {
1002 ast::ptr<ast::Expr> expr = new ast::CastExpr( stmt->location, stmt->expr );
1003 expr->accept( *visitor );
1004 } else {
1005 stmt->expr->accept( *visitor );
1006 }
1007 output << ";";
1008}
1009
[0bd3faf]1010void CodeGenerator::postvisit( ast::AsmStmt const * stmt ) {
[8941b6b]1011 output << "asm ";
1012 if ( stmt->isVolatile ) output << "volatile ";
1013 if ( !stmt->gotoLabels.empty() ) output << "goto ";
1014 output << "( ";
1015 if ( stmt->instruction ) stmt->instruction->accept( *visitor );
1016 output << " : ";
1017 genCommaList( stmt->output );
1018 output << " : ";
1019 genCommaList( stmt->input );
1020 output << " : ";
1021 genCommaList( stmt->clobber );
1022 if ( !stmt->gotoLabels.empty() ) {
1023 output << " : ";
1024 auto it = stmt->gotoLabels.begin();
1025 while (true) {
1026 output << *it++;
1027 if ( stmt->gotoLabels.end() == it ) break;
1028 output << ", ";
1029 }
1030 }
1031 output << " );";
1032}
1033
[0bd3faf]1034void CodeGenerator::postvisit( ast::AsmDecl const * decl ) {
[8941b6b]1035 output << "asm ";
1036 ast::AsmStmt const * stmt = decl->stmt;
1037 output << "( ";
1038 if ( stmt->instruction ) stmt->instruction->accept( *visitor );
1039 output << " )";
1040}
1041
[0bd3faf]1042void CodeGenerator::postvisit( ast::DirectiveDecl const * decl ) {
[8941b6b]1043 // endl prevents spaces before the directive.
1044 output << endl << decl->stmt->directive;
1045}
1046
[0bd3faf]1047void CodeGenerator::postvisit( ast::DirectiveStmt const * stmt ) {
[8941b6b]1048 // endl prevents spaces before the directive.
1049 output << endl << stmt->directive;
1050}
1051
[0bd3faf]1052void CodeGenerator::postvisit( ast::IfStmt const * stmt ) {
[8941b6b]1053 output << "if ( ";
1054 stmt->cond->accept( *visitor );
1055 output << " ) ";
1056
1057 stmt->then->accept( *visitor );
1058
1059 if ( nullptr != stmt->else_ ) {
1060 output << " else ";
1061 stmt->else_->accept( *visitor );
1062 }
1063}
1064
[0bd3faf]1065void CodeGenerator::postvisit( ast::SwitchStmt const * stmt ) {
[8941b6b]1066 output << "switch ( ";
1067 stmt->cond->accept( *visitor );
1068 output << " ) ";
1069
[69ab896]1070 output << "{" << endl;
[8941b6b]1071 ++indent;
1072 for ( auto node : stmt->cases ) {
1073 node->accept( *visitor );
1074 }
1075 --indent;
1076 output << indent << "}";
1077}
1078
[0bd3faf]1079void CodeGenerator::postvisit( ast::CaseClause const * clause ) {
[8941b6b]1080 updateLocation( clause );
1081 output << indent;
1082 if ( clause->isDefault() ) {
1083 output << "default";
1084 } else {
1085 output << "case ";
1086 clause->cond->accept( *visitor );
1087 }
1088 output << ":" << endl;
1089
1090 ++indent;
1091 for ( auto stmt : clause->stmts ) {
1092 output << indent << printLabels( stmt->labels ) ;
1093 stmt->accept( *visitor );
1094 output << endl;
1095 }
1096 --indent;
1097}
1098
[0bd3faf]1099void CodeGenerator::postvisit( ast::BranchStmt const * stmt ) {
[8941b6b]1100 switch ( stmt->kind ) {
1101 case ast::BranchStmt::Goto:
1102 if ( !stmt->target.empty() ) {
1103 output << "goto " << stmt->target;
1104 } else if ( nullptr != stmt->computedTarget ) {
1105 output << "goto *";
1106 stmt->computedTarget->accept( *visitor );
1107 }
1108 break;
1109 case ast::BranchStmt::Break:
1110 output << "break";
1111 break;
1112 case ast::BranchStmt::Continue:
1113 output << "continue";
1114 break;
1115 case ast::BranchStmt::FallThrough:
1116 case ast::BranchStmt::FallThroughDefault:
[d96f7c4]1117 assertf( !options.genC, "fallthrough should not reach code generation." );
1118 output << "fallthrough";
[9506c70]1119 if ( ast::BranchStmt::FallThroughDefault == stmt->kind ) {
1120 assertf( stmt->target.empty(), "fallthough default should not have a target." );
1121 output << " default";
1122 }
[8941b6b]1123 break;
1124 default:
1125 assertf( false, "Bad BranchStmt value." );
1126 }
[9506c70]1127 // Print branch target for labelled break/continue/fallthrough.
1128 if ( ast::BranchStmt::Goto != stmt->kind && !stmt->target.empty() ) {
1129 assertf( !options.genC, "labelled branch should not reach code generation. %s", stmt->target.name.c_str() );
1130 output << " " << stmt->target;
[8941b6b]1131 }
1132 output << ";";
1133}
1134
[0bd3faf]1135void CodeGenerator::postvisit( ast::ReturnStmt const * stmt ) {
[8941b6b]1136 output << "return ";
1137 if ( stmt->expr ) stmt->expr->accept( *visitor );
1138 output << ";";
1139}
1140
[0bd3faf]1141void CodeGenerator::postvisit( ast::ThrowStmt const * stmt ) {
[8941b6b]1142 assertf( !options.genC, "ThrowStmt should not reach code generation." );
1143
1144 output << ((stmt->kind == ast::Terminate) ? "throw" : "throwResume");
1145 if ( stmt->expr ) {
1146 output << " ";
1147 stmt->expr->accept( *visitor );
1148 }
1149 if ( stmt->target ) {
1150 output << " _At ";
1151 stmt->target->accept( *visitor );
1152 }
1153 output << ";";
1154}
1155
[550446f]1156void CodeGenerator::postvisit( ast::TryStmt const * stmt ) {
1157 assertf( !options.genC, "TryStmt should not reach code generation." );
1158
1159 output << "try ";
1160 stmt->body->accept( *visitor );
1161 for ( ast::ptr<ast::CatchClause> const & handler : stmt->handlers ) {
1162 handler->accept( *visitor );
1163 }
1164 if ( stmt->finally ) stmt->finally->accept( *visitor );
1165}
1166
[0bd3faf]1167void CodeGenerator::postvisit( ast::CatchClause const * stmt ) {
[8941b6b]1168 assertf( !options.genC, "CatchClause should not reach code generation." );
1169
[550446f]1170 output << ((stmt->kind == ast::Terminate) ? " catch " : " catchResume ");
[8941b6b]1171 output << "( ";
1172 stmt->decl->accept( *visitor );
1173 if ( stmt->cond ) {
1174 output << " ; ";
1175 stmt->cond->accept( *visitor );
1176 }
1177 output << " ) ";
1178 stmt->body->accept( *visitor );
1179}
1180
[550446f]1181void CodeGenerator::postvisit( ast::FinallyClause const * clause ) {
1182 assertf( !options.genC, "FinallyClause should not reach code generation." );
1183
1184 output << " finally ";
1185 clause->body->accept( *visitor );
1186}
1187
[0bd3faf]1188void CodeGenerator::postvisit( ast::WaitForStmt const * stmt ) {
[8941b6b]1189 assertf( !options.genC, "WaitforStmt should not reach code generation." );
1190
1191 bool first = true;
1192 for ( ast::ptr<ast::WaitForClause> const & clause : stmt->clauses ) {
1193 if (first) { output << "or "; first = false; }
1194 if ( clause->when_cond ) {
1195 output << "when(";
[61e362f]1196 clause->when_cond->accept( *visitor );
[8941b6b]1197 output << ") ";
1198 }
1199 output << "waitfor(";
1200 clause->target->accept( *visitor );
1201 for ( ast::ptr<ast::Expr> const & expr : clause->target_args ) {
1202 output << ",";
1203 expr->accept( *visitor );
1204 }
1205 output << ") ";
1206 clause->stmt->accept( *visitor );
1207 }
1208
1209 if ( stmt->timeout_stmt ) {
1210 output << "or ";
1211 if ( stmt->timeout_cond ) {
1212 output << "when(";
1213 stmt->timeout_cond->accept( *visitor );
1214 output << ") ";
1215 }
1216 output << "timeout(";
1217 stmt->timeout_time->accept( *visitor );
1218 output << ") ";
1219 stmt->timeout_stmt->accept( *visitor );
1220 }
1221
1222 if ( stmt->else_stmt ) {
1223 output << "or ";
1224 if ( stmt->else_cond ) {
1225 output << "when(";
1226 stmt->else_cond->accept( *visitor );
1227 output << ")";
1228 }
1229 output << "else ";
1230 stmt->else_stmt->accept( *visitor );
1231 }
1232}
1233
[0bd3faf]1234void CodeGenerator::postvisit( ast::WithStmt const * stmt ) {
[8941b6b]1235 assertf( !options.genC, "WithStmt should not reach code generation." );
1236
1237 output << "with ( ";
1238 genCommaList( stmt->exprs );
1239 output << " ) ";
1240 stmt->stmt->accept( *visitor );
1241}
1242
[0bd3faf]1243void CodeGenerator::postvisit( ast::WhileDoStmt const * stmt ) {
[8941b6b]1244 if ( stmt->isDoWhile ) {
1245 output << "do";
1246 } else {
1247 output << "while (";
1248 stmt->cond->accept( *visitor );
1249 output << ")";
1250 }
1251 output << " ";
1252
[0bd3faf]1253 output << CodeGenerator::printLabels( stmt->body->labels );
[8941b6b]1254 stmt->body->accept( *visitor );
1255
1256 if ( stmt->isDoWhile ) {
1257 output << " while (";
1258 stmt->cond->accept( *visitor );
[88bc876]1259 output << ( ( nullptr == stmt->else_ ) ? ");" : ")" );
1260 }
1261 if ( stmt->else_ ) {
1262 output << " else ";
1263 stmt->else_->accept( *visitor );
[8941b6b]1264 }
1265}
1266
[0bd3faf]1267void CodeGenerator::postvisit( ast::ForStmt const * stmt ) {
[8941b6b]1268 // Initializer is always hoised so don't generate it.
1269 // TODO: Do an assertion check?
1270 output << "for (;";
1271
1272 if ( nullptr != stmt->cond ) {
1273 stmt->cond->accept( *visitor );
1274 }
1275 output << ";";
1276
1277 if ( nullptr != stmt->inc ) {
1278 // cast the top-level expression to void to reduce gcc warnings.
1279 ast::Expr * expr = new ast::CastExpr( stmt->inc );
1280 expr->accept( *visitor );
1281 }
1282 output << ") ";
1283
1284 if ( nullptr != stmt->body ) {
1285 output << printLabels( stmt->body->labels );
1286 stmt->body->accept( *visitor );
1287 }
[88bc876]1288
1289 if ( nullptr != stmt->else_ ) {
1290 assertf( !options.genC, "Loop else should not reach code generation." );
1291 output << " else ";
1292 stmt->else_->accept( *visitor );
1293 }
[8941b6b]1294}
1295
[0bd3faf]1296void CodeGenerator::postvisit( ast::NullStmt const * ) {
[8941b6b]1297 output << "/* null statement */ ;";
1298}
1299
[0bd3faf]1300void CodeGenerator::postvisit( ast::DeclStmt const * stmt ) {
[8941b6b]1301 stmt->decl->accept( *visitor );
1302
1303 if ( doSemicolon( stmt->decl ) ) output << ";";
1304}
1305
[0bd3faf]1306void CodeGenerator::postvisit( ast::ImplicitCtorDtorStmt const * stmt ) {
[8941b6b]1307 assertf( !options.genC, "ImplicitCtorCtorStmt should not reach code generation." );
1308 stmt->callStmt->accept( *visitor );
1309}
1310
[0bd3faf]1311void CodeGenerator::postvisit( ast::MutexStmt const * stmt ) {
[8941b6b]1312 assertf( !options.genC, "MutexStmt should not reach code generation." );
1313 // TODO: But this isn't what a mutex statement looks like.
1314 stmt->stmt->accept( *visitor );
1315}
1316
[6e7ed0aa]1317std::string genName( ast::DeclWithType const * decl ) {
1318 if ( const OperatorInfo * opInfo = operatorLookup( decl->name ) ) {
1319 return opInfo->outputName;
1320 } else {
1321 return decl->name;
1322 }
1323}
[8941b6b]1324
1325} // namespace CodeGen
Note: See TracBrowser for help on using the repository browser.