Added LogStatement
[delight/core.git] / dmd / statement.c
blob0f14a70a0805e6521b83f02be41afca21483606c
2 // Compiler implementation of the D programming language
3 // Copyright (c) 1999-2007 by Digital Mars
4 // All Rights Reserved
5 // written by Walter Bright
6 // http://www.digitalmars.com
7 // License for redistribution is by either the Artistic License
8 // in artistic.txt, or the GNU General Public License in gnu.txt.
9 // See the included readme.txt for details.
11 /* NOTE: This file has been patched from the original DMD distribution to
12 work with the GDC compiler.
14 Modified by David Friedman, September 2004
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <assert.h>
21 #include "mem.h"
23 #include "statement.h"
24 #include "expression.h"
25 #include "cond.h"
26 #include "init.h"
27 #include "staticassert.h"
28 #include "mtype.h"
29 #include "scope.h"
30 #include "declaration.h"
31 #include "aggregate.h"
32 #include "id.h"
33 #include "hdrgen.h"
34 #include "parse.h"
36 /******************************** Statement ***************************/
38 Statement::Statement(Loc loc)
39 : loc(loc)
41 #ifdef _DH
42 // If this is an in{} contract scope statement (skip for determining
43 // inlineStatus of a function body for header content)
44 incontract = 0;
45 #endif
48 Statement *Statement::syntaxCopy()
50 assert(0);
51 return NULL;
54 void Statement::print()
56 fprintf(stdmsg, "%s\n", toChars());
57 fflush(stdmsg);
60 char *Statement::toChars()
61 { OutBuffer *buf;
62 HdrGenState hgs;
64 buf = new OutBuffer();
65 toCBuffer(buf, &hgs);
66 return buf->toChars();
69 void Statement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
71 buf->printf("Statement::toCBuffer()");
72 buf->writenl();
75 Statement *Statement::semantic(Scope *sc)
77 return this;
80 // Same as semantic(), but do create a new scope
82 Statement *Statement::semanticScope(Scope *sc, Statement *sbreak, Statement *scontinue)
83 { Scope *scd;
84 Statement *s;
86 scd = sc->push();
87 if (sbreak)
88 scd->sbreak = sbreak;
89 if (scontinue)
90 scd->scontinue = scontinue;
91 s = semantic(scd);
92 scd->pop();
93 return s;
96 void Statement::error(const char *format, ...)
98 va_list ap;
99 va_start(ap, format);
100 ::verror(loc, format, ap);
101 va_end( ap );
104 int Statement::hasBreak()
106 //printf("Statement::hasBreak()\n");
107 return FALSE;
110 int Statement::hasContinue()
112 return FALSE;
115 // TRUE if statement uses exception handling
117 int Statement::usesEH()
119 return FALSE;
122 // TRUE if statement may fall off the end without a throw or return
124 int Statement::fallOffEnd()
126 return TRUE;
129 // TRUE if statement 'comes from' somewhere else, like a goto
131 int Statement::comeFrom()
133 //printf("Statement::comeFrom()\n");
134 return FALSE;
137 /****************************************
138 * If this statement has code that needs to run in a finally clause
139 * at the end of the current scope, return that code in the form of
140 * a Statement.
141 * Output:
142 * *sentry code executed upon entry to the scope
143 * *sexception code executed upon exit from the scope via exception
144 * *sfinally code executed in finally block
147 void Statement::scopeCode(Statement **sentry, Statement **sexception, Statement **sfinally)
149 //printf("Statement::scopeCode()\n");
150 //print();
151 *sentry = NULL;
152 *sexception = NULL;
153 *sfinally = NULL;
156 /*********************************
157 * Flatten out the scope by presenting the statement
158 * as an array of statements.
159 * Returns NULL if no flattening necessary.
162 Statements *Statement::flatten(Scope *sc)
164 return NULL;
168 /******************************** ExpStatement ***************************/
170 ExpStatement::ExpStatement(Loc loc, Expression *exp)
171 : Statement(loc)
173 this->exp = exp;
176 Statement *ExpStatement::syntaxCopy()
178 Expression *e = exp ? exp->syntaxCopy() : NULL;
179 ExpStatement *es = new ExpStatement(loc, e);
180 return es;
183 void ExpStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
185 if (exp)
186 exp->toCBuffer(buf, hgs);
187 buf->writeByte(';');
188 if (!hgs->FLinit.init)
189 buf->writenl();
192 Statement *ExpStatement::semantic(Scope *sc)
194 if (exp)
196 //printf("ExpStatement::semantic() %s\n", exp->toChars());
197 exp = exp->semantic(sc);
198 exp = resolveProperties(sc, exp);
199 exp->checkSideEffect(0);
200 exp = exp->optimize(0);
201 //exp = exp->optimize(isDeclarationStatement() ? WANTvalue : 0);
203 return this;
206 int ExpStatement::fallOffEnd()
208 if (exp)
210 if (exp->op == TOKassert)
211 { AssertExp *a = (AssertExp *)exp;
213 if (a->e1->isBool(FALSE)) // if it's an assert(0)
214 return FALSE;
216 else if (exp->op == TOKhalt)
217 return FALSE;
219 return TRUE;
222 /******************************** CompileStatement ***************************/
224 CompileStatement::CompileStatement(Loc loc, Expression *exp)
225 : Statement(loc)
227 this->exp = exp;
230 Statement *CompileStatement::syntaxCopy()
232 Expression *e = exp->syntaxCopy();
233 CompileStatement *es = new CompileStatement(loc, e);
234 return es;
237 void CompileStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
239 buf->writestring("mixin(");
240 exp->toCBuffer(buf, hgs);
241 buf->writestring(");");
242 if (!hgs->FLinit.init)
243 buf->writenl();
246 Statement *CompileStatement::semantic(Scope *sc)
248 //printf("CompileStatement::semantic() %s\n", exp->toChars());
249 exp = exp->semantic(sc);
250 exp = resolveProperties(sc, exp);
251 exp = exp->optimize(WANTvalue | WANTinterpret);
252 if (exp->op != TOKstring)
253 { error("argument to mixin must be a string, not (%s)", exp->toChars());
254 return this;
256 StringExp *se = (StringExp *)exp;
257 se = se->toUTF8(sc);
258 Parser p(sc->module, (unsigned char *)se->string, se->len, 0);
259 p.loc = loc;
260 p.nextToken();
262 Statements *statements = new Statements();
263 while (p.token.value != TOKeof)
265 Statement *s = p.parseStatement(PSsemi | PScurlyscope);
266 statements->push(s);
269 Statement *s = new CompoundStatement(loc, statements);
270 return s->semantic(sc);
274 /******************************** DeclarationStatement ***************************/
276 DeclarationStatement::DeclarationStatement(Loc loc, Dsymbol *declaration)
277 : ExpStatement(loc, new DeclarationExp(loc, declaration))
281 DeclarationStatement::DeclarationStatement(Loc loc, Expression *exp)
282 : ExpStatement(loc, exp)
286 Statement *DeclarationStatement::syntaxCopy()
288 DeclarationStatement *ds = new DeclarationStatement(loc, exp->syntaxCopy());
289 return ds;
292 void DeclarationStatement::scopeCode(Statement **sentry, Statement **sexception, Statement **sfinally)
294 //printf("DeclarationStatement::scopeCode()\n");
295 //print();
297 *sentry = NULL;
298 *sexception = NULL;
299 *sfinally = NULL;
301 if (exp)
303 if (exp->op == TOKdeclaration)
305 DeclarationExp *de = (DeclarationExp *)(exp);
306 VarDeclaration *v = de->declaration->isVarDeclaration();
307 if (v)
308 { Expression *e;
310 e = v->callAutoDtor();
311 if (e)
313 //printf("dtor is: "); e->print();
314 *sfinally = new ExpStatement(loc, e);
321 void DeclarationStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
323 exp->toCBuffer(buf, hgs);
327 /******************************** InjectorMainBody ***************************/
329 static Expressions *getAutoArgs(Loc loc, Arguments *arguments) {
330 Expressions *args = new Expressions();
332 Expression *externals = new IdentifierExp(loc, Id::externals);
333 // Collect all the objects we need for the constructor's arguments
334 for (int i = 0; i < arguments->dim; i++) {
335 Argument *arg = (Argument *) arguments->data[i];
336 if (arg->ident == Id::args) {
337 // For 'args', just pass through the string[] passed to main()
338 args->push(new IdentifierExp(loc, arg->ident));
339 } else {
340 // For everything else, call a getter in the _externals module
341 Expression *getter = new DotIdExp(loc, externals, arg->ident);
342 args->push(getter);
346 return args;
349 InjectorMainBody::InjectorMainBody(Loc loc, ClassDeclaration *mainClass)
350 : Statement(loc), mainClass(mainClass)
354 Statement *InjectorMainBody::semantic(Scope *sc)
356 // Find the constructor and the main method
357 CtorDeclaration *ctor = NULL;
358 FuncDeclaration *mainDecl = NULL;
359 for (int i = 0; i < mainClass->members->dim; i++) {
360 Dsymbol *s;
362 s = (Dsymbol *)mainClass->members->data[i];
364 CtorDeclaration *thisCtor = s->isCtorDeclaration();
365 if (thisCtor) {
366 if (ctor) {
367 error("Multiple constructors for Main class!");
368 return NULL;
369 } else {
370 ctor = thisCtor;
374 FuncDeclaration *thisMethod = s->isFuncDeclaration();
375 if (thisMethod && thisMethod->ident == Id::main) {
376 if (mainDecl) {
377 error("Multiple main methods for Main class!");
378 return NULL;
379 } else {
380 mainDecl = thisMethod;
385 if (mainDecl == NULL) {
386 error("No main method in Main class!");
387 return NULL;
390 // Externals externals = new _externals.Externals()
391 TypeIdentifier *extType = new TypeIdentifier(loc, Id::_externals);
392 extType->addIdent(Id::Externals);
394 Expression *newExt = new NewExp(loc, NULL, NULL, extType, NULL);
395 VarDeclaration *v = new VarDeclaration(loc, extType, Id::externals,
396 new ExpInitializer(loc, newExt));
397 Statement *assignExt = new DeclarationStatement(loc, v);
398 Expression *newMain = new NewExp(loc, NULL, NULL, mainClass->getType(),
399 ctor ? getAutoArgs(ctor->loc, ctor->arguments) : NULL);
401 // Then invoke the main() method inside it
402 // mainObject.main(...)
403 Expression *mainMethod = new DotIdExp(mainDecl->loc, newMain, Id::main);
404 Expression *mainCall = new CallExp(mainMethod->loc, mainMethod,
405 getAutoArgs(mainDecl->loc,
406 ((TypeFunction *) mainDecl->type)->parameters));
408 Statement *s = new ExpStatement(loc, mainCall);
409 Statement *body = new CompoundStatement(loc, assignExt, s);
411 return body->semantic(sc);
414 /******************************** CompoundStatement ***************************/
416 CompoundStatement::CompoundStatement(Loc loc, Statements *s)
417 : Statement(loc)
419 statements = s;
422 CompoundStatement::CompoundStatement(Loc loc, Statement *s1, Statement *s2)
423 : Statement(loc)
425 statements = new Statements();
426 statements->reserve(2);
427 statements->push(s1);
428 statements->push(s2);
431 Statement *CompoundStatement::syntaxCopy()
433 Statements *a = new Statements();
434 a->setDim(statements->dim);
435 for (size_t i = 0; i < statements->dim; i++)
436 { Statement *s = (Statement *)statements->data[i];
437 if (s)
438 s = s->syntaxCopy();
439 a->data[i] = s;
441 CompoundStatement *cs = new CompoundStatement(loc, a);
442 return cs;
446 Statement *CompoundStatement::semantic(Scope *sc)
447 { Statement *s;
449 //printf("CompoundStatement::semantic(this = %p, sc = %p)\n", this, sc);
451 for (size_t i = 0; i < statements->dim; )
453 s = (Statement *) statements->data[i];
454 if (s)
455 { Statements *a = s->flatten(sc);
457 if (a)
459 statements->remove(i);
460 statements->insert(i, a);
461 continue;
463 s = s->semantic(sc);
464 statements->data[i] = s;
465 if (s)
467 Statement *sentry;
468 Statement *sexception;
469 Statement *sfinally;
471 s->scopeCode(&sentry, &sexception, &sfinally);
472 if (sentry)
474 sentry = sentry->semantic(sc);
475 statements->data[i] = sentry;
477 if (sexception)
479 if (i + 1 == statements->dim && !sfinally)
481 #if 1
482 sexception = sexception->semantic(sc);
483 #else
484 statements->push(sexception);
485 if (sfinally)
486 // Assume sexception does not throw
487 statements->push(sfinally);
488 #endif
490 else
492 /* Rewrite:
493 * s; s1; s2;
494 * As:
495 * s;
496 * try { s1; s2; }
497 * catch (Object __o)
498 * { sexception; throw __o; }
500 Statement *body;
501 Statements *a = new Statements();
503 for (int j = i + 1; j < statements->dim; j++)
505 a->push(statements->data[j]);
507 body = new CompoundStatement(0, a);
508 body = new ScopeStatement(0, body);
510 static int num;
511 char name[3 + sizeof(num) * 3 + 1];
512 sprintf(name, "__o%d", ++num);
513 Identifier *id = Lexer::idPool(name);
515 Statement *handler = new ThrowStatement(0, new IdentifierExp(0, id));
516 handler = new CompoundStatement(0, sexception, handler);
518 Array *catches = new Array();
519 Catch *ctch = new Catch(0, NULL, id, handler);
520 catches->push(ctch);
521 s = new TryCatchStatement(0, body, catches);
523 if (sfinally)
524 s = new TryFinallyStatement(0, s, sfinally);
525 s = s->semantic(sc);
526 statements->setDim(i + 1);
527 statements->push(s);
528 break;
531 else if (sfinally)
533 if (0 && i + 1 == statements->dim)
535 statements->push(sfinally);
537 else
539 /* Rewrite:
540 * s; s1; s2;
541 * As:
542 * s; try { s1; s2; } finally { sfinally; }
544 Statement *body;
545 Statements *a = new Statements();
547 for (int j = i + 1; j < statements->dim; j++)
549 a->push(statements->data[j]);
551 body = new CompoundStatement(0, a);
552 s = new TryFinallyStatement(0, body, sfinally);
553 s = s->semantic(sc);
554 statements->setDim(i + 1);
555 statements->push(s);
556 break;
561 i++;
563 if (statements->dim == 1)
564 return s;
565 return this;
568 Statements *CompoundStatement::flatten(Scope *sc)
570 return statements;
573 ReturnStatement *CompoundStatement::isReturnStatement()
574 { int i;
575 ReturnStatement *rs = NULL;
577 for (i = 0; i < statements->dim; i++)
578 { Statement *s;
580 s = (Statement *) statements->data[i];
581 if (s)
583 rs = s->isReturnStatement();
584 if (rs)
585 break;
588 return rs;
591 void CompoundStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
592 { int i;
594 for (i = 0; i < statements->dim; i++)
595 { Statement *s;
597 s = (Statement *) statements->data[i];
598 if (s)
599 s->toCBuffer(buf, hgs);
603 int CompoundStatement::usesEH()
605 for (int i = 0; i < statements->dim; i++)
606 { Statement *s;
608 s = (Statement *) statements->data[i];
609 if (s && s->usesEH())
610 return TRUE;
612 return FALSE;
615 int CompoundStatement::fallOffEnd()
616 { int falloff = TRUE;
618 //printf("CompoundStatement::fallOffEnd() %s\n", toChars());
619 for (int i = 0; i < statements->dim; i++)
620 { Statement *s = (Statement *)statements->data[i];
622 if (!s)
623 continue;
625 if (!falloff && global.params.warnings && !s->comeFrom())
627 fprintf(stdmsg, "warning - ");
628 s->error("statement is not reachable");
630 falloff = s->fallOffEnd();
632 return falloff;
635 int CompoundStatement::comeFrom()
636 { int comefrom = FALSE;
638 //printf("CompoundStatement::comeFrom()\n");
639 for (int i = 0; i < statements->dim; i++)
640 { Statement *s = (Statement *)statements->data[i];
642 if (!s)
643 continue;
645 comefrom |= s->comeFrom();
647 return comefrom;
651 /**************************** UnrolledLoopStatement ***************************/
653 UnrolledLoopStatement::UnrolledLoopStatement(Loc loc, Statements *s)
654 : Statement(loc)
656 statements = s;
659 Statement *UnrolledLoopStatement::syntaxCopy()
661 Statements *a = new Statements();
662 a->setDim(statements->dim);
663 for (size_t i = 0; i < statements->dim; i++)
664 { Statement *s = (Statement *)statements->data[i];
665 if (s)
666 s = s->syntaxCopy();
667 a->data[i] = s;
669 UnrolledLoopStatement *cs = new UnrolledLoopStatement(loc, a);
670 return cs;
674 Statement *UnrolledLoopStatement::semantic(Scope *sc)
676 //printf("UnrolledLoopStatement::semantic(this = %p, sc = %p)\n", this, sc);
678 sc->noctor++;
679 Scope *scd = sc->push();
680 scd->sbreak = this;
681 scd->scontinue = this;
683 for (size_t i = 0; i < statements->dim; i++)
685 Statement *s = (Statement *) statements->data[i];
686 if (s)
688 s = s->semantic(scd);
689 statements->data[i] = s;
693 scd->pop();
694 sc->noctor--;
695 return this;
698 void UnrolledLoopStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
700 buf->writestring("unrolled {");
701 buf->writenl();
703 for (size_t i = 0; i < statements->dim; i++)
704 { Statement *s;
706 s = (Statement *) statements->data[i];
707 if (s)
708 s->toCBuffer(buf, hgs);
711 buf->writeByte('}');
712 buf->writenl();
715 int UnrolledLoopStatement::hasBreak()
717 return TRUE;
720 int UnrolledLoopStatement::hasContinue()
722 return TRUE;
725 int UnrolledLoopStatement::usesEH()
727 for (size_t i = 0; i < statements->dim; i++)
728 { Statement *s;
730 s = (Statement *) statements->data[i];
731 if (s && s->usesEH())
732 return TRUE;
734 return FALSE;
737 int UnrolledLoopStatement::fallOffEnd()
739 //printf("UnrolledLoopStatement::fallOffEnd()\n");
740 for (size_t i = 0; i < statements->dim; i++)
741 { Statement *s = (Statement *)statements->data[i];
743 if (s)
744 s->fallOffEnd();
746 return TRUE;
750 int UnrolledLoopStatement::comeFrom()
751 { int comefrom = FALSE;
753 //printf("UnrolledLoopStatement::comeFrom()\n");
754 for (size_t i = 0; i < statements->dim; i++)
755 { Statement *s = (Statement *)statements->data[i];
757 if (!s)
758 continue;
760 comefrom |= s->comeFrom();
762 return comefrom;
766 /******************************** ScopeStatement ***************************/
768 ScopeStatement::ScopeStatement(Loc loc, Statement *s)
769 : Statement(loc)
771 this->statement = s;
774 Statement *ScopeStatement::syntaxCopy()
776 Statement *s;
778 s = statement ? statement->syntaxCopy() : NULL;
779 s = new ScopeStatement(loc, s);
780 return s;
784 Statement *ScopeStatement::semantic(Scope *sc)
785 { ScopeDsymbol *sym;
787 //printf("ScopeStatement::semantic(sc = %p)\n", sc);
788 if (statement)
789 { Statements *a;
791 sym = new ScopeDsymbol();
792 sym->parent = sc->scopesym;
793 sc = sc->push(sym);
795 a = statement->flatten(sc);
796 if (a)
798 statement = new CompoundStatement(loc, a);
801 statement = statement->semantic(sc);
802 if (statement)
804 Statement *sentry;
805 Statement *sexception;
806 Statement *sfinally;
808 statement->scopeCode(&sentry, &sexception, &sfinally);
809 if (sfinally)
811 //printf("adding sfinally\n");
812 statement = new CompoundStatement(loc, statement, sfinally);
816 sc->pop();
818 return this;
821 int ScopeStatement::hasBreak()
823 //printf("ScopeStatement::hasBreak() %s\n", toChars());
824 return statement ? statement->hasBreak() : FALSE;
827 int ScopeStatement::hasContinue()
829 return statement ? statement->hasContinue() : FALSE;
832 int ScopeStatement::usesEH()
834 return statement ? statement->usesEH() : FALSE;
837 int ScopeStatement::fallOffEnd()
839 return statement ? statement->fallOffEnd() : TRUE;
842 int ScopeStatement::comeFrom()
844 //printf("ScopeStatement::comeFrom()\n");
845 return statement ? statement->comeFrom() : FALSE;
848 void ScopeStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
850 buf->writeByte('{');
851 buf->writenl();
853 if (statement)
854 statement->toCBuffer(buf, hgs);
856 buf->writeByte('}');
857 buf->writenl();
860 /******************************** WhileStatement ***************************/
862 WhileStatement::WhileStatement(Loc loc, Expression *c, Statement *b)
863 : Statement(loc)
865 condition = c;
866 body = b;
869 Statement *WhileStatement::syntaxCopy()
871 WhileStatement *s = new WhileStatement(loc, condition->syntaxCopy(), body ? body->syntaxCopy() : NULL);
872 return s;
876 Statement *WhileStatement::semantic(Scope *sc)
878 #if 0
879 if (condition->op == TOKmatch)
881 /* Rewrite while (condition) body as:
882 * if (condition)
883 * do
884 * body
885 * while ((_match = _match.opNext), _match);
888 Expression *ew = new IdentifierExp(0, Id::_match);
889 ew = new DotIdExp(0, ew, Id::next);
890 ew = new AssignExp(0, new IdentifierExp(0, Id::_match), ew);
891 ////ew = new EqualExp(TOKnotequal, 0, ew, new NullExp(0));
892 Expression *ev = new IdentifierExp(0, Id::_match);
893 //ev = new CastExp(0, ev, Type::tvoidptr);
894 ew = new CommaExp(0, ew, ev);
895 Statement *sw = new DoStatement(loc, body, ew);
896 Statement *si = new IfStatement(loc, condition, sw, NULL);
897 return si->semantic(sc);
899 #endif
901 condition = condition->semantic(sc);
902 condition = resolveProperties(sc, condition);
903 condition = condition->optimize(WANTvalue);
904 condition = condition->checkToBoolean();
906 sc->noctor++;
908 Scope *scd = sc->push();
909 scd->sbreak = this;
910 scd->scontinue = this;
911 if (body)
912 body = body->semantic(scd);
913 scd->pop();
915 sc->noctor--;
917 return this;
920 int WhileStatement::hasBreak()
922 return TRUE;
925 int WhileStatement::hasContinue()
927 return TRUE;
930 int WhileStatement::usesEH()
932 return body ? body->usesEH() : 0;
935 int WhileStatement::fallOffEnd()
937 if (body)
938 body->fallOffEnd();
939 return TRUE;
942 int WhileStatement::comeFrom()
944 if (body)
945 return body->comeFrom();
946 return FALSE;
949 void WhileStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
951 buf->writestring("while (");
952 condition->toCBuffer(buf, hgs);
953 buf->writebyte(')');
954 buf->writenl();
955 if (body)
956 body->toCBuffer(buf, hgs);
959 /******************************** DoStatement ***************************/
961 DoStatement::DoStatement(Loc loc, Statement *b, Expression *c)
962 : Statement(loc)
964 body = b;
965 condition = c;
968 Statement *DoStatement::syntaxCopy()
970 DoStatement *s = new DoStatement(loc, body ? body->syntaxCopy() : NULL, condition->syntaxCopy());
971 return s;
975 Statement *DoStatement::semantic(Scope *sc)
977 sc->noctor++;
978 if (body)
979 body = body->semanticScope(sc, this, this);
980 sc->noctor--;
981 condition = condition->semantic(sc);
982 condition = resolveProperties(sc, condition);
983 condition = condition->optimize(WANTvalue);
985 condition = condition->checkToBoolean();
987 return this;
990 int DoStatement::hasBreak()
992 return TRUE;
995 int DoStatement::hasContinue()
997 return TRUE;
1000 int DoStatement::usesEH()
1002 return body ? body->usesEH() : 0;
1005 int DoStatement::fallOffEnd()
1007 if (body)
1008 body->fallOffEnd();
1009 return TRUE;
1012 int DoStatement::comeFrom()
1014 if (body)
1015 return body->comeFrom();
1016 return FALSE;
1019 void DoStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
1021 buf->writestring("do");
1022 buf->writenl();
1023 if (body)
1024 body->toCBuffer(buf, hgs);
1025 buf->writestring("while (");
1026 condition->toCBuffer(buf, hgs);
1027 buf->writebyte(')');
1030 /******************************** ForStatement ***************************/
1032 ForStatement::ForStatement(Loc loc, Statement *init, Expression *condition, Expression *increment, Statement *body)
1033 : Statement(loc)
1035 this->init = init;
1036 this->condition = condition;
1037 this->increment = increment;
1038 this->body = body;
1041 Statement *ForStatement::syntaxCopy()
1043 Statement *i = NULL;
1044 if (init)
1045 i = init->syntaxCopy();
1046 Expression *c = NULL;
1047 if (condition)
1048 c = condition->syntaxCopy();
1049 Expression *inc = NULL;
1050 if (increment)
1051 inc = increment->syntaxCopy();
1052 ForStatement *s = new ForStatement(loc, i, c, inc, body->syntaxCopy());
1053 return s;
1056 Statement *ForStatement::semantic(Scope *sc)
1058 ScopeDsymbol *sym = new ScopeDsymbol();
1059 sym->parent = sc->scopesym;
1060 sc = sc->push(sym);
1061 if (init)
1062 init = init->semantic(sc);
1063 if (!condition)
1064 // Use a default value
1065 condition = new IntegerExp(loc, 1, Type::tboolean);
1066 sc->noctor++;
1067 condition = condition->semantic(sc);
1068 condition = resolveProperties(sc, condition);
1069 condition = condition->optimize(WANTvalue);
1070 condition = condition->checkToBoolean();
1071 if (increment)
1072 increment = increment->semantic(sc);
1074 sc->sbreak = this;
1075 sc->scontinue = this;
1076 body = body->semantic(sc);
1077 sc->noctor--;
1079 sc->pop();
1080 return this;
1083 void ForStatement::scopeCode(Statement **sentry, Statement **sexception, Statement **sfinally)
1085 //printf("ForStatement::scopeCode()\n");
1086 //print();
1087 if (init)
1088 init->scopeCode(sentry, sexception, sfinally);
1089 else
1090 Statement::scopeCode(sentry, sexception, sfinally);
1093 int ForStatement::hasBreak()
1095 //printf("ForStatement::hasBreak()\n");
1096 return TRUE;
1099 int ForStatement::hasContinue()
1101 return TRUE;
1104 int ForStatement::usesEH()
1106 return (init && init->usesEH()) || body->usesEH();
1109 int ForStatement::fallOffEnd()
1111 if (body)
1112 body->fallOffEnd();
1113 return TRUE;
1116 int ForStatement::comeFrom()
1118 //printf("ForStatement::comeFrom()\n");
1119 if (body)
1120 { int result = body->comeFrom();
1121 //printf("result = %d\n", result);
1122 return result;
1124 return FALSE;
1127 void ForStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
1129 buf->writestring("for (");
1130 if (init)
1132 hgs->FLinit.init++;
1133 hgs->FLinit.decl = 0;
1134 init->toCBuffer(buf, hgs);
1135 if (hgs->FLinit.decl > 0)
1136 buf->writebyte(';');
1137 hgs->FLinit.decl = 0;
1138 hgs->FLinit.init--;
1140 else
1141 buf->writebyte(';');
1142 if (condition)
1143 { buf->writebyte(' ');
1144 condition->toCBuffer(buf, hgs);
1146 buf->writebyte(';');
1147 if (increment)
1148 { buf->writebyte(' ');
1149 increment->toCBuffer(buf, hgs);
1151 buf->writebyte(')');
1152 buf->writenl();
1153 buf->writebyte('{');
1154 buf->writenl();
1155 body->toCBuffer(buf, hgs);
1156 buf->writebyte('}');
1157 buf->writenl();
1160 /******************************** ForeachStatement ***************************/
1162 ForeachStatement::ForeachStatement(Loc loc, enum TOK op, Arguments *arguments,
1163 Expression *aggr, Statement *body)
1164 : Statement(loc)
1166 this->op = op;
1167 this->arguments = arguments;
1168 this->aggr = aggr;
1169 this->body = body;
1171 this->key = NULL;
1172 this->value = NULL;
1174 this->func = NULL;
1177 Statement *ForeachStatement::syntaxCopy()
1179 Arguments *args = Argument::arraySyntaxCopy(arguments);
1180 Expression *exp = aggr->syntaxCopy();
1181 ForeachStatement *s = new ForeachStatement(loc, op, args, exp,
1182 body ? body->syntaxCopy() : NULL);
1183 return s;
1186 Statement *ForeachStatement::semantic(Scope *sc)
1188 //printf("ForeachStatement::semantic() %p\n", this);
1189 ScopeDsymbol *sym;
1190 Statement *s = this;
1191 int dim = arguments->dim;
1192 int i;
1193 TypeAArray *taa = NULL;
1195 Type *tn = NULL;
1196 Type *tnv = NULL;
1198 func = sc->func;
1199 if (func->fes)
1200 func = func->fes->func;
1202 aggr = aggr->semantic(sc);
1203 aggr = resolveProperties(sc, aggr);
1204 if (!aggr->type)
1206 error("invalid foreach aggregate %s", aggr->toChars());
1207 return this;
1210 inferApplyArgTypes(op, arguments, aggr);
1212 /* Check for inference errors
1214 if (dim != arguments->dim)
1216 //printf("dim = %d, arguments->dim = %d\n", dim, arguments->dim);
1217 error("cannot uniquely infer foreach argument types");
1218 return this;
1221 Type *tab = aggr->type->toBasetype();
1223 if (tab->ty == Ttuple) // don't generate new scope for tuple loops
1225 if (dim < 1 || dim > 2)
1227 error("only one (value) or two (key,value) arguments for tuple foreach");
1228 return s;
1231 TypeTuple *tuple = (TypeTuple *)tab;
1232 Statements *statements = new Statements();
1233 //printf("aggr: op = %d, %s\n", aggr->op, aggr->toChars());
1234 size_t n;
1235 TupleExp *te = NULL;
1236 if (aggr->op == TOKtuple) // expression tuple
1237 { te = (TupleExp *)aggr;
1238 n = te->exps->dim;
1240 else if (aggr->op == TOKtype) // type tuple
1242 n = Argument::dim(tuple->arguments);
1244 else
1245 assert(0);
1246 for (size_t j = 0; j < n; j++)
1247 { size_t k = (op == TOKforeach) ? j : n - 1 - j;
1248 Expression *e;
1249 Type *t;
1250 if (te)
1251 e = (Expression *)te->exps->data[k];
1252 else
1253 t = Argument::getNth(tuple->arguments, k)->type;
1254 Argument *arg = (Argument *)arguments->data[0];
1255 Statements *st = new Statements();
1257 if (dim == 2)
1258 { // Declare key
1259 if (arg->storageClass & (STCout | STCref | STClazy))
1260 error("no storage class for key %s", arg->ident->toChars());
1261 TY keyty = arg->type->ty;
1262 if ((keyty != Tint32 && keyty != Tuns32) &&
1263 (! global.params.isX86_64 ||
1264 (keyty != Tint64 && keyty != Tuns64))
1267 error("foreach: key type must be int or uint, not %s", arg->type->toChars());
1269 Initializer *ie = new ExpInitializer(0, new IntegerExp(k));
1270 VarDeclaration *var = new VarDeclaration(loc, arg->type, arg->ident, ie);
1271 var->storage_class |= STCconst;
1272 DeclarationExp *de = new DeclarationExp(loc, var);
1273 st->push(new ExpStatement(loc, de));
1274 arg = (Argument *)arguments->data[1]; // value
1276 // Declare value
1277 if (arg->storageClass & (STCout | STCref | STClazy))
1278 error("no storage class for value %s", arg->ident->toChars());
1279 Dsymbol *var;
1280 if (te)
1282 if (e->type->toBasetype()->ty == Tfunction &&
1283 e->op == TOKvar)
1284 { VarExp *ve = (VarExp *)e;
1285 var = new AliasDeclaration(loc, arg->ident, ve->var);
1287 else
1289 arg->type = e->type;
1290 Initializer *ie = new ExpInitializer(0, e);
1291 VarDeclaration *v = new VarDeclaration(loc, arg->type, arg->ident, ie);
1292 if (e->isConst())
1293 v->storage_class |= STCconst;
1294 #if V2
1295 else
1296 v->storage_class |= STCfinal;
1297 #endif
1298 var = v;
1301 else
1303 var = new AliasDeclaration(loc, arg->ident, t);
1305 DeclarationExp *de = new DeclarationExp(loc, var);
1306 st->push(new ExpStatement(loc, de));
1308 st->push(body->syntaxCopy());
1309 s = new CompoundStatement(loc, st);
1310 s = new ScopeStatement(loc, s);
1311 statements->push(s);
1314 s = new UnrolledLoopStatement(loc, statements);
1315 s = s->semantic(sc);
1316 return s;
1319 for (i = 0; i < dim; i++)
1320 { Argument *arg = (Argument *)arguments->data[i];
1321 if (!arg->type)
1323 error("cannot infer type for %s", arg->ident->toChars());
1324 return this;
1328 sym = new ScopeDsymbol();
1329 sym->parent = sc->scopesym;
1330 sc = sc->push(sym);
1332 sc->noctor++;
1334 switch (tab->ty)
1336 case Tarray:
1337 case Tsarray:
1338 if (dim < 1 || dim > 2)
1340 error("only one or two arguments for array foreach");
1341 break;
1344 /* Look for special case of parsing char types out of char type
1345 * array.
1347 tn = tab->nextOf()->toBasetype();
1348 if (tn->ty == Tchar || tn->ty == Twchar || tn->ty == Tdchar)
1349 { Argument *arg;
1351 i = (dim == 1) ? 0 : 1; // index of value
1352 arg = (Argument *)arguments->data[i];
1353 arg->type = arg->type->semantic(loc, sc);
1354 tnv = arg->type->toBasetype();
1355 if (tnv->ty != tn->ty &&
1356 (tnv->ty == Tchar || tnv->ty == Twchar || tnv->ty == Tdchar))
1358 if (arg->storageClass & STCref)
1359 error("foreach: value of UTF conversion cannot be ref");
1360 if (dim == 2)
1361 { arg = (Argument *)arguments->data[0];
1362 if (arg->storageClass & STCref)
1363 error("foreach: key cannot be ref");
1365 goto Lapply;
1369 for (i = 0; i < dim; i++)
1370 { // Declare args
1371 Argument *arg = (Argument *)arguments->data[i];
1372 VarDeclaration *var;
1374 var = new VarDeclaration(loc, arg->type, arg->ident, NULL);
1375 var->storage_class |= STCforeach;
1376 var->storage_class |= arg->storageClass & (STCin | STCout | STCref);
1377 #if 1
1378 DeclarationExp *de = new DeclarationExp(loc, var);
1379 de->semantic(sc);
1380 #else
1381 var->semantic(sc);
1382 if (!sc->insert(var))
1383 error("%s already defined", var->ident->toChars());
1384 #endif
1385 if (dim == 2 && i == 0)
1386 key = var;
1387 else
1388 value = var;
1391 sc->sbreak = this;
1392 sc->scontinue = this;
1393 body = body->semantic(sc);
1395 if (!value->type->equals(tab->next))
1397 if (aggr->op == TOKstring)
1398 aggr = aggr->implicitCastTo(sc, value->type->arrayOf());
1399 else
1400 error("foreach: %s is not an array of %s", tab->toChars(), value->type->toChars());
1403 if (key &&
1404 ((key->type->ty != Tint32 && key->type->ty != Tuns32) &&
1405 (! global.params.isX86_64 ||
1406 (key->type->ty != Tint64 && key->type->ty != Tuns64))
1410 error("foreach: key type must be int or uint, not %s", key->type->toChars());
1413 if (key && key->storage_class & (STCout | STCref))
1414 error("foreach: key cannot be out or ref");
1415 break;
1417 case Taarray:
1418 taa = (TypeAArray *)tab;
1419 if (dim < 1 || dim > 2)
1421 error("only one or two arguments for associative array foreach");
1422 break;
1424 if (op == TOKforeach_reverse)
1426 error("no reverse iteration on associative arrays");
1428 goto Lapply;
1430 case Tclass:
1431 case Tstruct:
1432 case Tdelegate:
1433 Lapply:
1434 { FuncDeclaration *fdapply;
1435 Arguments *args;
1436 Expression *ec;
1437 Expression *e;
1438 FuncLiteralDeclaration *fld;
1439 Argument *a;
1440 Type *t;
1441 Expression *flde;
1442 Identifier *id;
1443 Type *tret;
1445 tret = func->type->nextOf();
1447 // Need a variable to hold value from any return statements in body.
1448 if (!sc->func->vresult && tret && tret != Type::tvoid)
1449 { VarDeclaration *v;
1451 v = new VarDeclaration(loc, tret, Id::result, NULL);
1452 v->noauto = 1;
1453 v->semantic(sc);
1454 if (!sc->insert(v))
1455 assert(0);
1456 v->parent = sc->func;
1457 sc->func->vresult = v;
1460 /* Turn body into the function literal:
1461 * int delegate(ref T arg) { body }
1463 args = new Arguments();
1464 for (i = 0; i < dim; i++)
1465 { Argument *arg = (Argument *)arguments->data[i];
1467 arg->type = arg->type->semantic(loc, sc);
1468 if (arg->storageClass & STCref)
1469 id = arg->ident;
1470 else
1471 { // Make a copy of the ref argument so it isn't
1472 // a reference.
1473 VarDeclaration *v;
1474 Initializer *ie;
1475 char applyArg[10 + sizeof(i)*3 + 1];
1477 sprintf(applyArg, "__applyArg%d", i);
1478 id = Lexer::idPool(applyArg);
1480 ie = new ExpInitializer(0, new IdentifierExp(0, id));
1481 v = new VarDeclaration(0, arg->type, arg->ident, ie);
1482 s = new DeclarationStatement(0, v);
1483 body = new CompoundStatement(loc, s, body);
1485 a = new Argument(STCref, arg->type, id, NULL);
1486 args->push(a);
1488 t = new TypeFunction(args, Type::tint32, 0, LINKd);
1489 fld = new FuncLiteralDeclaration(loc, 0, t, TOKdelegate, this);
1490 fld->fbody = body;
1491 flde = new FuncExp(loc, fld);
1492 flde = flde->semantic(sc);
1494 // Resolve any forward referenced goto's
1495 for (int i = 0; i < gotos.dim; i++)
1496 { CompoundStatement *cs = (CompoundStatement *)gotos.data[i];
1497 GotoStatement *gs = (GotoStatement *)cs->statements->data[0];
1499 if (!gs->label->statement)
1500 { // 'Promote' it to this scope, and replace with a return
1501 cases.push(gs);
1502 s = new ReturnStatement(0, new IntegerExp(cases.dim + 1));
1503 cs->statements->data[0] = (void *)s;
1507 if (tab->ty == Taarray)
1509 // Check types
1510 Argument *arg = (Argument *)arguments->data[0];
1511 if (dim == 2)
1513 if (arg->storageClass & STCref)
1514 error("foreach: index cannot be ref");
1515 if (!arg->type->equals(taa->index))
1516 error("foreach: index must be type %s, not %s", taa->index->toChars(), arg->type->toChars());
1517 arg = (Argument *)arguments->data[1];
1519 if (!arg->type->equals(taa->nextOf()))
1520 error("foreach: value must be type %s, not %s", taa->nextOf()->toChars(), arg->type->toChars());
1522 /* Call:
1523 * _aaApply(aggr, keysize, flde)
1525 if (dim == 2)
1526 fdapply = FuncDeclaration::genCfunc(Type::tint32, "_aaApply2",
1527 Type::tvoid->arrayOf(), Type::tsize_t, flde->type); // flde->type is not generic
1528 else
1529 fdapply = FuncDeclaration::genCfunc(Type::tint32, "_aaApply",
1530 Type::tvoid->arrayOf(), Type::tsize_t, flde->type); // flde->type is not generic);
1531 ec = new VarExp(0, fdapply);
1532 Expressions *exps = new Expressions();
1533 exps->push(aggr);
1534 size_t keysize = taa->key->size();
1535 keysize = (keysize + (PTRSIZE-1)) & ~(PTRSIZE-1);
1536 exps->push(new IntegerExp(0, keysize, Type::tsize_t));
1537 exps->push(flde);
1538 e = new CallExp(loc, ec, exps);
1539 e->type = Type::tint32; // don't run semantic() on e
1541 else if (tab->ty == Tarray || tab->ty == Tsarray)
1543 /* Call:
1544 * _aApply(aggr, flde)
1546 static char fntab[9][3] =
1547 { "cc","cw","cd",
1548 "wc","cc","wd",
1549 "dc","dw","dd"
1551 char fdname[7+1+2+ sizeof(dim)*3 + 1];
1552 int flag;
1554 switch (tn->ty)
1556 case Tchar: flag = 0; break;
1557 case Twchar: flag = 3; break;
1558 case Tdchar: flag = 6; break;
1559 default: assert(0);
1561 switch (tnv->ty)
1563 case Tchar: flag += 0; break;
1564 case Twchar: flag += 1; break;
1565 case Tdchar: flag += 2; break;
1566 default: assert(0);
1568 const char *r = (op == TOKforeach_reverse) ? "R" : "";
1569 int j = sprintf(fdname, "_aApply%s%.*s%d", r, 2, fntab[flag], dim);
1570 assert(j < sizeof(fdname));
1571 fdapply = FuncDeclaration::genCfunc(Type::tint32, fdname,
1572 Type::tvoid->arrayOf(), flde->type); // flde->type is not generic
1574 ec = new VarExp(0, fdapply);
1575 Expressions *exps = new Expressions();
1576 if (tab->ty == Tsarray)
1577 aggr = aggr->castTo(sc, tn->arrayOf());
1578 exps->push(aggr);
1579 exps->push(flde);
1580 e = new CallExp(loc, ec, exps);
1581 e->type = Type::tint32; // don't run semantic() on e
1583 else if (tab->ty == Tdelegate)
1585 /* Call:
1586 * aggr(flde)
1588 Expressions *exps = new Expressions();
1589 exps->push(flde);
1590 e = new CallExp(loc, aggr, exps);
1591 e = e->semantic(sc);
1592 if (e->type != Type::tint32)
1593 error("opApply() function for %s must return an int", tab->toChars());
1595 else
1597 /* Call:
1598 * aggr.apply(flde)
1600 ec = new DotIdExp(loc, aggr,
1601 (op == TOKforeach_reverse) ? Id::applyReverse
1602 : Id::apply);
1603 Expressions *exps = new Expressions();
1604 exps->push(flde);
1605 e = new CallExp(loc, ec, exps);
1606 e = e->semantic(sc);
1607 if (e->type != Type::tint32)
1608 error("opApply() function for %s must return an int", tab->toChars());
1611 if (!cases.dim)
1612 // Easy case, a clean exit from the loop
1613 s = new ExpStatement(loc, e);
1614 else
1615 { // Construct a switch statement around the return value
1616 // of the apply function.
1617 Statements *a = new Statements();
1619 // default: break; takes care of cases 0 and 1
1620 s = new BreakStatement(0, NULL);
1621 s = new DefaultStatement(0, s);
1622 a->push(s);
1624 // cases 2...
1625 for (int i = 0; i < cases.dim; i++)
1627 s = (Statement *)cases.data[i];
1628 s = new CaseStatement(0, new IntegerExp(i + 2), s);
1629 a->push(s);
1632 s = new CompoundStatement(loc, a);
1633 s = new SwitchStatement(loc, e, s);
1634 s = s->semantic(sc);
1636 break;
1639 default:
1640 error("foreach: %s is not an aggregate type", aggr->type->toChars());
1641 break;
1643 sc->noctor--;
1644 sc->pop();
1645 return s;
1648 int ForeachStatement::hasBreak()
1650 return TRUE;
1653 int ForeachStatement::hasContinue()
1655 return TRUE;
1658 int ForeachStatement::usesEH()
1660 return body->usesEH();
1663 int ForeachStatement::fallOffEnd()
1665 if (body)
1666 body->fallOffEnd();
1667 return TRUE;
1670 int ForeachStatement::comeFrom()
1672 if (body)
1673 return body->comeFrom();
1674 return FALSE;
1677 void ForeachStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
1679 buf->writestring(Token::toChars(op));
1680 buf->writestring(" (");
1681 int i;
1682 for (int i = 0; i < arguments->dim; i++)
1684 Argument *a = (Argument *)arguments->data[i];
1685 if (i)
1686 buf->writestring(", ");
1687 if (a->storageClass & STCref)
1688 buf->writestring((global.params.Dversion == 1)
1689 ? (char*)"inout " : (char*)"ref ");
1690 if (a->type)
1691 a->type->toCBuffer(buf, a->ident, hgs);
1692 else
1693 buf->writestring(a->ident->toChars());
1695 buf->writestring("; ");
1696 aggr->toCBuffer(buf, hgs);
1697 buf->writebyte(')');
1698 buf->writenl();
1699 buf->writebyte('{');
1700 buf->writenl();
1701 if (body)
1702 body->toCBuffer(buf, hgs);
1703 buf->writebyte('}');
1704 buf->writenl();
1707 /******************************** IfStatement ***************************/
1709 IfStatement::IfStatement(Loc loc, Argument *arg, Expression *condition, Statement *ifbody, Statement *elsebody)
1710 : Statement(loc)
1712 this->arg = arg;
1713 this->condition = condition;
1714 this->ifbody = ifbody;
1715 this->elsebody = elsebody;
1716 this->match = NULL;
1719 Statement *IfStatement::syntaxCopy()
1721 Statement *i = NULL;
1722 if (ifbody)
1723 i = ifbody->syntaxCopy();
1725 Statement *e = NULL;
1726 if (elsebody)
1727 e = elsebody->syntaxCopy();
1729 Argument *a = arg ? arg->syntaxCopy() : NULL;
1730 IfStatement *s = new IfStatement(loc, a, condition->syntaxCopy(), i, e);
1731 return s;
1734 Statement *IfStatement::semantic(Scope *sc)
1736 condition = condition->semantic(sc);
1737 condition = resolveProperties(sc, condition);
1738 condition = condition->checkToBoolean();
1740 // If we can short-circuit evaluate the if statement, don't do the
1741 // semantic analysis of the skipped code.
1742 // This feature allows a limited form of conditional compilation.
1743 condition = condition->optimize(WANTflags);
1745 // Evaluate at runtime
1746 unsigned cs0 = sc->callSuper;
1747 unsigned cs1;
1749 Scope *scd;
1750 if (arg)
1751 { /* Declare arg, which we will set to be the
1752 * result of condition.
1754 ScopeDsymbol *sym = new ScopeDsymbol();
1755 sym->parent = sc->scopesym;
1756 scd = sc->push(sym);
1758 Type *t = arg->type ? arg->type : condition->type;
1759 match = new VarDeclaration(loc, t, arg->ident, NULL);
1760 match->noauto = 1;
1761 match->semantic(scd);
1762 if (!scd->insert(match))
1763 assert(0);
1764 match->parent = sc->func;
1766 /* Generate:
1767 * (arg = condition)
1769 VarExp *v = new VarExp(0, match);
1770 condition = new AssignExp(loc, v, condition);
1771 condition = condition->semantic(scd);
1773 else
1774 scd = sc->push();
1775 ifbody = ifbody->semantic(scd);
1776 scd->pop();
1778 cs1 = sc->callSuper;
1779 sc->callSuper = cs0;
1780 if (elsebody)
1781 elsebody = elsebody->semanticScope(sc, NULL, NULL);
1782 sc->mergeCallSuper(loc, cs1);
1784 return this;
1787 int IfStatement::usesEH()
1789 return (ifbody && ifbody->usesEH()) || (elsebody && elsebody->usesEH());
1792 int IfStatement::fallOffEnd()
1794 if (!ifbody || ifbody->fallOffEnd() ||
1795 !elsebody || elsebody->fallOffEnd())
1796 return TRUE;
1797 return FALSE;
1801 void IfStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
1803 buf->writestring("if (");
1804 if (arg)
1806 if (arg->type)
1807 arg->type->toCBuffer(buf, arg->ident, hgs);
1808 else
1809 buf->writestring(arg->ident->toChars());
1810 buf->writebyte(';');
1812 condition->toCBuffer(buf, hgs);
1813 buf->writebyte(')');
1814 buf->writenl();
1815 ifbody->toCBuffer(buf, hgs);
1816 if (elsebody)
1817 { buf->writestring("else");
1818 buf->writenl();
1819 elsebody->toCBuffer(buf, hgs);
1823 /******************************** ConditionalStatement ***************************/
1825 ConditionalStatement::ConditionalStatement(Loc loc, Condition *condition, Statement *ifbody, Statement *elsebody)
1826 : Statement(loc)
1828 this->condition = condition;
1829 this->ifbody = ifbody;
1830 this->elsebody = elsebody;
1833 Statement *ConditionalStatement::syntaxCopy()
1835 Statement *e = NULL;
1836 if (elsebody)
1837 e = elsebody->syntaxCopy();
1838 ConditionalStatement *s = new ConditionalStatement(loc,
1839 condition->syntaxCopy(), ifbody->syntaxCopy(), e);
1840 return s;
1843 Statement *ConditionalStatement::semantic(Scope *sc)
1845 //printf("ConditionalStatement::semantic()\n");
1847 // If we can short-circuit evaluate the if statement, don't do the
1848 // semantic analysis of the skipped code.
1849 // This feature allows a limited form of conditional compilation.
1850 if (condition->include(sc, NULL))
1852 ifbody = ifbody->semantic(sc);
1853 return ifbody;
1855 else
1857 if (elsebody)
1858 elsebody = elsebody->semantic(sc);
1859 return elsebody;
1863 Statements *ConditionalStatement::flatten(Scope *sc)
1865 Statement *s;
1867 if (condition->include(sc, NULL))
1868 s = ifbody;
1869 else
1870 s = elsebody;
1872 Statements *a = new Statements();
1873 a->push(s);
1874 return a;
1877 int ConditionalStatement::usesEH()
1879 return (ifbody && ifbody->usesEH()) || (elsebody && elsebody->usesEH());
1882 void ConditionalStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
1884 condition->toCBuffer(buf, hgs);
1885 buf->writenl();
1886 if (ifbody)
1887 ifbody->toCBuffer(buf, hgs);
1888 if (elsebody)
1890 buf->writestring("else");
1891 buf->writenl();
1892 elsebody->toCBuffer(buf, hgs);
1894 buf->writenl();
1898 /******************************** PragmaStatement ***************************/
1900 PragmaStatement::PragmaStatement(Loc loc, Identifier *ident, Expressions *args, Statement *body)
1901 : Statement(loc)
1903 this->ident = ident;
1904 this->args = args;
1905 this->body = body;
1908 Statement *PragmaStatement::syntaxCopy()
1910 Statement *b = NULL;
1911 if (body)
1912 b = body->syntaxCopy();
1913 PragmaStatement *s = new PragmaStatement(loc,
1914 ident, Expression::arraySyntaxCopy(args), b);
1915 return s;
1918 Statement *PragmaStatement::semantic(Scope *sc)
1919 { // Should be merged with PragmaDeclaration
1920 //printf("PragmaStatement::semantic() %s\n", toChars());
1921 //printf("body = %p\n", body);
1922 if (ident == Id::msg)
1924 if (args)
1926 for (size_t i = 0; i < args->dim; i++)
1928 Expression *e = (Expression *)args->data[i];
1930 e = e->semantic(sc);
1931 e = e->optimize(WANTvalue | WANTinterpret);
1932 if (e->op == TOKstring)
1934 StringExp *se = (StringExp *)e;
1935 fprintf(stdmsg, "%.*s", (int)se->len, se->string);
1937 else
1938 error("string expected for message, not '%s'", e->toChars());
1940 fprintf(stdmsg, "\n");
1943 else if (ident == Id::lib)
1945 if (!args || args->dim != 1)
1946 error("string expected for library name");
1947 else
1949 Expression *e = (Expression *)args->data[0];
1951 e = e->semantic(sc);
1952 e = e->optimize(WANTvalue | WANTinterpret);
1953 args->data[0] = (void *)e;
1954 if (e->op != TOKstring)
1955 error("string expected for library name, not '%s'", e->toChars());
1956 else if (global.params.verbose)
1958 StringExp *se = (StringExp *)e;
1959 char *name = (char *)mem.malloc(se->len + 1);
1960 memcpy(name, se->string, se->len);
1961 name[se->len] = 0;
1962 printf("library %s\n", name);
1963 mem.free(name);
1967 else
1968 error("unrecognized pragma(%s)", ident->toChars());
1970 if (body)
1972 body = body->semantic(sc);
1974 return body;
1977 int PragmaStatement::usesEH()
1979 return body && body->usesEH();
1982 int PragmaStatement::fallOffEnd()
1984 if (body)
1985 return body->fallOffEnd();
1986 return TRUE;
1989 void PragmaStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
1991 buf->writestring("pragma (");
1992 buf->writestring(ident->toChars());
1993 if (args && args->dim)
1995 buf->writestring(", ");
1996 argsToCBuffer(buf, args, hgs);
1998 buf->writeByte(')');
1999 if (body)
2001 buf->writenl();
2002 buf->writeByte('{');
2003 buf->writenl();
2005 body->toCBuffer(buf, hgs);
2007 buf->writeByte('}');
2008 buf->writenl();
2010 else
2012 buf->writeByte(';');
2013 buf->writenl();
2018 /******************************** LogStatement ***************************/
2020 LogStatement::LogStatement(Loc loc, int level, Expressions *args)
2021 : Statement(loc)
2023 this->level = level;
2024 this->args = args;
2027 Statement *LogStatement::semantic(Scope *sc)
2029 Expression *logger = new DotIdExp(loc, new GetLoggerExp(loc), Id::log);
2030 Type *t = new TypeTypeof(loc, new ThisExp(loc));
2031 args->shift(new DotIdExp(loc, new TypeExp(loc, t), Id::classinfo));
2032 args->shift(new IntegerExp(loc, level, Type::tint32));
2033 Expression *callLogger = new CallExp(loc, logger, args);
2035 Statement *s = new ExpStatement(loc, callLogger);
2037 return s->semantic(sc);
2040 void LogStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
2042 char *l;
2043 switch (level) {
2044 case 10: l = "log_debug"; break;
2045 case 20: l = "log_info"; break;
2046 case 30: l = "log_warning"; break;
2047 case 40: l = "log_error"; break;
2048 default:
2049 error("Unknown log level %d", level);
2050 l = "log_UNKNOWN";
2052 buf->writestring(l);
2053 buf->writeByte('(');
2054 argsToCBuffer(buf, args, hgs);
2055 buf->writeByte(')');
2056 buf->writenl();
2059 /******************************** StaticAssertStatement ***************************/
2061 StaticAssertStatement::StaticAssertStatement(StaticAssert *sa)
2062 : Statement(sa->loc)
2064 this->sa = sa;
2067 Statement *StaticAssertStatement::syntaxCopy()
2069 StaticAssertStatement *s = new StaticAssertStatement((StaticAssert *)sa->syntaxCopy(NULL));
2070 return s;
2073 Statement *StaticAssertStatement::semantic(Scope *sc)
2075 sa->semantic2(sc);
2076 return NULL;
2079 void StaticAssertStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
2081 sa->toCBuffer(buf, hgs);
2085 /******************************** SwitchStatement ***************************/
2087 SwitchStatement::SwitchStatement(Loc loc, Expression *c, Statement *b)
2088 : Statement(loc)
2090 condition = c;
2091 body = b;
2092 sdefault = NULL;
2093 cases = NULL;
2094 hasNoDefault = 0;
2097 Statement *SwitchStatement::syntaxCopy()
2099 SwitchStatement *s = new SwitchStatement(loc,
2100 condition->syntaxCopy(), body->syntaxCopy());
2101 return s;
2104 Statement *SwitchStatement::semantic(Scope *sc)
2106 //printf("SwitchStatement::semantic(%p)\n", this);
2107 assert(!cases); // ensure semantic() is only run once
2108 condition = condition->semantic(sc);
2109 condition = resolveProperties(sc, condition);
2110 if (condition->type->isString())
2112 // If it's not an array, cast it to one
2113 if (condition->type->ty != Tarray)
2115 condition = condition->implicitCastTo(sc, condition->type->nextOf()->arrayOf());
2118 else
2119 { condition = condition->integralPromotions(sc);
2120 condition->checkIntegral();
2122 condition = condition->optimize(WANTvalue);
2124 sc = sc->push();
2125 sc->sbreak = this;
2126 sc->sw = this;
2128 cases = new Array();
2129 sc->noctor++; // BUG: should use Scope::mergeCallSuper() for each case instead
2130 body = body->semantic(sc);
2131 sc->noctor--;
2133 // Resolve any goto case's with exp
2134 for (int i = 0; i < gotoCases.dim; i++)
2136 GotoCaseStatement *gcs = (GotoCaseStatement *)gotoCases.data[i];
2138 if (!gcs->exp)
2140 gcs->error("no case statement following goto case;");
2141 break;
2144 for (Scope *scx = sc; scx; scx = scx->enclosing)
2146 if (!scx->sw)
2147 continue;
2148 for (int j = 0; j < scx->sw->cases->dim; j++)
2150 CaseStatement *cs = (CaseStatement *)scx->sw->cases->data[j];
2152 if (cs->exp->equals(gcs->exp))
2154 gcs->cs = cs;
2155 goto Lfoundcase;
2159 gcs->error("case %s not found", gcs->exp->toChars());
2161 Lfoundcase:
2165 if (!sc->sw->sdefault)
2166 { hasNoDefault = 1;
2168 if (global.params.warnings)
2169 { fprintf(stdmsg, "warning - ");
2170 error("switch statement has no default");
2173 // Generate runtime error if the default is hit
2174 Statements *a = new Statements();
2175 CompoundStatement *cs;
2176 Statement *s;
2178 if (global.params.useSwitchError)
2179 s = new SwitchErrorStatement(loc);
2180 else
2181 { Expression *e = new HaltExp(loc);
2182 s = new ExpStatement(loc, e);
2185 a->reserve(4);
2186 a->push(body);
2187 a->push(new BreakStatement(loc, NULL));
2188 sc->sw->sdefault = new DefaultStatement(loc, s);
2189 a->push(sc->sw->sdefault);
2190 cs = new CompoundStatement(loc, a);
2191 body = cs;
2194 sc->pop();
2195 return this;
2198 int SwitchStatement::hasBreak()
2200 return TRUE;
2203 int SwitchStatement::usesEH()
2205 return body ? body->usesEH() : 0;
2208 int SwitchStatement::fallOffEnd()
2210 if (body)
2211 body->fallOffEnd();
2212 return TRUE; // need to do this better
2215 void SwitchStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
2217 buf->writestring("switch (");
2218 condition->toCBuffer(buf, hgs);
2219 buf->writebyte(')');
2220 buf->writenl();
2221 if (body)
2223 if (!body->isScopeStatement())
2224 { buf->writebyte('{');
2225 buf->writenl();
2226 body->toCBuffer(buf, hgs);
2227 buf->writebyte('}');
2228 buf->writenl();
2230 else
2232 body->toCBuffer(buf, hgs);
2237 /******************************** CaseStatement ***************************/
2239 CaseStatement::CaseStatement(Loc loc, Expression *exp, Statement *s)
2240 : Statement(loc)
2242 this->exp = exp;
2243 this->statement = s;
2244 cblock = NULL;
2247 Statement *CaseStatement::syntaxCopy()
2249 CaseStatement *s = new CaseStatement(loc, exp->syntaxCopy(), statement->syntaxCopy());
2250 return s;
2253 Statement *CaseStatement::semantic(Scope *sc)
2254 { SwitchStatement *sw = sc->sw;
2256 //printf("CaseStatement::semantic() %s\n", toChars());
2257 exp = exp->semantic(sc);
2258 if (sw)
2259 { int i;
2261 exp = exp->implicitCastTo(sc, sw->condition->type);
2262 exp = exp->optimize(WANTvalue | WANTinterpret);
2263 if (exp->op != TOKstring && exp->op != TOKint64)
2265 error("case must be a string or an integral constant, not %s", exp->toChars());
2266 exp = new IntegerExp(0);
2269 for (i = 0; i < sw->cases->dim; i++)
2271 CaseStatement *cs = (CaseStatement *)sw->cases->data[i];
2273 //printf("comparing '%s' with '%s'\n", exp->toChars(), cs->exp->toChars());
2274 if (cs->exp->equals(exp))
2275 { error("duplicate case %s in switch statement", exp->toChars());
2276 break;
2280 sw->cases->push(this);
2282 // Resolve any goto case's with no exp to this case statement
2283 for (i = 0; i < sw->gotoCases.dim; i++)
2285 GotoCaseStatement *gcs = (GotoCaseStatement *)sw->gotoCases.data[i];
2287 if (!gcs->exp)
2289 gcs->cs = this;
2290 sw->gotoCases.remove(i); // remove from array
2294 else
2295 error("case not in switch statement");
2296 statement = statement->semantic(sc);
2297 return this;
2300 int CaseStatement::compare(Object *obj)
2302 // Sort cases so we can do an efficient lookup
2303 CaseStatement *cs2 = (CaseStatement *)(obj);
2305 return exp->compare(cs2->exp);
2308 int CaseStatement::usesEH()
2310 return statement->usesEH();
2313 int CaseStatement::fallOffEnd()
2315 return statement->fallOffEnd();
2318 int CaseStatement::comeFrom()
2320 return TRUE;
2323 void CaseStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
2325 buf->writestring("case ");
2326 exp->toCBuffer(buf, hgs);
2327 buf->writebyte(':');
2328 buf->writenl();
2329 statement->toCBuffer(buf, hgs);
2332 /******************************** DefaultStatement ***************************/
2334 DefaultStatement::DefaultStatement(Loc loc, Statement *s)
2335 : Statement(loc)
2337 this->statement = s;
2338 #if IN_GCC
2339 cblock = NULL;
2340 #endif
2343 Statement *DefaultStatement::syntaxCopy()
2345 DefaultStatement *s = new DefaultStatement(loc, statement->syntaxCopy());
2346 return s;
2349 Statement *DefaultStatement::semantic(Scope *sc)
2351 if (sc->sw)
2353 if (sc->sw->sdefault)
2355 error("switch statement already has a default");
2357 sc->sw->sdefault = this;
2359 else
2360 error("default not in switch statement");
2361 statement = statement->semantic(sc);
2362 return this;
2365 int DefaultStatement::usesEH()
2367 return statement->usesEH();
2370 int DefaultStatement::fallOffEnd()
2372 return statement->fallOffEnd();
2375 int DefaultStatement::comeFrom()
2377 return TRUE;
2380 void DefaultStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
2382 buf->writestring("default:\n");
2383 statement->toCBuffer(buf, hgs);
2386 /******************************** GotoDefaultStatement ***************************/
2388 GotoDefaultStatement::GotoDefaultStatement(Loc loc)
2389 : Statement(loc)
2391 sw = NULL;
2394 Statement *GotoDefaultStatement::syntaxCopy()
2396 GotoDefaultStatement *s = new GotoDefaultStatement(loc);
2397 return s;
2400 Statement *GotoDefaultStatement::semantic(Scope *sc)
2402 sw = sc->sw;
2403 if (!sw)
2404 error("goto default not in switch statement");
2405 return this;
2408 int GotoDefaultStatement::fallOffEnd()
2410 return FALSE;
2413 void GotoDefaultStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
2415 buf->writestring("goto default;\n");
2418 /******************************** GotoCaseStatement ***************************/
2420 GotoCaseStatement::GotoCaseStatement(Loc loc, Expression *exp)
2421 : Statement(loc)
2423 cs = NULL;
2424 this->exp = exp;
2427 Statement *GotoCaseStatement::syntaxCopy()
2429 Expression *e = exp ? exp->syntaxCopy() : NULL;
2430 GotoCaseStatement *s = new GotoCaseStatement(loc, e);
2431 return s;
2434 Statement *GotoCaseStatement::semantic(Scope *sc)
2436 if (exp)
2437 exp = exp->semantic(sc);
2439 if (!sc->sw)
2440 error("goto case not in switch statement");
2441 else
2443 sc->sw->gotoCases.push(this);
2444 if (exp)
2446 exp = exp->implicitCastTo(sc, sc->sw->condition->type);
2447 exp = exp->optimize(WANTvalue);
2450 return this;
2453 int GotoCaseStatement::fallOffEnd()
2455 return FALSE;
2458 void GotoCaseStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
2460 buf->writestring("goto case");
2461 if (exp)
2462 { buf->writebyte(' ');
2463 exp->toCBuffer(buf, hgs);
2465 buf->writebyte(';');
2466 buf->writenl();
2469 /******************************** SwitchErrorStatement ***************************/
2471 SwitchErrorStatement::SwitchErrorStatement(Loc loc)
2472 : Statement(loc)
2476 int SwitchErrorStatement::fallOffEnd()
2478 return FALSE;
2481 void SwitchErrorStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
2483 buf->writestring("SwitchErrorStatement::toCBuffer()");
2484 buf->writenl();
2487 /******************************** ReturnStatement ***************************/
2489 ReturnStatement::ReturnStatement(Loc loc, Expression *exp)
2490 : Statement(loc)
2492 this->exp = exp;
2495 Statement *ReturnStatement::syntaxCopy()
2497 Expression *e = NULL;
2498 if (exp)
2499 e = exp->syntaxCopy();
2500 ReturnStatement *s = new ReturnStatement(loc, e);
2501 return s;
2504 Statement *ReturnStatement::semantic(Scope *sc)
2506 //printf("ReturnStatement::semantic() %s\n", toChars());
2508 FuncDeclaration *fd = sc->parent->isFuncDeclaration();
2509 Scope *scx = sc;
2510 int implicit0 = 0;
2512 if (sc->fes)
2514 // Find scope of function foreach is in
2515 for (; 1; scx = scx->enclosing)
2517 assert(scx);
2518 if (scx->func != fd)
2519 { fd = scx->func; // fd is now function enclosing foreach
2520 break;
2525 Type *tret = fd->type->nextOf();
2526 if (fd->tintro)
2527 tret = fd->tintro->nextOf();
2528 Type *tbret = NULL;
2530 if (tret)
2531 tbret = tret->toBasetype();
2533 // main() returns 0, even if it returns void
2534 if (!exp && (!tbret || tbret->ty == Tvoid) && fd->isMain())
2535 { implicit0 = 1;
2536 exp = new IntegerExp(0);
2539 if (sc->incontract || scx->incontract)
2540 error("return statements cannot be in contracts");
2541 if (sc->tf || scx->tf)
2542 error("return statements cannot be in finally, scope(exit) or scope(success) bodies");
2544 if (fd->isCtorDeclaration())
2546 // Constructors implicitly do:
2547 // return this;
2548 if (exp && exp->op != TOKthis)
2549 error("cannot return expression from constructor");
2550 exp = new ThisExp(0);
2553 if (!exp)
2554 fd->nrvo_can = 0;
2556 if (exp)
2558 fd->hasReturnExp |= 1;
2560 exp = exp->semantic(sc);
2561 exp = resolveProperties(sc, exp);
2562 exp = exp->optimize(WANTvalue);
2564 if (fd->nrvo_can && exp->op == TOKvar)
2565 { VarExp *ve = (VarExp *)exp;
2566 VarDeclaration *v = ve->var->isVarDeclaration();
2568 if (!v || v->isOut() || v->isRef())
2569 fd->nrvo_can = 0;
2570 else if (fd->nrvo_var == NULL)
2571 { if (!v->isDataseg() && !v->isParameter() && v->toParent2() == fd)
2572 fd->nrvo_var = v;
2573 else
2574 fd->nrvo_can = 0;
2576 else if (fd->nrvo_var != v)
2577 fd->nrvo_can = 0;
2579 else
2580 fd->nrvo_can = 0;
2582 if (fd->returnLabel && tbret->ty != Tvoid)
2585 else if (fd->inferRetType)
2587 if (fd->type->nextOf())
2589 if (!exp->type->equals(fd->type->nextOf()))
2590 error("mismatched function return type inference of %s and %s",
2591 exp->type->toChars(), fd->type->nextOf()->toChars());
2593 else
2595 fd->type->next = exp->type;
2596 fd->type = fd->type->semantic(loc, sc);
2597 if (!fd->tintro)
2598 { tret = fd->type->nextOf();
2599 tbret = tret->toBasetype();
2603 else if (tbret->ty != Tvoid)
2605 exp = exp->implicitCastTo(sc, tret);
2608 else if (fd->inferRetType)
2610 if (fd->type->nextOf())
2612 if (fd->type->nextOf()->ty != Tvoid)
2613 error("mismatched function return type inference of void and %s",
2614 fd->type->nextOf()->toChars());
2616 else
2618 fd->type->next = Type::tvoid;
2619 fd->type = fd->type->semantic(loc, sc);
2620 if (!fd->tintro)
2621 { tret = Type::tvoid;
2622 tbret = tret;
2626 else if (tbret->ty != Tvoid) // if non-void return
2627 error("return expression expected");
2629 if (sc->fes)
2631 Statement *s;
2633 if (exp && !implicit0)
2635 exp = exp->implicitCastTo(sc, tret);
2637 if (!exp || exp->op == TOKint64 || exp->op == TOKfloat64 ||
2638 exp->op == TOKimaginary80 || exp->op == TOKcomplex80 ||
2639 exp->op == TOKthis || exp->op == TOKsuper || exp->op == TOKnull ||
2640 exp->op == TOKstring)
2642 sc->fes->cases.push(this);
2643 s = new ReturnStatement(0, new IntegerExp(sc->fes->cases.dim + 1));
2645 else if (fd->type->nextOf()->toBasetype() == Type::tvoid)
2647 Statement *s1;
2648 Statement *s2;
2650 s = new ReturnStatement(0, NULL);
2651 sc->fes->cases.push(s);
2653 // Construct: { exp; return cases.dim + 1; }
2654 s1 = new ExpStatement(loc, exp);
2655 s2 = new ReturnStatement(0, new IntegerExp(sc->fes->cases.dim + 1));
2656 s = new CompoundStatement(loc, s1, s2);
2658 else
2660 VarExp *v;
2661 Statement *s1;
2662 Statement *s2;
2664 // Construct: return vresult;
2665 if (!fd->vresult)
2666 { VarDeclaration *v;
2668 v = new VarDeclaration(loc, tret, Id::result, NULL);
2669 v->noauto = 1;
2670 v->semantic(scx);
2671 if (!scx->insert(v))
2672 assert(0);
2673 v->parent = fd;
2674 fd->vresult = v;
2677 v = new VarExp(0, fd->vresult);
2678 s = new ReturnStatement(0, v);
2679 sc->fes->cases.push(s);
2681 // Construct: { vresult = exp; return cases.dim + 1; }
2682 v = new VarExp(0, fd->vresult);
2683 exp = new AssignExp(loc, v, exp);
2684 exp = exp->semantic(sc);
2685 s1 = new ExpStatement(loc, exp);
2686 s2 = new ReturnStatement(0, new IntegerExp(sc->fes->cases.dim + 1));
2687 s = new CompoundStatement(loc, s1, s2);
2689 return s;
2692 if (exp)
2694 if (fd->returnLabel && tbret->ty != Tvoid)
2696 assert(fd->vresult);
2697 VarExp *v = new VarExp(0, fd->vresult);
2699 exp = new AssignExp(loc, v, exp);
2700 exp = exp->semantic(sc);
2702 //exp->dump(0);
2703 //exp->print();
2704 exp->checkEscape();
2707 /* BUG: need to issue an error on:
2708 * this
2709 * { if (x) return;
2710 * super();
2714 if (sc->callSuper & CSXany_ctor &&
2715 !(sc->callSuper & (CSXthis_ctor | CSXsuper_ctor)))
2716 error("return without calling constructor");
2718 sc->callSuper |= CSXreturn;
2720 // See if all returns are instead to be replaced with a goto returnLabel;
2721 if (fd->returnLabel)
2723 GotoStatement *gs = new GotoStatement(loc, Id::returnLabel);
2725 gs->label = fd->returnLabel;
2726 if (exp)
2727 { Statement *s;
2729 s = new ExpStatement(0, exp);
2730 return new CompoundStatement(loc, s, gs);
2732 return gs;
2735 if (exp && tbret->ty == Tvoid && !fd->isMain())
2736 { Statement *s;
2738 s = new ExpStatement(loc, exp);
2739 loc = 0;
2740 exp = NULL;
2741 return new CompoundStatement(loc, s, this);
2744 return this;
2747 int ReturnStatement::fallOffEnd()
2749 return FALSE;
2752 void ReturnStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
2754 buf->printf("return ");
2755 if (exp)
2756 exp->toCBuffer(buf, hgs);
2757 buf->writeByte(';');
2758 buf->writenl();
2761 /******************************** BreakStatement ***************************/
2763 BreakStatement::BreakStatement(Loc loc, Identifier *ident)
2764 : Statement(loc)
2766 this->ident = ident;
2769 Statement *BreakStatement::syntaxCopy()
2771 BreakStatement *s = new BreakStatement(loc, ident);
2772 return s;
2775 Statement *BreakStatement::semantic(Scope *sc)
2777 // If:
2778 // break Identifier;
2779 if (ident)
2781 Scope *scx;
2782 FuncDeclaration *thisfunc = sc->func;
2784 for (scx = sc; scx; scx = scx->enclosing)
2786 LabelStatement *ls;
2788 if (scx->func != thisfunc) // if in enclosing function
2790 if (sc->fes) // if this is the body of a foreach
2792 /* Post this statement to the fes, and replace
2793 * it with a return value that caller will put into
2794 * a switch. Caller will figure out where the break
2795 * label actually is.
2796 * Case numbers start with 2, not 0, as 0 is continue
2797 * and 1 is break.
2799 Statement *s;
2800 sc->fes->cases.push(this);
2801 s = new ReturnStatement(0, new IntegerExp(sc->fes->cases.dim + 1));
2802 return s;
2804 break; // can't break to it
2807 ls = scx->slabel;
2808 if (ls && ls->ident == ident)
2810 Statement *s = ls->statement;
2812 if (!s->hasBreak())
2813 error("label '%s' has no break", ident->toChars());
2814 if (ls->tf != sc->tf)
2815 error("cannot break out of finally block");
2816 return this;
2819 error("enclosing label '%s' for break not found", ident->toChars());
2821 else if (!sc->sbreak)
2823 if (sc->fes)
2824 { Statement *s;
2826 // Replace break; with return 1;
2827 s = new ReturnStatement(0, new IntegerExp(1));
2828 return s;
2830 error("break is not inside a loop or switch");
2832 return this;
2835 int BreakStatement::fallOffEnd()
2837 return FALSE;
2840 void BreakStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
2842 buf->writestring("break");
2843 if (ident)
2844 { buf->writebyte(' ');
2845 buf->writestring(ident->toChars());
2847 buf->writebyte(';');
2848 buf->writenl();
2851 /******************************** ContinueStatement ***************************/
2853 ContinueStatement::ContinueStatement(Loc loc, Identifier *ident)
2854 : Statement(loc)
2856 this->ident = ident;
2859 Statement *ContinueStatement::syntaxCopy()
2861 ContinueStatement *s = new ContinueStatement(loc, ident);
2862 return s;
2865 Statement *ContinueStatement::semantic(Scope *sc)
2867 //printf("ContinueStatement::semantic() %p\n", this);
2868 if (ident)
2870 Scope *scx;
2871 FuncDeclaration *thisfunc = sc->func;
2873 for (scx = sc; scx; scx = scx->enclosing)
2875 LabelStatement *ls;
2877 if (scx->func != thisfunc) // if in enclosing function
2879 if (sc->fes) // if this is the body of a foreach
2881 for (; scx; scx = scx->enclosing)
2883 ls = scx->slabel;
2884 if (ls && ls->ident == ident && ls->statement == sc->fes)
2886 // Replace continue ident; with return 0;
2887 return new ReturnStatement(0, new IntegerExp(0));
2891 /* Post this statement to the fes, and replace
2892 * it with a return value that caller will put into
2893 * a switch. Caller will figure out where the break
2894 * label actually is.
2895 * Case numbers start with 2, not 0, as 0 is continue
2896 * and 1 is break.
2898 Statement *s;
2899 sc->fes->cases.push(this);
2900 s = new ReturnStatement(0, new IntegerExp(sc->fes->cases.dim + 1));
2901 return s;
2903 break; // can't continue to it
2906 ls = scx->slabel;
2907 if (ls && ls->ident == ident)
2909 Statement *s = ls->statement;
2911 if (!s->hasContinue())
2912 error("label '%s' has no continue", ident->toChars());
2913 if (ls->tf != sc->tf)
2914 error("cannot continue out of finally block");
2915 return this;
2918 error("enclosing label '%s' for continue not found", ident->toChars());
2920 else if (!sc->scontinue)
2922 if (sc->fes)
2923 { Statement *s;
2925 // Replace continue; with return 0;
2926 s = new ReturnStatement(0, new IntegerExp(0));
2927 return s;
2929 error("continue is not inside a loop");
2931 return this;
2934 int ContinueStatement::fallOffEnd()
2936 return FALSE;
2939 void ContinueStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
2941 buf->writestring("continue");
2942 if (ident)
2943 { buf->writebyte(' ');
2944 buf->writestring(ident->toChars());
2946 buf->writebyte(';');
2947 buf->writenl();
2950 /******************************** SynchronizedStatement ***************************/
2952 SynchronizedStatement::SynchronizedStatement(Loc loc, Expression *exp, Statement *body)
2953 : Statement(loc)
2955 this->exp = exp;
2956 this->body = body;
2957 this->esync = NULL;
2960 SynchronizedStatement::SynchronizedStatement(Loc loc, elem *esync, Statement *body)
2961 : Statement(loc)
2963 this->exp = NULL;
2964 this->body = body;
2965 this->esync = esync;
2968 Statement *SynchronizedStatement::syntaxCopy()
2970 Expression *e = exp ? exp->syntaxCopy() : NULL;
2971 SynchronizedStatement *s = new SynchronizedStatement(loc, e, body ? body->syntaxCopy() : NULL);
2972 return s;
2975 Statement *SynchronizedStatement::semantic(Scope *sc)
2977 if (exp)
2978 { ClassDeclaration *cd;
2980 exp = exp->semantic(sc);
2981 exp = resolveProperties(sc, exp);
2982 cd = exp->type->isClassHandle();
2983 if (!cd)
2984 error("can only synchronize on class objects, not '%s'", exp->type->toChars());
2985 else if (cd->isInterfaceDeclaration())
2986 { Type *t = new TypeIdentifier(0, Id::Object);
2988 t = t->semantic(0, sc);
2989 exp = new CastExp(loc, exp, t);
2990 exp = exp->semantic(sc);
2993 if (body)
2994 body = body->semantic(sc);
2995 return this;
2998 int SynchronizedStatement::hasBreak()
3000 return FALSE; //TRUE;
3003 int SynchronizedStatement::hasContinue()
3005 return FALSE; //TRUE;
3008 int SynchronizedStatement::usesEH()
3010 return TRUE;
3013 int SynchronizedStatement::fallOffEnd()
3015 return body ? body->fallOffEnd() : TRUE;
3018 void SynchronizedStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
3020 buf->writestring("synchronized");
3021 if (exp)
3022 { buf->writebyte('(');
3023 exp->toCBuffer(buf, hgs);
3024 buf->writebyte(')');
3026 if (body)
3028 buf->writebyte(' ');
3029 body->toCBuffer(buf, hgs);
3033 /******************************** WithStatement ***************************/
3035 WithStatement::WithStatement(Loc loc, Expression *exp, Statement *body)
3036 : Statement(loc)
3038 this->exp = exp;
3039 this->body = body;
3040 wthis = NULL;
3043 Statement *WithStatement::syntaxCopy()
3045 WithStatement *s = new WithStatement(loc, exp->syntaxCopy(), body ? body->syntaxCopy() : NULL);
3046 return s;
3049 Statement *WithStatement::semantic(Scope *sc)
3050 { ScopeDsymbol *sym;
3051 Initializer *init;
3053 //printf("WithStatement::semantic()\n");
3054 exp = exp->semantic(sc);
3055 exp = resolveProperties(sc, exp);
3056 if (exp->op == TOKimport)
3057 { ScopeExp *es = (ScopeExp *)exp;
3059 sym = es->sds;
3061 else if (exp->op == TOKtype)
3062 { TypeExp *es = (TypeExp *)exp;
3064 sym = es->type->toDsymbol(sc)->isScopeDsymbol();
3065 if (!sym)
3066 { error("%s has no members", es->toChars());
3067 body = body->semantic(sc);
3068 return this;
3071 else
3072 { Type *t = exp->type;
3074 assert(t);
3075 t = t->toBasetype();
3076 if (t->isClassHandle())
3078 init = new ExpInitializer(loc, exp);
3079 wthis = new VarDeclaration(loc, exp->type, Id::withSym, init);
3080 wthis->semantic(sc);
3082 sym = new WithScopeSymbol(this);
3083 sym->parent = sc->scopesym;
3085 else if (t->ty == Tstruct)
3087 Expression *e = exp->addressOf(sc);
3088 init = new ExpInitializer(loc, e);
3089 wthis = new VarDeclaration(loc, e->type, Id::withSym, init);
3090 wthis->semantic(sc);
3091 sym = new WithScopeSymbol(this);
3092 sym->parent = sc->scopesym;
3094 else
3095 { error("with expressions must be class objects, not '%s'", exp->type->toChars());
3096 return NULL;
3099 sc = sc->push(sym);
3101 if (body)
3102 body = body->semantic(sc);
3104 sc->pop();
3106 return this;
3109 void WithStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
3111 buf->writestring("with (");
3112 exp->toCBuffer(buf, hgs);
3113 buf->writestring(")\n");
3114 if (body)
3115 body->toCBuffer(buf, hgs);
3118 int WithStatement::usesEH()
3120 return body ? body->usesEH() : 0;
3123 int WithStatement::fallOffEnd()
3125 return body ? body->fallOffEnd() : TRUE;
3128 /******************************** TryCatchStatement ***************************/
3130 TryCatchStatement::TryCatchStatement(Loc loc, Statement *body, Array *catches)
3131 : Statement(loc)
3133 this->body = body;
3134 this->catches = catches;
3137 Statement *TryCatchStatement::syntaxCopy()
3139 Array *a = new Array();
3140 a->setDim(catches->dim);
3141 for (int i = 0; i < a->dim; i++)
3142 { Catch *c;
3144 c = (Catch *)catches->data[i];
3145 c = c->syntaxCopy();
3146 a->data[i] = c;
3148 TryCatchStatement *s = new TryCatchStatement(loc, body->syntaxCopy(), a);
3149 return s;
3152 Statement *TryCatchStatement::semantic(Scope *sc)
3154 body = body->semanticScope(sc, NULL /*this*/, NULL);
3156 for (int i = 0; i < catches->dim; i++)
3157 { Catch *c;
3159 c = (Catch *)catches->data[i];
3160 c->semantic(sc);
3162 // Determine if current catch 'hides' any previous catches
3163 for (int j = 0; j < i; j++)
3164 { Catch *cj = (Catch *)catches->data[j];
3165 char *si = c->loc.toChars();
3166 char *sj = cj->loc.toChars();
3168 if (c->type->toBasetype()->implicitConvTo(cj->type->toBasetype()))
3169 error("catch at %s hides catch at %s", sj, si);
3172 return this;
3175 int TryCatchStatement::hasBreak()
3177 return FALSE; //TRUE;
3180 int TryCatchStatement::usesEH()
3182 return TRUE;
3185 int TryCatchStatement::fallOffEnd()
3187 int result = FALSE;
3189 if (body)
3190 result = body->fallOffEnd();
3191 for (int i = 0; i < catches->dim; i++)
3192 { Catch *c;
3194 c = (Catch *)catches->data[i];
3195 if (c->handler)
3196 result |= c->handler->fallOffEnd();
3198 return result;
3201 void TryCatchStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
3203 buf->writestring("try");
3204 buf->writenl();
3205 if (body)
3206 body->toCBuffer(buf, hgs);
3207 int i;
3208 for (i = 0; i < catches->dim; i++)
3210 Catch *c = (Catch *)catches->data[i];
3211 c->toCBuffer(buf, hgs);
3215 /******************************** Catch ***************************/
3217 Catch::Catch(Loc loc, Type *t, Identifier *id, Statement *handler)
3219 //printf("Catch(%s, loc = %s)\n", id->toChars(), loc.toChars());
3220 this->loc = loc;
3221 this->type = t;
3222 this->ident = id;
3223 this->handler = handler;
3224 var = NULL;
3227 Catch *Catch::syntaxCopy()
3229 Catch *c = new Catch(loc,
3230 (type ? type->syntaxCopy() : NULL),
3231 ident,
3232 (handler ? handler->syntaxCopy() : NULL));
3233 return c;
3236 void Catch::semantic(Scope *sc)
3237 { ScopeDsymbol *sym;
3239 //printf("Catch::semantic(%s)\n", ident->toChars());
3241 #ifndef IN_GCC
3242 if (sc->tf)
3244 /* This is because the _d_local_unwind() gets the stack munged
3245 * up on this. The workaround is to place any try-catches into
3246 * a separate function, and call that.
3247 * To fix, have the compiler automatically convert the finally
3248 * body into a nested function.
3250 error(loc, "cannot put catch statement inside finally block");
3252 #endif
3254 sym = new ScopeDsymbol();
3255 sym->parent = sc->scopesym;
3256 sc = sc->push(sym);
3258 if (!type)
3259 type = new TypeIdentifier(0, Id::Object);
3260 type = type->semantic(loc, sc);
3261 if (!type->toBasetype()->isClassHandle())
3262 error("can only catch class objects, not '%s'", type->toChars());
3263 else if (ident)
3265 var = new VarDeclaration(loc, type, ident, NULL);
3266 var->parent = sc->parent;
3267 sc->insert(var);
3269 handler = handler->semantic(sc);
3271 sc->pop();
3274 void Catch::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
3276 buf->writestring("catch");
3277 if (type)
3278 { buf->writebyte('(');
3279 type->toCBuffer(buf, ident, hgs);
3280 buf->writebyte(')');
3282 buf->writenl();
3283 buf->writebyte('{');
3284 buf->writenl();
3285 handler->toCBuffer(buf, hgs);
3286 buf->writebyte('}');
3287 buf->writenl();
3290 /****************************** TryFinallyStatement ***************************/
3292 TryFinallyStatement::TryFinallyStatement(Loc loc, Statement *body, Statement *finalbody)
3293 : Statement(loc)
3295 this->body = body;
3296 this->finalbody = finalbody;
3299 Statement *TryFinallyStatement::syntaxCopy()
3301 TryFinallyStatement *s = new TryFinallyStatement(loc,
3302 body->syntaxCopy(), finalbody->syntaxCopy());
3303 return s;
3306 Statement *TryFinallyStatement::semantic(Scope *sc)
3308 //printf("TryFinallyStatement::semantic()\n");
3309 body = body->semantic(sc);
3310 sc = sc->push();
3311 sc->tf = this;
3312 sc->sbreak = NULL;
3313 sc->scontinue = NULL; // no break or continue out of finally block
3314 finalbody = finalbody->semantic(sc);
3315 sc->pop();
3316 return this;
3319 void TryFinallyStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
3321 buf->printf("try\n{\n");
3322 body->toCBuffer(buf, hgs);
3323 buf->printf("}\nfinally\n{\n");
3324 finalbody->toCBuffer(buf, hgs);
3325 buf->writeByte('}');
3326 buf->writenl();
3329 int TryFinallyStatement::hasBreak()
3331 return FALSE; //TRUE;
3334 int TryFinallyStatement::hasContinue()
3336 return FALSE; //TRUE;
3339 int TryFinallyStatement::usesEH()
3341 return TRUE;
3344 int TryFinallyStatement::fallOffEnd()
3345 { int result;
3347 result = body ? body->fallOffEnd() : TRUE;
3348 // if (finalbody)
3349 // result = finalbody->fallOffEnd();
3350 return result;
3353 /****************************** OnScopeStatement ***************************/
3355 OnScopeStatement::OnScopeStatement(Loc loc, TOK tok, Statement *statement)
3356 : Statement(loc)
3358 this->tok = tok;
3359 this->statement = statement;
3362 Statement *OnScopeStatement::syntaxCopy()
3364 OnScopeStatement *s = new OnScopeStatement(loc,
3365 tok, statement->syntaxCopy());
3366 return s;
3369 Statement *OnScopeStatement::semantic(Scope *sc)
3371 /* semantic is called on results of scopeCode() */
3372 return this;
3375 void OnScopeStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
3377 buf->writestring(Token::toChars(tok));
3378 buf->writebyte(' ');
3379 statement->toCBuffer(buf, hgs);
3382 int OnScopeStatement::usesEH()
3384 return (tok != TOKon_scope_success);
3387 void OnScopeStatement::scopeCode(Statement **sentry, Statement **sexception, Statement **sfinally)
3389 //printf("OnScopeStatement::scopeCode()\n");
3390 //print();
3391 *sentry = NULL;
3392 *sexception = NULL;
3393 *sfinally = NULL;
3394 switch (tok)
3396 case TOKon_scope_exit:
3397 *sfinally = statement;
3398 break;
3400 case TOKon_scope_failure:
3401 *sexception = statement;
3402 break;
3404 case TOKon_scope_success:
3406 /* Create:
3407 * sentry: int x = 0;
3408 * sexception: x = 1;
3409 * sfinally: if (!x) statement;
3411 static int num;
3412 char name[5 + sizeof(num) * 3 + 1];
3413 sprintf(name, "__osf%d", ++num);
3414 Identifier *id = Lexer::idPool(name);
3416 ExpInitializer *ie = new ExpInitializer(loc, new IntegerExp(0));
3417 VarDeclaration *v = new VarDeclaration(loc, Type::tint32, id, ie);
3418 *sentry = new DeclarationStatement(loc, v);
3420 Expression *e = new IntegerExp(1);
3421 e = new AssignExp(0, new VarExp(0, v), e);
3422 *sexception = new ExpStatement(0, e);
3424 e = new VarExp(0, v);
3425 e = new NotExp(0, e);
3426 *sfinally = new IfStatement(0, NULL, e, statement, NULL);
3428 break;
3431 default:
3432 assert(0);
3436 /******************************** ThrowStatement ***************************/
3438 ThrowStatement::ThrowStatement(Loc loc, Expression *exp)
3439 : Statement(loc)
3441 this->exp = exp;
3444 Statement *ThrowStatement::syntaxCopy()
3446 ThrowStatement *s = new ThrowStatement(loc, exp->syntaxCopy());
3447 return s;
3450 Statement *ThrowStatement::semantic(Scope *sc)
3452 //printf("ThrowStatement::semantic()\n");
3454 FuncDeclaration *fd = sc->parent->isFuncDeclaration();
3455 fd->hasReturnExp |= 2;
3457 if (sc->incontract)
3458 error("Throw statements cannot be in contracts");
3459 exp = exp->semantic(sc);
3460 exp = resolveProperties(sc, exp);
3461 if (!exp->type->toBasetype()->isClassHandle())
3462 error("can only throw class objects, not type %s", exp->type->toChars());
3463 return this;
3466 int ThrowStatement::fallOffEnd()
3468 return FALSE;
3471 void ThrowStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
3473 buf->printf("throw ");
3474 exp->toCBuffer(buf, hgs);
3475 buf->writeByte(';');
3476 buf->writenl();
3479 /******************************** VolatileStatement **************************/
3481 VolatileStatement::VolatileStatement(Loc loc, Statement *statement)
3482 : Statement(loc)
3484 this->statement = statement;
3487 Statement *VolatileStatement::syntaxCopy()
3489 VolatileStatement *s = new VolatileStatement(loc,
3490 statement ? statement->syntaxCopy() : NULL);
3491 return s;
3494 Statement *VolatileStatement::semantic(Scope *sc)
3496 statement = statement ? statement->semantic(sc) : NULL;
3497 return this;
3500 Statements *VolatileStatement::flatten(Scope *sc)
3502 Statements *a;
3504 a = statement ? statement->flatten(sc) : NULL;
3505 if (a)
3506 { for (int i = 0; i < a->dim; i++)
3507 { Statement *s = (Statement *)a->data[i];
3509 s = new VolatileStatement(loc, s);
3510 a->data[i] = s;
3514 return a;
3517 int VolatileStatement::fallOffEnd()
3519 return statement ? statement->fallOffEnd() : TRUE;
3522 void VolatileStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
3524 buf->writestring("volatile");
3525 if (statement)
3526 { if (statement->isScopeStatement())
3527 buf->writenl();
3528 else
3529 buf->writebyte(' ');
3530 statement->toCBuffer(buf, hgs);
3535 /******************************** GotoStatement ***************************/
3537 GotoStatement::GotoStatement(Loc loc, Identifier *ident)
3538 : Statement(loc)
3540 this->ident = ident;
3541 this->label = NULL;
3542 this->tf = NULL;
3545 Statement *GotoStatement::syntaxCopy()
3547 GotoStatement *s = new GotoStatement(loc, ident);
3548 return s;
3551 Statement *GotoStatement::semantic(Scope *sc)
3552 { FuncDeclaration *fd = sc->parent->isFuncDeclaration();
3554 //printf("GotoStatement::semantic()\n");
3555 tf = sc->tf;
3556 label = fd->searchLabel(ident);
3557 if (!label->statement && sc->fes)
3559 /* Either the goto label is forward referenced or it
3560 * is in the function that the enclosing foreach is in.
3561 * Can't know yet, so wrap the goto in a compound statement
3562 * so we can patch it later, and add it to a 'look at this later'
3563 * list.
3565 Statements *a = new Statements();
3566 Statement *s;
3568 a->push(this);
3569 s = new CompoundStatement(loc, a);
3570 sc->fes->gotos.push(s); // 'look at this later' list
3571 return s;
3573 if (label->statement && label->statement->tf != sc->tf)
3574 error("cannot goto in or out of finally block");
3575 return this;
3578 int GotoStatement::fallOffEnd()
3580 return FALSE;
3583 void GotoStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
3585 buf->writestring("goto ");
3586 buf->writestring(ident->toChars());
3587 buf->writebyte(';');
3588 buf->writenl();
3591 /******************************** LabelStatement ***************************/
3593 LabelStatement::LabelStatement(Loc loc, Identifier *ident, Statement *statement)
3594 : Statement(loc)
3596 this->ident = ident;
3597 this->statement = statement;
3598 this->tf = NULL;
3599 this->lblock = NULL;
3600 this->isReturnLabel = 0;
3603 Statement *LabelStatement::syntaxCopy()
3605 LabelStatement *s = new LabelStatement(loc, ident, statement->syntaxCopy());
3606 return s;
3609 Statement *LabelStatement::semantic(Scope *sc)
3610 { LabelDsymbol *ls;
3611 FuncDeclaration *fd = sc->parent->isFuncDeclaration();
3613 //printf("LabelStatement::semantic()\n");
3614 ls = fd->searchLabel(ident);
3615 if (ls->statement)
3616 error("Label '%s' already defined", ls->toChars());
3617 else
3618 ls->statement = this;
3619 tf = sc->tf;
3620 sc = sc->push();
3621 sc->scopesym = sc->enclosing->scopesym;
3622 sc->callSuper |= CSXlabel;
3623 sc->slabel = this;
3624 if (statement)
3625 statement = statement->semantic(sc);
3626 sc->pop();
3627 return this;
3630 Statements *LabelStatement::flatten(Scope *sc)
3632 Statements *a = NULL;
3634 if (statement)
3636 a = statement->flatten(sc);
3637 if (a)
3639 if (!a->dim)
3641 a->push(new ExpStatement(loc, NULL));
3643 Statement *s = (Statement *)a->data[0];
3645 s = new LabelStatement(loc, ident, s);
3646 a->data[0] = s;
3650 return a;
3654 int LabelStatement::usesEH()
3656 return statement ? statement->usesEH() : FALSE;
3659 int LabelStatement::fallOffEnd()
3661 return statement ? statement->fallOffEnd() : TRUE;
3664 int LabelStatement::comeFrom()
3666 //printf("LabelStatement::comeFrom()\n");
3667 return TRUE;
3670 void LabelStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
3672 buf->writestring(ident->toChars());
3673 buf->writebyte(':');
3674 buf->writenl();
3675 if (statement)
3676 statement->toCBuffer(buf, hgs);
3680 /******************************** LabelDsymbol ***************************/
3682 LabelDsymbol::LabelDsymbol(Identifier *ident)
3683 : Dsymbol(ident)
3685 statement = NULL;
3686 #if IN_GCC
3687 asmLabelNum = 0;
3688 #endif
3691 LabelDsymbol *LabelDsymbol::isLabel() // is this a LabelDsymbol()?
3693 return this;