2 // Compiler implementation of the D programming language
3 // Copyright (c) 1999-2008 by Digital Mars
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
23 #include "statement.h"
24 #include "expression.h"
27 #include "staticassert.h"
30 #include "declaration.h"
31 #include "aggregate.h"
37 /******************************** Statement ***************************/
39 Statement::Statement(Loc loc
)
43 // If this is an in{} contract scope statement (skip for determining
44 // inlineStatus of a function body for header content)
49 Statement
*Statement::syntaxCopy()
55 void Statement::print()
57 fprintf(stdmsg
, "%s\n", toChars());
61 char *Statement::toChars()
65 buf
= new OutBuffer();
67 return buf
->toChars();
70 void Statement::toCBuffer(OutBuffer
*buf
, HdrGenState
*hgs
)
72 buf
->printf("Statement::toCBuffer()");
76 Statement
*Statement::semantic(Scope
*sc
)
81 // Same as semantic(), but do create a new scope
83 Statement
*Statement::semanticScope(Scope
*sc
, Statement
*sbreak
, Statement
*scontinue
)
91 scd
->scontinue
= scontinue
;
97 void Statement::error(const char *format
, ...)
100 va_start(ap
, format
);
101 ::verror(loc
, format
, ap
);
105 int Statement::hasBreak()
107 //printf("Statement::hasBreak()\n");
111 int Statement::hasContinue()
116 // TRUE if statement uses exception handling
118 int Statement::usesEH()
123 /* Only valid after semantic analysis
125 int Statement::blockExit()
127 printf("Statement::blockExit(%p)\n", this);
128 printf("%s\n", toChars());
133 // TRUE if statement may fall off the end without a throw or return
135 int Statement::fallOffEnd()
140 // TRUE if statement 'comes from' somewhere else, like a goto
142 int Statement::comeFrom()
144 //printf("Statement::comeFrom()\n");
148 /****************************************
149 * If this statement has code that needs to run in a finally clause
150 * at the end of the current scope, return that code in the form of
153 * *sentry code executed upon entry to the scope
154 * *sexception code executed upon exit from the scope via exception
155 * *sfinally code executed in finally block
158 void Statement::scopeCode(Scope
*sc
, Statement
**sentry
, Statement
**sexception
, Statement
**sfinally
)
160 //printf("Statement::scopeCode()\n");
167 /*********************************
168 * Flatten out the scope by presenting the statement
169 * as an array of statements.
170 * Returns NULL if no flattening necessary.
173 Statements
*Statement::flatten(Scope
*sc
)
179 /******************************** ExpStatement ***************************/
181 ExpStatement::ExpStatement(Loc loc
, Expression
*exp
)
187 Statement
*ExpStatement::syntaxCopy()
189 Expression
*e
= exp
? exp
->syntaxCopy() : NULL
;
190 ExpStatement
*es
= new ExpStatement(loc
, e
);
194 void ExpStatement::toCBuffer(OutBuffer
*buf
, HdrGenState
*hgs
)
197 exp
->toCBuffer(buf
, hgs
);
199 if (!hgs
->FLinit
.init
)
203 Statement
*ExpStatement::semantic(Scope
*sc
)
207 //printf("ExpStatement::semantic() %s\n", exp->toChars());
208 exp
= exp
->semantic(sc
);
209 exp
= resolveProperties(sc
, exp
);
210 exp
->checkSideEffect(0);
211 exp
= exp
->optimize(0);
212 //exp = exp->optimize(isDeclarationStatement() ? WANTvalue : 0);
217 int ExpStatement::blockExit()
218 { int result
= BEfallthru
;
222 if (exp
->op
== TOKhalt
)
224 if (exp
->op
== TOKassert
)
225 { AssertExp
*a
= (AssertExp
*)exp
;
227 if (a
->e1
->isBool(FALSE
)) // if it's an assert(0)
236 int ExpStatement::fallOffEnd()
240 if (exp
->op
== TOKassert
)
241 { AssertExp
*a
= (AssertExp
*)exp
;
243 if (a
->e1
->isBool(FALSE
)) // if it's an assert(0)
246 else if (exp
->op
== TOKhalt
)
252 /******************************** CompileStatement ***************************/
254 CompileStatement::CompileStatement(Loc loc
, Expression
*exp
)
260 Statement
*CompileStatement::syntaxCopy()
262 Expression
*e
= exp
->syntaxCopy();
263 CompileStatement
*es
= new CompileStatement(loc
, e
);
267 void CompileStatement::toCBuffer(OutBuffer
*buf
, HdrGenState
*hgs
)
269 buf
->writestring("mixin(");
270 exp
->toCBuffer(buf
, hgs
);
271 buf
->writestring(");");
272 if (!hgs
->FLinit
.init
)
276 Statement
*CompileStatement::semantic(Scope
*sc
)
278 //printf("CompileStatement::semantic() %s\n", exp->toChars());
279 exp
= exp
->semantic(sc
);
280 exp
= resolveProperties(sc
, exp
);
281 exp
= exp
->optimize(WANTvalue
| WANTinterpret
);
282 if (exp
->op
!= TOKstring
)
283 { error("argument to mixin must be a string, not (%s)", exp
->toChars());
286 StringExp
*se
= (StringExp
*)exp
;
288 Parser
p(sc
->module
, (unsigned char *)se
->string
, se
->len
, 0);
292 Statements
*statements
= new Statements();
293 while (p
.token
.value
!= TOKeof
)
295 Statement
*s
= p
.parseStatement(PSsemi
| PScurlyscope
);
299 Statement
*s
= new CompoundStatement(loc
, statements
);
300 return s
->semantic(sc
);
304 /******************************** DeclarationStatement ***************************/
306 DeclarationStatement::DeclarationStatement(Loc loc
, Dsymbol
*declaration
)
307 : ExpStatement(loc
, new DeclarationExp(loc
, declaration
))
311 DeclarationStatement::DeclarationStatement(Loc loc
, Expression
*exp
)
312 : ExpStatement(loc
, exp
)
316 Statement
*DeclarationStatement::syntaxCopy()
318 DeclarationStatement
*ds
= new DeclarationStatement(loc
, exp
->syntaxCopy());
322 void DeclarationStatement::scopeCode(Scope
*sc
, Statement
**sentry
, Statement
**sexception
, Statement
**sfinally
)
324 //printf("DeclarationStatement::scopeCode()\n");
333 if (exp
->op
== TOKdeclaration
)
335 DeclarationExp
*de
= (DeclarationExp
*)(exp
);
336 VarDeclaration
*v
= de
->declaration
->isVarDeclaration();
340 e
= v
->callAutoDtor(sc
);
343 //printf("dtor is: "); e->print();
344 *sfinally
= new ExpStatement(loc
, e
);
351 void DeclarationStatement::toCBuffer(OutBuffer
*buf
, HdrGenState
*hgs
)
353 exp
->toCBuffer(buf
, hgs
);
357 /******************************** CompoundStatement ***************************/
359 CompoundStatement::CompoundStatement(Loc loc
, Statements
*s
)
365 CompoundStatement::CompoundStatement(Loc loc
, Statement
*s1
, Statement
*s2
)
368 statements
= new Statements();
369 statements
->reserve(2);
370 statements
->push(s1
);
371 statements
->push(s2
);
374 Statement
*CompoundStatement::syntaxCopy()
376 Statements
*a
= new Statements();
377 a
->setDim(statements
->dim
);
378 for (size_t i
= 0; i
< statements
->dim
; i
++)
379 { Statement
*s
= (Statement
*)statements
->data
[i
];
384 CompoundStatement
*cs
= new CompoundStatement(loc
, a
);
389 Statement
*CompoundStatement::semantic(Scope
*sc
)
392 //printf("CompoundStatement::semantic(this = %p, sc = %p)\n", this, sc);
394 for (size_t i
= 0; i
< statements
->dim
; )
396 s
= (Statement
*) statements
->data
[i
];
398 { Statements
*a
= s
->flatten(sc
);
402 statements
->remove(i
);
403 statements
->insert(i
, a
);
407 statements
->data
[i
] = s
;
411 Statement
*sexception
;
414 s
->scopeCode(sc
, &sentry
, &sexception
, &sfinally
);
417 sentry
= sentry
->semantic(sc
);
418 statements
->data
[i
] = sentry
;
422 if (i
+ 1 == statements
->dim
&& !sfinally
)
425 sexception
= sexception
->semantic(sc
);
427 statements
->push(sexception
);
429 // Assume sexception does not throw
430 statements
->push(sfinally
);
441 * { sexception; throw __o; }
444 Statements
*a
= new Statements();
446 for (int j
= i
+ 1; j
< statements
->dim
; j
++)
448 a
->push(statements
->data
[j
]);
450 body
= new CompoundStatement(0, a
);
451 body
= new ScopeStatement(0, body
);
453 Identifier
*id
= Lexer::uniqueId("__o");
455 Statement
*handler
= new ThrowStatement(0, new IdentifierExp(0, id
));
456 handler
= new CompoundStatement(0, sexception
, handler
);
458 Array
*catches
= new Array();
459 Catch
*ctch
= new Catch(0, NULL
, id
, handler
);
461 s
= new TryCatchStatement(0, body
, catches
);
464 s
= new TryFinallyStatement(0, s
, sfinally
);
466 statements
->setDim(i
+ 1);
473 if (0 && i
+ 1 == statements
->dim
)
475 statements
->push(sfinally
);
482 * s; try { s1; s2; } finally { sfinally; }
485 Statements
*a
= new Statements();
487 for (int j
= i
+ 1; j
< statements
->dim
; j
++)
489 a
->push(statements
->data
[j
]);
491 body
= new CompoundStatement(0, a
);
492 s
= new TryFinallyStatement(0, body
, sfinally
);
494 statements
->setDim(i
+ 1);
503 if (statements
->dim
== 1)
508 Statements
*CompoundStatement::flatten(Scope
*sc
)
513 ReturnStatement
*CompoundStatement::isReturnStatement()
515 ReturnStatement
*rs
= NULL
;
517 for (i
= 0; i
< statements
->dim
; i
++)
520 s
= (Statement
*) statements
->data
[i
];
523 rs
= s
->isReturnStatement();
531 void CompoundStatement::toCBuffer(OutBuffer
*buf
, HdrGenState
*hgs
)
534 for (i
= 0; i
< statements
->dim
; i
++)
537 s
= (Statement
*) statements
->data
[i
];
539 s
->toCBuffer(buf
, hgs
);
543 int CompoundStatement::usesEH()
545 for (int i
= 0; i
< statements
->dim
; i
++)
548 s
= (Statement
*) statements
->data
[i
];
549 if (s
&& s
->usesEH())
555 int CompoundStatement::blockExit()
557 //printf("CompoundStatement::blockExit(%p) %d\n", this, statements->dim);
558 int result
= BEfallthru
;
559 for (size_t i
= 0; i
< statements
->dim
; i
++)
560 { Statement
*s
= (Statement
*) statements
->data
[i
];
563 //printf("result = x%x\n", result);
564 //printf("%s\n", s->toChars());
565 if (!(result
& BEfallthru
) && !s
->comeFrom())
567 if (global
.params
.warnings
)
568 { fprintf(stdmsg
, "warning - ");
569 s
->error("statement is not reachable");
573 result
&= ~BEfallthru
;
574 result
|= s
->blockExit();
580 int CompoundStatement::fallOffEnd()
581 { int falloff
= TRUE
;
583 //printf("CompoundStatement::fallOffEnd()\n");
584 for (int i
= 0; i
< statements
->dim
; i
++)
585 { Statement
*s
= (Statement
*)statements
->data
[i
];
591 if (!falloff
&& global
.params
.warnings
&& !s
->comeFrom())
593 fprintf(stdmsg
, "warning - ");
594 s
->error("statement is not reachable");
597 falloff
= s
->fallOffEnd();
602 int CompoundStatement::comeFrom()
603 { int comefrom
= FALSE
;
605 //printf("CompoundStatement::comeFrom()\n");
606 for (int i
= 0; i
< statements
->dim
; i
++)
607 { Statement
*s
= (Statement
*)statements
->data
[i
];
612 comefrom
|= s
->comeFrom();
618 /**************************** UnrolledLoopStatement ***************************/
620 UnrolledLoopStatement::UnrolledLoopStatement(Loc loc
, Statements
*s
)
626 Statement
*UnrolledLoopStatement::syntaxCopy()
628 Statements
*a
= new Statements();
629 a
->setDim(statements
->dim
);
630 for (size_t i
= 0; i
< statements
->dim
; i
++)
631 { Statement
*s
= (Statement
*)statements
->data
[i
];
636 UnrolledLoopStatement
*cs
= new UnrolledLoopStatement(loc
, a
);
641 Statement
*UnrolledLoopStatement::semantic(Scope
*sc
)
643 //printf("UnrolledLoopStatement::semantic(this = %p, sc = %p)\n", this, sc);
646 Scope
*scd
= sc
->push();
648 scd
->scontinue
= this;
650 for (size_t i
= 0; i
< statements
->dim
; i
++)
652 Statement
*s
= (Statement
*) statements
->data
[i
];
655 s
= s
->semantic(scd
);
656 statements
->data
[i
] = s
;
665 void UnrolledLoopStatement::toCBuffer(OutBuffer
*buf
, HdrGenState
*hgs
)
667 buf
->writestring("unrolled {");
670 for (size_t i
= 0; i
< statements
->dim
; i
++)
673 s
= (Statement
*) statements
->data
[i
];
675 s
->toCBuffer(buf
, hgs
);
682 int UnrolledLoopStatement::hasBreak()
687 int UnrolledLoopStatement::hasContinue()
692 int UnrolledLoopStatement::usesEH()
694 for (size_t i
= 0; i
< statements
->dim
; i
++)
695 { Statement
*s
= (Statement
*) statements
->data
[i
];
696 if (s
&& s
->usesEH())
702 int UnrolledLoopStatement::blockExit()
704 int result
= BEfallthru
;
705 for (size_t i
= 0; i
< statements
->dim
; i
++)
706 { Statement
*s
= (Statement
*) statements
->data
[i
];
709 int r
= s
->blockExit();
710 result
|= r
& ~(BEbreak
| BEcontinue
);
716 int UnrolledLoopStatement::fallOffEnd()
718 //printf("UnrolledLoopStatement::fallOffEnd()\n");
719 for (size_t i
= 0; i
< statements
->dim
; i
++)
720 { Statement
*s
= (Statement
*)statements
->data
[i
];
728 int UnrolledLoopStatement::comeFrom()
729 { int comefrom
= FALSE
;
731 //printf("UnrolledLoopStatement::comeFrom()\n");
732 for (size_t i
= 0; i
< statements
->dim
; i
++)
733 { Statement
*s
= (Statement
*)statements
->data
[i
];
738 comefrom
|= s
->comeFrom();
744 /******************************** ScopeStatement ***************************/
746 ScopeStatement::ScopeStatement(Loc loc
, Statement
*s
)
752 Statement
*ScopeStatement::syntaxCopy()
756 s
= statement
? statement
->syntaxCopy() : NULL
;
757 s
= new ScopeStatement(loc
, s
);
762 Statement
*ScopeStatement::semantic(Scope
*sc
)
765 //printf("ScopeStatement::semantic(sc = %p)\n", sc);
769 sym
= new ScopeDsymbol();
770 sym
->parent
= sc
->scopesym
;
773 a
= statement
->flatten(sc
);
776 statement
= new CompoundStatement(loc
, a
);
779 statement
= statement
->semantic(sc
);
783 Statement
*sexception
;
786 statement
->scopeCode(sc
, &sentry
, &sexception
, &sfinally
);
789 //printf("adding sfinally\n");
790 statement
= new CompoundStatement(loc
, statement
, sfinally
);
799 int ScopeStatement::hasBreak()
801 //printf("ScopeStatement::hasBreak() %s\n", toChars());
802 return statement
? statement
->hasBreak() : FALSE
;
805 int ScopeStatement::hasContinue()
807 return statement
? statement
->hasContinue() : FALSE
;
810 int ScopeStatement::usesEH()
812 return statement
? statement
->usesEH() : FALSE
;
815 int ScopeStatement::blockExit()
817 //printf("ScopeStatement::blockExit(%p)\n", statement);
818 return statement
? statement
->blockExit() : BEfallthru
;
821 int ScopeStatement::fallOffEnd()
823 return statement
? statement
->fallOffEnd() : TRUE
;
826 int ScopeStatement::comeFrom()
828 //printf("ScopeStatement::comeFrom()\n");
829 return statement
? statement
->comeFrom() : FALSE
;
832 void ScopeStatement::toCBuffer(OutBuffer
*buf
, HdrGenState
*hgs
)
838 statement
->toCBuffer(buf
, hgs
);
844 /******************************** WhileStatement ***************************/
846 WhileStatement::WhileStatement(Loc loc
, Expression
*c
, Statement
*b
)
853 Statement
*WhileStatement::syntaxCopy()
855 WhileStatement
*s
= new WhileStatement(loc
, condition
->syntaxCopy(), body
? body
->syntaxCopy() : NULL
);
860 Statement
*WhileStatement::semantic(Scope
*sc
)
863 if (condition
->op
== TOKmatch
)
865 /* Rewrite while (condition) body as:
869 * while ((_match = _match.opNext), _match);
872 Expression
*ew
= new IdentifierExp(0, Id::_match
);
873 ew
= new DotIdExp(0, ew
, Id::next
);
874 ew
= new AssignExp(0, new IdentifierExp(0, Id::_match
), ew
);
875 ////ew = new EqualExp(TOKnotequal, 0, ew, new NullExp(0));
876 Expression
*ev
= new IdentifierExp(0, Id::_match
);
877 //ev = new CastExp(0, ev, Type::tvoidptr);
878 ew
= new CommaExp(0, ew
, ev
);
879 Statement
*sw
= new DoStatement(loc
, body
, ew
);
880 Statement
*si
= new IfStatement(loc
, condition
, sw
, NULL
);
881 return si
->semantic(sc
);
885 condition
= condition
->semantic(sc
);
886 condition
= resolveProperties(sc
, condition
);
887 condition
= condition
->optimize(WANTvalue
);
888 condition
= condition
->checkToBoolean();
892 Scope
*scd
= sc
->push();
894 scd
->scontinue
= this;
896 body
= body
->semantic(scd
);
904 int WhileStatement::hasBreak()
909 int WhileStatement::hasContinue()
914 int WhileStatement::usesEH()
916 return body
? body
->usesEH() : 0;
919 int WhileStatement::blockExit()
921 //printf("WhileStatement::blockExit(%p)\n", this);
924 if (condition
->canThrow())
927 { result
|= body
->blockExit();
928 if (result
& BEbreak
)
929 result
|= BEfallthru
;
930 result
&= ~(BEbreak
| BEcontinue
);
933 result
|= BEfallthru
;
937 int WhileStatement::fallOffEnd()
944 int WhileStatement::comeFrom()
947 return body
->comeFrom();
951 void WhileStatement::toCBuffer(OutBuffer
*buf
, HdrGenState
*hgs
)
953 buf
->writestring("while (");
954 condition
->toCBuffer(buf
, hgs
);
958 body
->toCBuffer(buf
, hgs
);
961 /******************************** DoStatement ***************************/
963 DoStatement::DoStatement(Loc loc
, Statement
*b
, Expression
*c
)
970 Statement
*DoStatement::syntaxCopy()
972 DoStatement
*s
= new DoStatement(loc
, body
? body
->syntaxCopy() : NULL
, condition
->syntaxCopy());
977 Statement
*DoStatement::semantic(Scope
*sc
)
981 body
= body
->semanticScope(sc
, this, this);
983 condition
= condition
->semantic(sc
);
984 condition
= resolveProperties(sc
, condition
);
985 condition
= condition
->optimize(WANTvalue
);
987 condition
= condition
->checkToBoolean();
992 int DoStatement::hasBreak()
997 int DoStatement::hasContinue()
1002 int DoStatement::usesEH()
1004 return body
? body
->usesEH() : 0;
1007 int DoStatement::blockExit()
1011 { result
= body
->blockExit();
1012 if (result
& BEbreak
)
1014 if (result
== BEbreak
)
1016 result
|= BEfallthru
;
1018 if (result
& BEcontinue
)
1019 result
|= BEfallthru
;
1020 result
&= ~(BEbreak
| BEcontinue
);
1023 result
= BEfallthru
;
1024 if (result
& BEfallthru
&& condition
->canThrow())
1029 int DoStatement::fallOffEnd()
1036 int DoStatement::comeFrom()
1039 return body
->comeFrom();
1043 void DoStatement::toCBuffer(OutBuffer
*buf
, HdrGenState
*hgs
)
1045 buf
->writestring("do");
1048 body
->toCBuffer(buf
, hgs
);
1049 buf
->writestring("while (");
1050 condition
->toCBuffer(buf
, hgs
);
1051 buf
->writebyte(')');
1054 /******************************** ForStatement ***************************/
1056 ForStatement::ForStatement(Loc loc
, Statement
*init
, Expression
*condition
, Expression
*increment
, Statement
*body
)
1060 this->condition
= condition
;
1061 this->increment
= increment
;
1065 Statement
*ForStatement::syntaxCopy()
1067 Statement
*i
= NULL
;
1069 i
= init
->syntaxCopy();
1070 Expression
*c
= NULL
;
1072 c
= condition
->syntaxCopy();
1073 Expression
*inc
= NULL
;
1075 inc
= increment
->syntaxCopy();
1076 ForStatement
*s
= new ForStatement(loc
, i
, c
, inc
, body
->syntaxCopy());
1080 Statement
*ForStatement::semantic(Scope
*sc
)
1082 ScopeDsymbol
*sym
= new ScopeDsymbol();
1083 sym
->parent
= sc
->scopesym
;
1086 init
= init
->semantic(sc
);
1090 condition
= condition
->semantic(sc
);
1091 condition
= resolveProperties(sc
, condition
);
1092 condition
= condition
->optimize(WANTvalue
);
1093 condition
= condition
->checkToBoolean();
1096 increment
= increment
->semantic(sc
);
1099 sc
->scontinue
= this;
1100 body
= body
->semantic(sc
);
1107 void ForStatement::scopeCode(Scope
*sc
, Statement
**sentry
, Statement
**sexception
, Statement
**sfinally
)
1109 //printf("ForStatement::scopeCode()\n");
1112 init
->scopeCode(sc
, sentry
, sexception
, sfinally
);
1114 Statement::scopeCode(sc
, sentry
, sexception
, sfinally
);
1117 int ForStatement::hasBreak()
1119 //printf("ForStatement::hasBreak()\n");
1123 int ForStatement::hasContinue()
1128 int ForStatement::usesEH()
1130 return (init
&& init
->usesEH()) || body
->usesEH();
1133 int ForStatement::blockExit()
1134 { int result
= BEfallthru
;
1137 { result
= init
->blockExit();
1138 if (!(result
& BEfallthru
))
1142 { if (condition
->canThrow())
1146 result
&= ~BEfallthru
; // the body must do the exiting
1148 { int r
= body
->blockExit();
1150 result
|= BEfallthru
;
1151 result
|= r
& ~(BEbreak
| BEcontinue
);
1153 if (increment
&& increment
->canThrow())
1158 int ForStatement::fallOffEnd()
1165 int ForStatement::comeFrom()
1167 //printf("ForStatement::comeFrom()\n");
1169 { int result
= body
->comeFrom();
1170 //printf("result = %d\n", result);
1176 void ForStatement::toCBuffer(OutBuffer
*buf
, HdrGenState
*hgs
)
1178 buf
->writestring("for (");
1182 hgs
->FLinit
.decl
= 0;
1183 init
->toCBuffer(buf
, hgs
);
1184 if (hgs
->FLinit
.decl
> 0)
1185 buf
->writebyte(';');
1186 hgs
->FLinit
.decl
= 0;
1190 buf
->writebyte(';');
1192 { buf
->writebyte(' ');
1193 condition
->toCBuffer(buf
, hgs
);
1195 buf
->writebyte(';');
1197 { buf
->writebyte(' ');
1198 increment
->toCBuffer(buf
, hgs
);
1200 buf
->writebyte(')');
1202 buf
->writebyte('{');
1204 body
->toCBuffer(buf
, hgs
);
1205 buf
->writebyte('}');
1209 /******************************** ForeachStatement ***************************/
1211 ForeachStatement::ForeachStatement(Loc loc
, enum TOK op
, Arguments
*arguments
,
1212 Expression
*aggr
, Statement
*body
)
1216 this->arguments
= arguments
;
1226 Statement
*ForeachStatement::syntaxCopy()
1228 Arguments
*args
= Argument::arraySyntaxCopy(arguments
);
1229 Expression
*exp
= aggr
->syntaxCopy();
1230 ForeachStatement
*s
= new ForeachStatement(loc
, op
, args
, exp
,
1231 body
? body
->syntaxCopy() : NULL
);
1235 Statement
*ForeachStatement::semantic(Scope
*sc
)
1237 //printf("ForeachStatement::semantic() %p\n", this);
1239 Statement
*s
= this;
1240 int dim
= arguments
->dim
;
1242 TypeAArray
*taa
= NULL
;
1249 func
= func
->fes
->func
;
1251 aggr
= aggr
->semantic(sc
);
1252 aggr
= resolveProperties(sc
, aggr
);
1253 aggr
= aggr
->optimize(WANTvalue
);
1256 error("invalid foreach aggregate %s", aggr
->toChars());
1260 inferApplyArgTypes(op
, arguments
, aggr
);
1262 /* Check for inference errors
1264 if (dim
!= arguments
->dim
)
1266 //printf("dim = %d, arguments->dim = %d\n", dim, arguments->dim);
1267 error("cannot uniquely infer foreach argument types");
1271 Type
*tab
= aggr
->type
->toBasetype();
1273 if (tab
->ty
== Ttuple
) // don't generate new scope for tuple loops
1275 if (dim
< 1 || dim
> 2)
1277 error("only one (value) or two (key,value) arguments for tuple foreach");
1281 TypeTuple
*tuple
= (TypeTuple
*)tab
;
1282 Statements
*statements
= new Statements();
1283 //printf("aggr: op = %d, %s\n", aggr->op, aggr->toChars());
1285 TupleExp
*te
= NULL
;
1286 if (aggr
->op
== TOKtuple
) // expression tuple
1287 { te
= (TupleExp
*)aggr
;
1290 else if (aggr
->op
== TOKtype
) // type tuple
1292 n
= Argument::dim(tuple
->arguments
);
1296 for (size_t j
= 0; j
< n
; j
++)
1297 { size_t k
= (op
== TOKforeach
) ? j
: n
- 1 - j
;
1301 e
= (Expression
*)te
->exps
->data
[k
];
1303 t
= Argument::getNth(tuple
->arguments
, k
)->type
;
1304 Argument
*arg
= (Argument
*)arguments
->data
[0];
1305 Statements
*st
= new Statements();
1309 if (arg
->storageClass
& (STCout
| STCref
| STClazy
))
1310 error("no storage class for key %s", arg
->ident
->toChars());
1311 TY keyty
= arg
->type
->ty
;
1312 if ((keyty
!= Tint32
&& keyty
!= Tuns32
) &&
1313 (! global
.params
.isX86_64
||
1314 (keyty
!= Tint64
&& keyty
!= Tuns64
))
1317 error("foreach: key type must be int or uint, not %s", arg
->type
->toChars());
1319 Initializer
*ie
= new ExpInitializer(0, new IntegerExp(k
));
1320 VarDeclaration
*var
= new VarDeclaration(loc
, arg
->type
, arg
->ident
, ie
);
1321 var
->storage_class
|= STCmanifest
;
1322 DeclarationExp
*de
= new DeclarationExp(loc
, var
);
1323 st
->push(new ExpStatement(loc
, de
));
1324 arg
= (Argument
*)arguments
->data
[1]; // value
1327 if (arg
->storageClass
& (STCout
| STCref
| STClazy
))
1328 error("no storage class for value %s", arg
->ident
->toChars());
1331 { Type
*tb
= e
->type
->toBasetype();
1332 if ((tb
->ty
== Tfunction
|| tb
->ty
== Tsarray
) && e
->op
== TOKvar
)
1333 { VarExp
*ve
= (VarExp
*)e
;
1334 var
= new AliasDeclaration(loc
, arg
->ident
, ve
->var
);
1338 arg
->type
= e
->type
;
1339 Initializer
*ie
= new ExpInitializer(0, e
);
1340 VarDeclaration
*v
= new VarDeclaration(loc
, arg
->type
, arg
->ident
, ie
);
1342 v
->storage_class
|= STCconst
;
1348 var
= new AliasDeclaration(loc
, arg
->ident
, t
);
1350 DeclarationExp
*de
= new DeclarationExp(loc
, var
);
1351 st
->push(new ExpStatement(loc
, de
));
1353 st
->push(body
->syntaxCopy());
1354 s
= new CompoundStatement(loc
, st
);
1355 s
= new ScopeStatement(loc
, s
);
1356 statements
->push(s
);
1359 s
= new UnrolledLoopStatement(loc
, statements
);
1360 s
= s
->semantic(sc
);
1364 for (i
= 0; i
< dim
; i
++)
1365 { Argument
*arg
= (Argument
*)arguments
->data
[i
];
1368 error("cannot infer type for %s", arg
->ident
->toChars());
1373 sym
= new ScopeDsymbol();
1374 sym
->parent
= sc
->scopesym
;
1383 if (dim
< 1 || dim
> 2)
1385 error("only one or two arguments for array foreach");
1389 /* Look for special case of parsing char types out of char type
1392 tn
= tab
->nextOf()->toBasetype();
1393 if (tn
->ty
== Tchar
|| tn
->ty
== Twchar
|| tn
->ty
== Tdchar
)
1396 i
= (dim
== 1) ? 0 : 1; // index of value
1397 arg
= (Argument
*)arguments
->data
[i
];
1398 arg
->type
= arg
->type
->semantic(loc
, sc
);
1399 tnv
= arg
->type
->toBasetype();
1400 if (tnv
->ty
!= tn
->ty
&&
1401 (tnv
->ty
== Tchar
|| tnv
->ty
== Twchar
|| tnv
->ty
== Tdchar
))
1403 if (arg
->storageClass
& STCref
)
1404 error("foreach: value of UTF conversion cannot be ref");
1406 { arg
= (Argument
*)arguments
->data
[0];
1407 if (arg
->storageClass
& STCref
)
1408 error("foreach: key cannot be ref");
1414 for (i
= 0; i
< dim
; i
++)
1416 Argument
*arg
= (Argument
*)arguments
->data
[i
];
1417 VarDeclaration
*var
;
1419 var
= new VarDeclaration(loc
, arg
->type
, arg
->ident
, NULL
);
1420 var
->storage_class
|= STCforeach
;
1421 var
->storage_class
|= arg
->storageClass
& (STCin
| STCout
| STCref
| STCconst
| STCinvariant
);
1422 if (dim
== 2 && i
== 0)
1424 //var->storage_class |= STCfinal;
1427 { //if (!(arg->storageClass & STCref))
1428 //var->storage_class |= STCfinal;
1432 DeclarationExp
*de
= new DeclarationExp(loc
, var
);
1436 if (!sc
->insert(var
))
1437 error("%s already defined", var
->ident
->toChars());
1442 sc
->scontinue
= this;
1443 body
= body
->semantic(sc
);
1445 if (tab
->nextOf()->implicitConvTo(value
->type
) < MATCHconst
)
1447 if (aggr
->op
== TOKstring
)
1448 aggr
= aggr
->implicitCastTo(sc
, value
->type
->arrayOf());
1450 error("foreach: %s is not an array of %s",
1451 tab
->toChars(), value
->type
->toChars());
1455 ((key
->type
->ty
!= Tint32
&& key
->type
->ty
!= Tuns32
) &&
1456 (! global
.params
.isX86_64
||
1457 (key
->type
->ty
!= Tint64
&& key
->type
->ty
!= Tuns64
))
1461 error("foreach: key type must be int or uint, not %s", key
->type
->toChars());
1464 if (key
&& key
->storage_class
& (STCout
| STCref
))
1465 error("foreach: key cannot be out or ref");
1469 taa
= (TypeAArray
*)tab
;
1470 if (dim
< 1 || dim
> 2)
1472 error("only one or two arguments for associative array foreach");
1475 if (op
== TOKforeach_reverse
)
1477 error("no reverse iteration on associative arrays");
1485 { FuncDeclaration
*fdapply
;
1489 FuncLiteralDeclaration
*fld
;
1496 tret
= func
->type
->nextOf();
1498 // Need a variable to hold value from any return statements in body.
1499 if (!sc
->func
->vresult
&& tret
&& tret
!= Type::tvoid
)
1500 { VarDeclaration
*v
;
1502 v
= new VarDeclaration(loc
, tret
, Id::result
, NULL
);
1507 v
->parent
= sc
->func
;
1508 sc
->func
->vresult
= v
;
1511 /* Turn body into the function literal:
1512 * int delegate(ref T arg) { body }
1514 args
= new Arguments();
1515 for (i
= 0; i
< dim
; i
++)
1516 { Argument
*arg
= (Argument
*)arguments
->data
[i
];
1518 arg
->type
= arg
->type
->semantic(loc
, sc
);
1519 if (arg
->storageClass
& STCref
)
1522 { // Make a copy of the ref argument so it isn't
1527 id
= Lexer::uniqueId("__applyArg", i
);
1529 ie
= new ExpInitializer(0, new IdentifierExp(0, id
));
1530 v
= new VarDeclaration(0, arg
->type
, arg
->ident
, ie
);
1531 s
= new DeclarationStatement(0, v
);
1532 body
= new CompoundStatement(loc
, s
, body
);
1534 a
= new Argument(STCref
, arg
->type
, id
, NULL
);
1537 t
= new TypeFunction(args
, Type::tint32
, 0, LINKd
);
1538 fld
= new FuncLiteralDeclaration(loc
, 0, t
, TOKdelegate
, this);
1540 flde
= new FuncExp(loc
, fld
);
1541 flde
= flde
->semantic(sc
);
1542 fld
->tookAddressOf
= 0;
1544 // Resolve any forward referenced goto's
1545 for (int i
= 0; i
< gotos
.dim
; i
++)
1546 { CompoundStatement
*cs
= (CompoundStatement
*)gotos
.data
[i
];
1547 GotoStatement
*gs
= (GotoStatement
*)cs
->statements
->data
[0];
1549 if (!gs
->label
->statement
)
1550 { // 'Promote' it to this scope, and replace with a return
1552 s
= new ReturnStatement(0, new IntegerExp(cases
.dim
+ 1));
1553 cs
->statements
->data
[0] = (void *)s
;
1557 if (tab
->ty
== Taarray
)
1560 Argument
*arg
= (Argument
*)arguments
->data
[0];
1563 if (arg
->storageClass
& STCref
)
1564 error("foreach: index cannot be ref");
1565 if (!arg
->type
->equals(taa
->index
))
1566 error("foreach: index must be type %s, not %s", taa
->index
->toChars(), arg
->type
->toChars());
1567 arg
= (Argument
*)arguments
->data
[1];
1569 if (!arg
->type
->equals(taa
->nextOf()))
1570 error("foreach: value must be type %s, not %s", taa
->nextOf()->toChars(), arg
->type
->toChars());
1573 * _aaApply(aggr, keysize, flde)
1576 fdapply
= FuncDeclaration::genCfunc(Type::tint32
, "_aaApply2",
1577 Type::tvoid
->arrayOf(), Type::tsize_t
, flde
->type
); // flde->type is not generic
1579 fdapply
= FuncDeclaration::genCfunc(Type::tint32
, "_aaApply",
1580 Type::tvoid
->arrayOf(), Type::tsize_t
, flde
->type
); // flde->type is not generic);
1581 ec
= new VarExp(0, fdapply
);
1582 Expressions
*exps
= new Expressions();
1584 size_t keysize
= taa
->index
->size();
1585 keysize
= (keysize
+ (PTRSIZE
-1)) & ~(PTRSIZE
-1);
1586 exps
->push(new IntegerExp(0, keysize
, Type::tsize_t
));
1588 e
= new CallExp(loc
, ec
, exps
);
1589 e
->type
= Type::tint32
; // don't run semantic() on e
1591 else if (tab
->ty
== Tarray
|| tab
->ty
== Tsarray
)
1594 * _aApply(aggr, flde)
1596 static char fntab
[9][3] =
1601 char fdname
[7+1+2+ sizeof(dim
)*3 + 1];
1606 case Tchar
: flag
= 0; break;
1607 case Twchar
: flag
= 3; break;
1608 case Tdchar
: flag
= 6; break;
1613 case Tchar
: flag
+= 0; break;
1614 case Twchar
: flag
+= 1; break;
1615 case Tdchar
: flag
+= 2; break;
1618 const char *r
= (op
== TOKforeach_reverse
) ? "R" : "";
1619 int j
= sprintf(fdname
, "_aApply%s%.*s%d", r
, 2, fntab
[flag
], dim
);
1620 assert(j
< sizeof(fdname
));
1621 fdapply
= FuncDeclaration::genCfunc(Type::tint32
, fdname
,
1622 Type::tvoid
->arrayOf(), flde
->type
); // flde->type is not generic
1624 ec
= new VarExp(0, fdapply
);
1625 Expressions
*exps
= new Expressions();
1626 if (tab
->ty
== Tsarray
)
1627 aggr
= aggr
->castTo(sc
, tn
->arrayOf());
1630 e
= new CallExp(loc
, ec
, exps
);
1631 e
->type
= Type::tint32
; // don't run semantic() on e
1633 else if (tab
->ty
== Tdelegate
)
1638 Expressions
*exps
= new Expressions();
1640 e
= new CallExp(loc
, aggr
, exps
);
1641 e
= e
->semantic(sc
);
1642 if (e
->type
!= Type::tint32
)
1643 error("opApply() function for %s must return an int", tab
->toChars());
1650 ec
= new DotIdExp(loc
, aggr
,
1651 (op
== TOKforeach_reverse
) ? Id::applyReverse
1653 Expressions
*exps
= new Expressions();
1655 e
= new CallExp(loc
, ec
, exps
);
1656 e
= e
->semantic(sc
);
1657 if (e
->type
!= Type::tint32
)
1658 error("opApply() function for %s must return an int", tab
->toChars());
1662 // Easy case, a clean exit from the loop
1663 s
= new ExpStatement(loc
, e
);
1665 { // Construct a switch statement around the return value
1666 // of the apply function.
1667 Statements
*a
= new Statements();
1669 // default: break; takes care of cases 0 and 1
1670 s
= new BreakStatement(0, NULL
);
1671 s
= new DefaultStatement(0, s
);
1675 for (int i
= 0; i
< cases
.dim
; i
++)
1677 s
= (Statement
*)cases
.data
[i
];
1678 s
= new CaseStatement(0, new IntegerExp(i
+ 2), s
);
1682 s
= new CompoundStatement(loc
, a
);
1683 s
= new SwitchStatement(loc
, e
, s
);
1684 s
= s
->semantic(sc
);
1690 error("foreach: %s is not an aggregate type", aggr
->type
->toChars());
1698 int ForeachStatement::hasBreak()
1703 int ForeachStatement::hasContinue()
1708 int ForeachStatement::usesEH()
1710 return body
->usesEH();
1713 int ForeachStatement::blockExit()
1714 { int result
= BEfallthru
;
1716 if (aggr
->canThrow())
1721 result
|= body
->blockExit() & ~(BEbreak
| BEcontinue
);
1726 int ForeachStatement::fallOffEnd()
1733 int ForeachStatement::comeFrom()
1736 return body
->comeFrom();
1740 void ForeachStatement::toCBuffer(OutBuffer
*buf
, HdrGenState
*hgs
)
1742 buf
->writestring(Token::toChars(op
));
1743 buf
->writestring(" (");
1744 for (int i
= 0; i
< arguments
->dim
; i
++)
1746 Argument
*a
= (Argument
*)arguments
->data
[i
];
1748 buf
->writestring(", ");
1749 if (a
->storageClass
& STCref
)
1750 buf
->writestring((global
.params
.Dversion
== 1)
1751 ? (char*)"inout " : (char*)"ref ");
1753 a
->type
->toCBuffer(buf
, a
->ident
, hgs
);
1755 buf
->writestring(a
->ident
->toChars());
1757 buf
->writestring("; ");
1758 aggr
->toCBuffer(buf
, hgs
);
1759 buf
->writebyte(')');
1761 buf
->writebyte('{');
1764 body
->toCBuffer(buf
, hgs
);
1765 buf
->writebyte('}');
1769 /**************************** ForeachRangeStatement ***************************/
1771 ForeachRangeStatement::ForeachRangeStatement(Loc loc
, enum TOK op
, Argument
*arg
,
1772 Expression
*lwr
, Expression
*upr
, Statement
*body
)
1784 Statement
*ForeachRangeStatement::syntaxCopy()
1786 ForeachRangeStatement
*s
= new ForeachRangeStatement(loc
, op
,
1790 body
? body
->syntaxCopy() : NULL
);
1794 Statement
*ForeachRangeStatement::semantic(Scope
*sc
)
1796 //printf("ForeachRangeStatement::semantic() %p\n", this);
1798 Statement
*s
= this;
1800 lwr
= lwr
->semantic(sc
);
1801 lwr
= resolveProperties(sc
, lwr
);
1802 lwr
= lwr
->optimize(WANTvalue
);
1805 error("invalid range lower bound %s", lwr
->toChars());
1809 upr
= upr
->semantic(sc
);
1810 upr
= resolveProperties(sc
, upr
);
1811 upr
= upr
->optimize(WANTvalue
);
1814 error("invalid range upper bound %s", upr
->toChars());
1820 lwr
= lwr
->implicitCastTo(sc
, arg
->type
);
1821 upr
= upr
->implicitCastTo(sc
, arg
->type
);
1825 /* Must infer types from lwr and upr
1827 AddExp
ea(loc
, lwr
, upr
);
1829 arg
->type
= ea
.type
;
1833 if (!arg
->type
->isscalar())
1834 error("%s is not a scalar type", arg
->type
->toChars());
1836 sym
= new ScopeDsymbol();
1837 sym
->parent
= sc
->scopesym
;
1842 key
= new VarDeclaration(loc
, arg
->type
, arg
->ident
, NULL
);
1843 DeclarationExp
*de
= new DeclarationExp(loc
, key
);
1846 if (key
->storage_class
)
1847 error("foreach range: key cannot have storage class");
1850 sc
->scontinue
= this;
1851 body
= body
->semantic(sc
);
1858 int ForeachRangeStatement::hasBreak()
1863 int ForeachRangeStatement::hasContinue()
1868 int ForeachRangeStatement::usesEH()
1870 return body
->usesEH();
1873 int ForeachRangeStatement::blockExit()
1874 { int result
= BEfallthru
;
1876 if (lwr
&& lwr
->canThrow())
1878 else if (upr
&& upr
->canThrow())
1883 result
|= body
->blockExit() & ~(BEbreak
| BEcontinue
);
1888 int ForeachRangeStatement::fallOffEnd()
1895 int ForeachRangeStatement::comeFrom()
1898 return body
->comeFrom();
1902 void ForeachRangeStatement::toCBuffer(OutBuffer
*buf
, HdrGenState
*hgs
)
1904 buf
->writestring(Token::toChars(op
));
1905 buf
->writestring(" (");
1908 arg
->type
->toCBuffer(buf
, arg
->ident
, hgs
);
1910 buf
->writestring(arg
->ident
->toChars());
1912 buf
->writestring("; ");
1913 lwr
->toCBuffer(buf
, hgs
);
1914 buf
->writestring(" .. ");
1915 upr
->toCBuffer(buf
, hgs
);
1916 buf
->writebyte(')');
1918 buf
->writebyte('{');
1921 body
->toCBuffer(buf
, hgs
);
1922 buf
->writebyte('}');
1926 /******************************** IfStatement ***************************/
1928 IfStatement::IfStatement(Loc loc
, Argument
*arg
, Expression
*condition
, Statement
*ifbody
, Statement
*elsebody
)
1932 this->condition
= condition
;
1933 this->ifbody
= ifbody
;
1934 this->elsebody
= elsebody
;
1938 Statement
*IfStatement::syntaxCopy()
1940 Statement
*i
= NULL
;
1942 i
= ifbody
->syntaxCopy();
1944 Statement
*e
= NULL
;
1946 e
= elsebody
->syntaxCopy();
1948 Argument
*a
= arg
? arg
->syntaxCopy() : NULL
;
1949 IfStatement
*s
= new IfStatement(loc
, a
, condition
->syntaxCopy(), i
, e
);
1953 Statement
*IfStatement::semantic(Scope
*sc
)
1955 condition
= condition
->semantic(sc
);
1956 condition
= resolveProperties(sc
, condition
);
1957 condition
= condition
->checkToBoolean();
1959 // If we can short-circuit evaluate the if statement, don't do the
1960 // semantic analysis of the skipped code.
1961 // This feature allows a limited form of conditional compilation.
1962 condition
= condition
->optimize(WANTflags
);
1964 // Evaluate at runtime
1965 unsigned cs0
= sc
->callSuper
;
1970 { /* Declare arg, which we will set to be the
1971 * result of condition.
1973 ScopeDsymbol
*sym
= new ScopeDsymbol();
1974 sym
->parent
= sc
->scopesym
;
1975 scd
= sc
->push(sym
);
1977 Type
*t
= arg
->type
? arg
->type
: condition
->type
;
1978 match
= new VarDeclaration(loc
, t
, arg
->ident
, NULL
);
1980 match
->semantic(scd
);
1981 if (!scd
->insert(match
))
1983 match
->parent
= sc
->func
;
1988 VarExp
*v
= new VarExp(0, match
);
1989 condition
= new AssignExp(loc
, v
, condition
);
1990 condition
= condition
->semantic(scd
);
1994 ifbody
= ifbody
->semantic(scd
);
1997 cs1
= sc
->callSuper
;
1998 sc
->callSuper
= cs0
;
2000 elsebody
= elsebody
->semanticScope(sc
, NULL
, NULL
);
2001 sc
->mergeCallSuper(loc
, cs1
);
2006 int IfStatement::usesEH()
2008 return (ifbody
&& ifbody
->usesEH()) || (elsebody
&& elsebody
->usesEH());
2011 int IfStatement::blockExit()
2013 //printf("IfStatement::blockExit(%p)\n", this);
2015 int result
= BEnone
;
2016 if (condition
->canThrow())
2019 result
|= ifbody
->blockExit();
2021 result
|= BEfallthru
;
2023 result
|= elsebody
->blockExit();
2025 result
|= BEfallthru
;
2026 //printf("IfStatement::blockExit(%p) = x%x\n", this, result);
2030 int IfStatement::fallOffEnd()
2032 if (!ifbody
|| ifbody
->fallOffEnd() ||
2033 !elsebody
|| elsebody
->fallOffEnd())
2039 void IfStatement::toCBuffer(OutBuffer
*buf
, HdrGenState
*hgs
)
2041 buf
->writestring("if (");
2045 arg
->type
->toCBuffer(buf
, arg
->ident
, hgs
);
2047 buf
->writestring(arg
->ident
->toChars());
2048 buf
->writebyte(';');
2050 condition
->toCBuffer(buf
, hgs
);
2051 buf
->writebyte(')');
2053 ifbody
->toCBuffer(buf
, hgs
);
2055 { buf
->writestring("else");
2057 elsebody
->toCBuffer(buf
, hgs
);
2061 /******************************** ConditionalStatement ***************************/
2063 ConditionalStatement::ConditionalStatement(Loc loc
, Condition
*condition
, Statement
*ifbody
, Statement
*elsebody
)
2066 this->condition
= condition
;
2067 this->ifbody
= ifbody
;
2068 this->elsebody
= elsebody
;
2071 Statement
*ConditionalStatement::syntaxCopy()
2073 Statement
*e
= NULL
;
2075 e
= elsebody
->syntaxCopy();
2076 ConditionalStatement
*s
= new ConditionalStatement(loc
,
2077 condition
->syntaxCopy(), ifbody
->syntaxCopy(), e
);
2081 Statement
*ConditionalStatement::semantic(Scope
*sc
)
2083 //printf("ConditionalStatement::semantic()\n");
2085 // If we can short-circuit evaluate the if statement, don't do the
2086 // semantic analysis of the skipped code.
2087 // This feature allows a limited form of conditional compilation.
2088 if (condition
->include(sc
, NULL
))
2090 ifbody
= ifbody
->semantic(sc
);
2096 elsebody
= elsebody
->semantic(sc
);
2101 Statements
*ConditionalStatement::flatten(Scope
*sc
)
2105 if (condition
->include(sc
, NULL
))
2110 Statements
*a
= new Statements();
2115 int ConditionalStatement::usesEH()
2117 return (ifbody
&& ifbody
->usesEH()) || (elsebody
&& elsebody
->usesEH());
2120 void ConditionalStatement::toCBuffer(OutBuffer
*buf
, HdrGenState
*hgs
)
2122 condition
->toCBuffer(buf
, hgs
);
2125 ifbody
->toCBuffer(buf
, hgs
);
2128 buf
->writestring("else");
2130 elsebody
->toCBuffer(buf
, hgs
);
2136 /******************************** PragmaStatement ***************************/
2138 PragmaStatement::PragmaStatement(Loc loc
, Identifier
*ident
, Expressions
*args
, Statement
*body
)
2141 this->ident
= ident
;
2146 Statement
*PragmaStatement::syntaxCopy()
2148 Statement
*b
= NULL
;
2150 b
= body
->syntaxCopy();
2151 PragmaStatement
*s
= new PragmaStatement(loc
,
2152 ident
, Expression::arraySyntaxCopy(args
), b
);
2156 Statement
*PragmaStatement::semantic(Scope
*sc
)
2157 { // Should be merged with PragmaDeclaration
2158 //printf("PragmaStatement::semantic() %s\n", toChars());
2159 //printf("body = %p\n", body);
2160 if (ident
== Id::msg
)
2164 for (size_t i
= 0; i
< args
->dim
; i
++)
2166 Expression
*e
= (Expression
*)args
->data
[i
];
2168 e
= e
->semantic(sc
);
2169 e
= e
->optimize(WANTvalue
| WANTinterpret
);
2170 if (e
->op
== TOKstring
)
2172 StringExp
*se
= (StringExp
*)e
;
2173 fprintf(stdmsg
, "%.*s", (int)se
->len
, se
->string
);
2176 error("string expected for message, not '%s'", e
->toChars());
2178 fprintf(stdmsg
, "\n");
2181 else if (ident
== Id::lib
)
2183 if (!args
|| args
->dim
!= 1)
2184 error("string expected for library name");
2187 Expression
*e
= (Expression
*)args
->data
[0];
2189 e
= e
->semantic(sc
);
2190 e
= e
->optimize(WANTvalue
| WANTinterpret
);
2191 args
->data
[0] = (void *)e
;
2192 if (e
->op
!= TOKstring
)
2193 error("string expected for library name, not '%s'", e
->toChars());
2194 else if (global
.params
.verbose
)
2196 StringExp
*se
= (StringExp
*)e
;
2197 char *name
= (char *)mem
.malloc(se
->len
+ 1);
2198 memcpy(name
, se
->string
, se
->len
);
2200 printf("library %s\n", name
);
2205 else if (ident
== Id::startaddress
)
2207 if (!args
|| args
->dim
!= 1)
2208 error("function name expected for start address");
2211 Expression
*e
= (Expression
*)args
->data
[0];
2212 e
= e
->semantic(sc
);
2213 e
= e
->optimize(WANTvalue
| WANTinterpret
);
2214 args
->data
[0] = (void *)e
;
2215 Dsymbol
*sa
= getDsymbol(e
);
2216 if (!sa
|| !sa
->isFuncDeclaration())
2217 error("function name expected for start address, not '%s'", e
->toChars());
2220 body
= body
->semantic(sc
);
2226 error("unrecognized pragma(%s)", ident
->toChars());
2230 body
= body
->semantic(sc
);
2235 int PragmaStatement::usesEH()
2237 return body
&& body
->usesEH();
2240 int PragmaStatement::blockExit()
2242 int result
= BEfallthru
;
2243 #if 0 // currently, no code is generated for Pragma's, so it's just fallthru
2244 if (arrayExpressionCanThrow(args
))
2247 result
|= body
->blockExit();
2252 int PragmaStatement::fallOffEnd()
2255 return body
->fallOffEnd();
2259 void PragmaStatement::toCBuffer(OutBuffer
*buf
, HdrGenState
*hgs
)
2261 buf
->writestring("pragma (");
2262 buf
->writestring(ident
->toChars());
2263 if (args
&& args
->dim
)
2265 buf
->writestring(", ");
2266 argsToCBuffer(buf
, args
, hgs
);
2268 buf
->writeByte(')');
2272 buf
->writeByte('{');
2275 body
->toCBuffer(buf
, hgs
);
2277 buf
->writeByte('}');
2282 buf
->writeByte(';');
2288 /******************************** StaticAssertStatement ***************************/
2290 StaticAssertStatement::StaticAssertStatement(StaticAssert
*sa
)
2291 : Statement(sa
->loc
)
2296 Statement
*StaticAssertStatement::syntaxCopy()
2298 StaticAssertStatement
*s
= new StaticAssertStatement((StaticAssert
*)sa
->syntaxCopy(NULL
));
2302 Statement
*StaticAssertStatement::semantic(Scope
*sc
)
2308 void StaticAssertStatement::toCBuffer(OutBuffer
*buf
, HdrGenState
*hgs
)
2310 sa
->toCBuffer(buf
, hgs
);
2314 /******************************** SwitchStatement ***************************/
2316 SwitchStatement::SwitchStatement(Loc loc
, Expression
*c
, Statement
*b
)
2328 Statement
*SwitchStatement::syntaxCopy()
2330 SwitchStatement
*s
= new SwitchStatement(loc
,
2331 condition
->syntaxCopy(), body
->syntaxCopy());
2335 Statement
*SwitchStatement::semantic(Scope
*sc
)
2337 //printf("SwitchStatement::semantic(%p)\n", this);
2339 assert(!cases
); // ensure semantic() is only run once
2340 condition
= condition
->semantic(sc
);
2341 condition
= resolveProperties(sc
, condition
);
2342 if (condition
->type
->isString())
2344 // If it's not an array, cast it to one
2345 if (condition
->type
->ty
!= Tarray
)
2347 condition
= condition
->implicitCastTo(sc
, condition
->type
->nextOf()->arrayOf());
2349 condition
->type
= condition
->type
->constOf();
2352 { condition
= condition
->integralPromotions(sc
);
2353 condition
->checkIntegral();
2355 condition
= condition
->optimize(WANTvalue
);
2361 cases
= new Array();
2362 sc
->noctor
++; // BUG: should use Scope::mergeCallSuper() for each case instead
2363 body
= body
->semantic(sc
);
2366 // Resolve any goto case's with exp
2367 for (int i
= 0; i
< gotoCases
.dim
; i
++)
2369 GotoCaseStatement
*gcs
= (GotoCaseStatement
*)gotoCases
.data
[i
];
2373 gcs
->error("no case statement following goto case;");
2377 for (Scope
*scx
= sc
; scx
; scx
= scx
->enclosing
)
2381 for (int j
= 0; j
< scx
->sw
->cases
->dim
; j
++)
2383 CaseStatement
*cs
= (CaseStatement
*)scx
->sw
->cases
->data
[j
];
2385 if (cs
->exp
->equals(gcs
->exp
))
2392 gcs
->error("case %s not found", gcs
->exp
->toChars());
2398 if (!sc
->sw
->sdefault
)
2401 if (global
.params
.warnings
)
2402 { fprintf(stdmsg
, "warning - ");
2403 error("switch statement has no default");
2406 // Generate runtime error if the default is hit
2407 Statements
*a
= new Statements();
2408 CompoundStatement
*cs
;
2411 if (global
.params
.useSwitchError
)
2412 s
= new SwitchErrorStatement(loc
);
2414 { Expression
*e
= new HaltExp(loc
);
2415 s
= new ExpStatement(loc
, e
);
2420 a
->push(new BreakStatement(loc
, NULL
));
2421 sc
->sw
->sdefault
= new DefaultStatement(loc
, s
);
2422 a
->push(sc
->sw
->sdefault
);
2423 cs
= new CompoundStatement(loc
, a
);
2431 int SwitchStatement::hasBreak()
2436 int SwitchStatement::usesEH()
2438 return body
? body
->usesEH() : 0;
2441 int SwitchStatement::blockExit()
2442 { int result
= BEnone
;
2443 if (condition
->canThrow())
2447 { result
|= body
->blockExit();
2448 if (result
& BEbreak
)
2449 { result
|= BEfallthru
;
2454 result
|= BEfallthru
;
2459 int SwitchStatement::fallOffEnd()
2463 return TRUE
; // need to do this better
2466 void SwitchStatement::toCBuffer(OutBuffer
*buf
, HdrGenState
*hgs
)
2468 buf
->writestring("switch (");
2469 condition
->toCBuffer(buf
, hgs
);
2470 buf
->writebyte(')');
2474 if (!body
->isScopeStatement())
2475 { buf
->writebyte('{');
2477 body
->toCBuffer(buf
, hgs
);
2478 buf
->writebyte('}');
2483 body
->toCBuffer(buf
, hgs
);
2488 /******************************** CaseStatement ***************************/
2490 CaseStatement::CaseStatement(Loc loc
, Expression
*exp
, Statement
*s
)
2494 this->statement
= s
;
2499 Statement
*CaseStatement::syntaxCopy()
2501 CaseStatement
*s
= new CaseStatement(loc
, exp
->syntaxCopy(), statement
->syntaxCopy());
2505 Statement
*CaseStatement::semantic(Scope
*sc
)
2506 { SwitchStatement
*sw
= sc
->sw
;
2508 //printf("CaseStatement::semantic() %s\n", toChars());
2509 exp
= exp
->semantic(sc
);
2512 exp
= exp
->implicitCastTo(sc
, sw
->condition
->type
);
2513 exp
= exp
->optimize(WANTvalue
| WANTinterpret
);
2515 /* This is where variables are allowed as case expressions.
2517 if (exp
->op
== TOKvar
)
2518 { VarExp
*ve
= (VarExp
*)exp
;
2519 VarDeclaration
*v
= ve
->var
->isVarDeclaration();
2520 Type
*t
= exp
->type
->toBasetype();
2521 if (v
&& (t
->isintegral() || t
->ty
== Tclass
))
2522 { /* Flag that we need to do special code generation
2523 * for this, i.e. generate a sequence of if-then-else
2530 if (exp
->op
!= TOKstring
&& exp
->op
!= TOKint64
)
2532 error("case must be a string or an integral constant, not %s", exp
->toChars());
2533 exp
= new IntegerExp(0);
2537 for (int i
= 0; i
< sw
->cases
->dim
; i
++)
2539 CaseStatement
*cs
= (CaseStatement
*)sw
->cases
->data
[i
];
2541 //printf("comparing '%s' with '%s'\n", exp->toChars(), cs->exp->toChars());
2542 if (cs
->exp
->equals(exp
))
2543 { error("duplicate case %s in switch statement", exp
->toChars());
2548 sw
->cases
->push(this);
2550 // Resolve any goto case's with no exp to this case statement
2551 for (int i
= 0; i
< sw
->gotoCases
.dim
; i
++)
2553 GotoCaseStatement
*gcs
= (GotoCaseStatement
*)sw
->gotoCases
.data
[i
];
2558 sw
->gotoCases
.remove(i
); // remove from array
2562 if (sc
->sw
->tf
!= sc
->tf
)
2563 error("switch and case are in different finally blocks");
2566 error("case not in switch statement");
2567 statement
= statement
->semantic(sc
);
2571 int CaseStatement::compare(Object
*obj
)
2573 // Sort cases so we can do an efficient lookup
2574 CaseStatement
*cs2
= (CaseStatement
*)(obj
);
2576 return exp
->compare(cs2
->exp
);
2579 int CaseStatement::usesEH()
2581 return statement
->usesEH();
2584 int CaseStatement::blockExit()
2590 int CaseStatement::fallOffEnd()
2592 return statement
->fallOffEnd();
2595 int CaseStatement::comeFrom()
2600 void CaseStatement::toCBuffer(OutBuffer
*buf
, HdrGenState
*hgs
)
2602 buf
->writestring("case ");
2603 exp
->toCBuffer(buf
, hgs
);
2604 buf
->writebyte(':');
2606 statement
->toCBuffer(buf
, hgs
);
2609 /******************************** DefaultStatement ***************************/
2611 DefaultStatement::DefaultStatement(Loc loc
, Statement
*s
)
2614 this->statement
= s
;
2620 Statement
*DefaultStatement::syntaxCopy()
2622 DefaultStatement
*s
= new DefaultStatement(loc
, statement
->syntaxCopy());
2626 Statement
*DefaultStatement::semantic(Scope
*sc
)
2628 //printf("DefaultStatement::semantic()\n");
2631 if (sc
->sw
->sdefault
)
2633 error("switch statement already has a default");
2635 sc
->sw
->sdefault
= this;
2637 if (sc
->sw
->tf
!= sc
->tf
)
2638 error("switch and default are in different finally blocks");
2641 error("default not in switch statement");
2642 statement
= statement
->semantic(sc
);
2646 int DefaultStatement::usesEH()
2648 return statement
->usesEH();
2651 int DefaultStatement::blockExit()
2657 int DefaultStatement::fallOffEnd()
2659 return statement
->fallOffEnd();
2662 int DefaultStatement::comeFrom()
2667 void DefaultStatement::toCBuffer(OutBuffer
*buf
, HdrGenState
*hgs
)
2669 buf
->writestring("default:\n");
2670 statement
->toCBuffer(buf
, hgs
);
2673 /******************************** GotoDefaultStatement ***************************/
2675 GotoDefaultStatement::GotoDefaultStatement(Loc loc
)
2681 Statement
*GotoDefaultStatement::syntaxCopy()
2683 GotoDefaultStatement
*s
= new GotoDefaultStatement(loc
);
2687 Statement
*GotoDefaultStatement::semantic(Scope
*sc
)
2691 error("goto default not in switch statement");
2695 int GotoDefaultStatement::blockExit()
2700 int GotoDefaultStatement::fallOffEnd()
2705 void GotoDefaultStatement::toCBuffer(OutBuffer
*buf
, HdrGenState
*hgs
)
2707 buf
->writestring("goto default;\n");
2710 /******************************** GotoCaseStatement ***************************/
2712 GotoCaseStatement::GotoCaseStatement(Loc loc
, Expression
*exp
)
2719 Statement
*GotoCaseStatement::syntaxCopy()
2721 Expression
*e
= exp
? exp
->syntaxCopy() : NULL
;
2722 GotoCaseStatement
*s
= new GotoCaseStatement(loc
, e
);
2726 Statement
*GotoCaseStatement::semantic(Scope
*sc
)
2729 exp
= exp
->semantic(sc
);
2732 error("goto case not in switch statement");
2735 sc
->sw
->gotoCases
.push(this);
2738 exp
= exp
->implicitCastTo(sc
, sc
->sw
->condition
->type
);
2739 exp
= exp
->optimize(WANTvalue
);
2745 int GotoCaseStatement::blockExit()
2750 int GotoCaseStatement::fallOffEnd()
2755 void GotoCaseStatement::toCBuffer(OutBuffer
*buf
, HdrGenState
*hgs
)
2757 buf
->writestring("goto case");
2759 { buf
->writebyte(' ');
2760 exp
->toCBuffer(buf
, hgs
);
2762 buf
->writebyte(';');
2766 /******************************** SwitchErrorStatement ***************************/
2768 SwitchErrorStatement::SwitchErrorStatement(Loc loc
)
2773 int SwitchErrorStatement::blockExit()
2778 int SwitchErrorStatement::fallOffEnd()
2783 void SwitchErrorStatement::toCBuffer(OutBuffer
*buf
, HdrGenState
*hgs
)
2785 buf
->writestring("SwitchErrorStatement::toCBuffer()");
2789 /******************************** ReturnStatement ***************************/
2791 ReturnStatement::ReturnStatement(Loc loc
, Expression
*exp
)
2797 Statement
*ReturnStatement::syntaxCopy()
2799 Expression
*e
= NULL
;
2801 e
= exp
->syntaxCopy();
2802 ReturnStatement
*s
= new ReturnStatement(loc
, e
);
2806 Statement
*ReturnStatement::semantic(Scope
*sc
)
2808 //printf("ReturnStatement::semantic() %s\n", toChars());
2810 FuncDeclaration
*fd
= sc
->parent
->isFuncDeclaration();
2816 // Find scope of function foreach is in
2817 for (; 1; scx
= scx
->enclosing
)
2820 if (scx
->func
!= fd
)
2821 { fd
= scx
->func
; // fd is now function enclosing foreach
2827 Type
*tret
= fd
->type
->nextOf();
2829 tret
= fd
->tintro
->nextOf();
2833 tbret
= tret
->toBasetype();
2835 // main() returns 0, even if it returns void
2836 if (!exp
&& (!tbret
|| tbret
->ty
== Tvoid
) && fd
->isMain())
2838 exp
= new IntegerExp(0);
2841 if (sc
->incontract
|| scx
->incontract
)
2842 error("return statements cannot be in contracts");
2843 if (sc
->tf
|| scx
->tf
)
2844 error("return statements cannot be in finally, scope(exit) or scope(success) bodies");
2846 if (fd
->isCtorDeclaration())
2848 // Constructors implicitly do:
2850 if (exp
&& exp
->op
!= TOKthis
)
2851 error("cannot return expression from constructor");
2852 exp
= new ThisExp(0);
2860 fd
->hasReturnExp
|= 1;
2862 exp
= exp
->semantic(sc
);
2863 exp
= resolveProperties(sc
, exp
);
2864 exp
= exp
->optimize(WANTvalue
);
2866 if (fd
->nrvo_can
&& exp
->op
== TOKvar
)
2867 { VarExp
*ve
= (VarExp
*)exp
;
2868 VarDeclaration
*v
= ve
->var
->isVarDeclaration();
2870 if (!v
|| v
->isOut() || v
->isRef())
2872 else if (tbret
->ty
== Tstruct
&& ((TypeStruct
*)tbret
)->sym
->dtor
)
2873 // Struct being returned has destructors
2875 else if (fd
->nrvo_var
== NULL
)
2876 { if (!v
->isDataseg() && !v
->isParameter() && v
->toParent2() == fd
)
2877 { //printf("Setting nrvo to %s\n", v->toChars());
2883 else if (fd
->nrvo_var
!= v
)
2889 if (fd
->returnLabel
&& tbret
->ty
!= Tvoid
)
2892 else if (fd
->inferRetType
)
2894 if (fd
->type
->nextOf())
2896 if (!exp
->type
->equals(fd
->type
->nextOf()))
2897 error("mismatched function return type inference of %s and %s",
2898 exp
->type
->toChars(), fd
->type
->nextOf()->toChars());
2902 ((TypeFunction
*)fd
->type
)->next
= exp
->type
;
2903 fd
->type
= fd
->type
->semantic(loc
, sc
);
2905 { tret
= fd
->type
->nextOf();
2906 tbret
= tret
->toBasetype();
2910 else if (tbret
->ty
!= Tvoid
)
2912 exp
= exp
->implicitCastTo(sc
, tret
);
2915 else if (fd
->inferRetType
)
2917 if (fd
->type
->nextOf())
2919 if (fd
->type
->nextOf()->ty
!= Tvoid
)
2920 error("mismatched function return type inference of void and %s",
2921 fd
->type
->nextOf()->toChars());
2925 ((TypeFunction
*)fd
->type
)->next
= Type::tvoid
;
2926 fd
->type
= fd
->type
->semantic(loc
, sc
);
2928 { tret
= Type::tvoid
;
2933 else if (tbret
->ty
!= Tvoid
) // if non-void return
2934 error("return expression expected");
2940 if (exp
&& !implicit0
)
2942 exp
= exp
->implicitCastTo(sc
, tret
);
2944 if (!exp
|| exp
->op
== TOKint64
|| exp
->op
== TOKfloat64
||
2945 exp
->op
== TOKimaginary80
|| exp
->op
== TOKcomplex80
||
2946 exp
->op
== TOKthis
|| exp
->op
== TOKsuper
|| exp
->op
== TOKnull
||
2947 exp
->op
== TOKstring
)
2949 sc
->fes
->cases
.push(this);
2950 s
= new ReturnStatement(0, new IntegerExp(sc
->fes
->cases
.dim
+ 1));
2952 else if (fd
->type
->nextOf()->toBasetype() == Type::tvoid
)
2957 s
= new ReturnStatement(0, NULL
);
2958 sc
->fes
->cases
.push(s
);
2960 // Construct: { exp; return cases.dim + 1; }
2961 s1
= new ExpStatement(loc
, exp
);
2962 s2
= new ReturnStatement(0, new IntegerExp(sc
->fes
->cases
.dim
+ 1));
2963 s
= new CompoundStatement(loc
, s1
, s2
);
2971 // Construct: return vresult;
2973 { VarDeclaration
*v
;
2975 v
= new VarDeclaration(loc
, tret
, Id::result
, NULL
);
2978 if (!scx
->insert(v
))
2984 v
= new VarExp(0, fd
->vresult
);
2985 s
= new ReturnStatement(0, v
);
2986 sc
->fes
->cases
.push(s
);
2988 // Construct: { vresult = exp; return cases.dim + 1; }
2989 v
= new VarExp(0, fd
->vresult
);
2990 exp
= new AssignExp(loc
, v
, exp
);
2991 exp
= exp
->semantic(sc
);
2992 s1
= new ExpStatement(loc
, exp
);
2993 s2
= new ReturnStatement(0, new IntegerExp(sc
->fes
->cases
.dim
+ 1));
2994 s
= new CompoundStatement(loc
, s1
, s2
);
3001 if (fd
->returnLabel
&& tbret
->ty
!= Tvoid
)
3003 assert(fd
->vresult
);
3004 VarExp
*v
= new VarExp(0, fd
->vresult
);
3006 exp
= new AssignExp(loc
, v
, exp
);
3007 exp
= exp
->semantic(sc
);
3014 /* BUG: need to issue an error on:
3021 if (sc
->callSuper
& CSXany_ctor
&&
3022 !(sc
->callSuper
& (CSXthis_ctor
| CSXsuper_ctor
)))
3023 error("return without calling constructor");
3025 sc
->callSuper
|= CSXreturn
;
3027 // See if all returns are instead to be replaced with a goto returnLabel;
3028 if (fd
->returnLabel
)
3030 GotoStatement
*gs
= new GotoStatement(loc
, Id::returnLabel
);
3032 gs
->label
= fd
->returnLabel
;
3036 s
= new ExpStatement(0, exp
);
3037 return new CompoundStatement(loc
, s
, gs
);
3042 if (exp
&& tbret
->ty
== Tvoid
&& !fd
->isMain())
3045 s
= new ExpStatement(loc
, exp
);
3048 return new CompoundStatement(loc
, s
, this);
3054 int ReturnStatement::blockExit()
3055 { int result
= BEreturn
;
3057 if (exp
&& exp
->canThrow())
3062 int ReturnStatement::fallOffEnd()
3067 void ReturnStatement::toCBuffer(OutBuffer
*buf
, HdrGenState
*hgs
)
3069 buf
->printf("return ");
3071 exp
->toCBuffer(buf
, hgs
);
3072 buf
->writeByte(';');
3076 /******************************** BreakStatement ***************************/
3078 BreakStatement::BreakStatement(Loc loc
, Identifier
*ident
)
3081 this->ident
= ident
;
3084 Statement
*BreakStatement::syntaxCopy()
3086 BreakStatement
*s
= new BreakStatement(loc
, ident
);
3090 Statement
*BreakStatement::semantic(Scope
*sc
)
3092 //printf("BreakStatement::semantic()\n");
3094 // break Identifier;
3098 FuncDeclaration
*thisfunc
= sc
->func
;
3100 for (scx
= sc
; scx
; scx
= scx
->enclosing
)
3104 if (scx
->func
!= thisfunc
) // if in enclosing function
3106 if (sc
->fes
) // if this is the body of a foreach
3108 /* Post this statement to the fes, and replace
3109 * it with a return value that caller will put into
3110 * a switch. Caller will figure out where the break
3111 * label actually is.
3112 * Case numbers start with 2, not 0, as 0 is continue
3116 sc
->fes
->cases
.push(this);
3117 s
= new ReturnStatement(0, new IntegerExp(sc
->fes
->cases
.dim
+ 1));
3120 break; // can't break to it
3124 if (ls
&& ls
->ident
== ident
)
3126 Statement
*s
= ls
->statement
;
3129 error("label '%s' has no break", ident
->toChars());
3130 if (ls
->tf
!= sc
->tf
)
3131 error("cannot break out of finally block");
3135 error("enclosing label '%s' for break not found", ident
->toChars());
3137 else if (!sc
->sbreak
)
3142 // Replace break; with return 1;
3143 s
= new ReturnStatement(0, new IntegerExp(1));
3146 error("break is not inside a loop or switch");
3151 int BreakStatement::blockExit()
3153 //printf("BreakStatement::blockExit(%p) = x%x\n", this, ident ? BEgoto : BEbreak);
3154 return ident
? BEgoto
: BEbreak
;
3157 int BreakStatement::fallOffEnd()
3162 void BreakStatement::toCBuffer(OutBuffer
*buf
, HdrGenState
*hgs
)
3164 buf
->writestring("break");
3166 { buf
->writebyte(' ');
3167 buf
->writestring(ident
->toChars());
3169 buf
->writebyte(';');
3173 /******************************** ContinueStatement ***************************/
3175 ContinueStatement::ContinueStatement(Loc loc
, Identifier
*ident
)
3178 this->ident
= ident
;
3181 Statement
*ContinueStatement::syntaxCopy()
3183 ContinueStatement
*s
= new ContinueStatement(loc
, ident
);
3187 Statement
*ContinueStatement::semantic(Scope
*sc
)
3189 //printf("ContinueStatement::semantic() %p\n", this);
3193 FuncDeclaration
*thisfunc
= sc
->func
;
3195 for (scx
= sc
; scx
; scx
= scx
->enclosing
)
3199 if (scx
->func
!= thisfunc
) // if in enclosing function
3201 if (sc
->fes
) // if this is the body of a foreach
3203 for (; scx
; scx
= scx
->enclosing
)
3206 if (ls
&& ls
->ident
== ident
&& ls
->statement
== sc
->fes
)
3208 // Replace continue ident; with return 0;
3209 return new ReturnStatement(0, new IntegerExp(0));
3213 /* Post this statement to the fes, and replace
3214 * it with a return value that caller will put into
3215 * a switch. Caller will figure out where the break
3216 * label actually is.
3217 * Case numbers start with 2, not 0, as 0 is continue
3221 sc
->fes
->cases
.push(this);
3222 s
= new ReturnStatement(0, new IntegerExp(sc
->fes
->cases
.dim
+ 1));
3225 break; // can't continue to it
3229 if (ls
&& ls
->ident
== ident
)
3231 Statement
*s
= ls
->statement
;
3233 if (!s
->hasContinue())
3234 error("label '%s' has no continue", ident
->toChars());
3235 if (ls
->tf
!= sc
->tf
)
3236 error("cannot continue out of finally block");
3240 error("enclosing label '%s' for continue not found", ident
->toChars());
3242 else if (!sc
->scontinue
)
3247 // Replace continue; with return 0;
3248 s
= new ReturnStatement(0, new IntegerExp(0));
3251 error("continue is not inside a loop");
3256 int ContinueStatement::blockExit()
3258 return ident
? BEgoto
: BEcontinue
;
3261 int ContinueStatement::fallOffEnd()
3266 void ContinueStatement::toCBuffer(OutBuffer
*buf
, HdrGenState
*hgs
)
3268 buf
->writestring("continue");
3270 { buf
->writebyte(' ');
3271 buf
->writestring(ident
->toChars());
3273 buf
->writebyte(';');
3277 /******************************** SynchronizedStatement ***************************/
3279 SynchronizedStatement::SynchronizedStatement(Loc loc
, Expression
*exp
, Statement
*body
)
3287 SynchronizedStatement::SynchronizedStatement(Loc loc
, elem
*esync
, Statement
*body
)
3292 this->esync
= esync
;
3295 Statement
*SynchronizedStatement::syntaxCopy()
3297 Expression
*e
= exp
? exp
->syntaxCopy() : NULL
;
3298 SynchronizedStatement
*s
= new SynchronizedStatement(loc
, e
, body
? body
->syntaxCopy() : NULL
);
3302 Statement
*SynchronizedStatement::semantic(Scope
*sc
)
3305 { ClassDeclaration
*cd
;
3307 exp
= exp
->semantic(sc
);
3308 exp
= resolveProperties(sc
, exp
);
3309 cd
= exp
->type
->isClassHandle();
3311 error("can only synchronize on class objects, not '%s'", exp
->type
->toChars());
3312 else if (cd
->isInterfaceDeclaration())
3313 { Type
*t
= new TypeIdentifier(0, Id::Object
);
3315 t
= t
->semantic(0, sc
);
3316 exp
= new CastExp(loc
, exp
, t
);
3317 exp
= exp
->semantic(sc
);
3321 body
= body
->semantic(sc
);
3325 int SynchronizedStatement::hasBreak()
3327 return FALSE
; //TRUE;
3330 int SynchronizedStatement::hasContinue()
3332 return FALSE
; //TRUE;
3335 int SynchronizedStatement::usesEH()
3340 int SynchronizedStatement::blockExit()
3342 return body
? body
->blockExit() : BEfallthru
;
3345 int SynchronizedStatement::fallOffEnd()
3347 return body
? body
->fallOffEnd() : TRUE
;
3350 void SynchronizedStatement::toCBuffer(OutBuffer
*buf
, HdrGenState
*hgs
)
3352 buf
->writestring("synchronized");
3354 { buf
->writebyte('(');
3355 exp
->toCBuffer(buf
, hgs
);
3356 buf
->writebyte(')');
3360 buf
->writebyte(' ');
3361 body
->toCBuffer(buf
, hgs
);
3365 /******************************** WithStatement ***************************/
3367 WithStatement::WithStatement(Loc loc
, Expression
*exp
, Statement
*body
)
3375 Statement
*WithStatement::syntaxCopy()
3377 WithStatement
*s
= new WithStatement(loc
, exp
->syntaxCopy(), body
? body
->syntaxCopy() : NULL
);
3381 Statement
*WithStatement::semantic(Scope
*sc
)
3382 { ScopeDsymbol
*sym
;
3385 //printf("WithStatement::semantic()\n");
3386 exp
= exp
->semantic(sc
);
3387 exp
= resolveProperties(sc
, exp
);
3388 if (exp
->op
== TOKimport
)
3389 { ScopeExp
*es
= (ScopeExp
*)exp
;
3393 else if (exp
->op
== TOKtype
)
3394 { TypeExp
*es
= (TypeExp
*)exp
;
3396 sym
= es
->type
->toDsymbol(sc
)->isScopeDsymbol();
3398 { error("%s has no members", es
->toChars());
3399 body
= body
->semantic(sc
);
3404 { Type
*t
= exp
->type
;
3407 t
= t
->toBasetype();
3408 if (t
->isClassHandle())
3410 init
= new ExpInitializer(loc
, exp
);
3411 wthis
= new VarDeclaration(loc
, exp
->type
, Id::withSym
, init
);
3412 wthis
->semantic(sc
);
3414 sym
= new WithScopeSymbol(this);
3415 sym
->parent
= sc
->scopesym
;
3417 else if (t
->ty
== Tstruct
)
3419 Expression
*e
= exp
->addressOf(sc
);
3420 init
= new ExpInitializer(loc
, e
);
3421 wthis
= new VarDeclaration(loc
, e
->type
, Id::withSym
, init
);
3422 wthis
->semantic(sc
);
3423 sym
= new WithScopeSymbol(this);
3424 sym
->parent
= sc
->scopesym
;
3427 { error("with expressions must be class objects, not '%s'", exp
->type
->toChars());
3434 body
= body
->semantic(sc
);
3441 void WithStatement::toCBuffer(OutBuffer
*buf
, HdrGenState
*hgs
)
3443 buf
->writestring("with (");
3444 exp
->toCBuffer(buf
, hgs
);
3445 buf
->writestring(")\n");
3447 body
->toCBuffer(buf
, hgs
);
3450 int WithStatement::usesEH()
3452 return body
? body
->usesEH() : 0;
3455 int WithStatement::blockExit()
3457 int result
= BEnone
;
3458 if (exp
->canThrow())
3461 result
|= body
->blockExit();
3463 result
|= BEfallthru
;
3467 int WithStatement::fallOffEnd()
3469 return body
? body
->fallOffEnd() : TRUE
;
3472 /******************************** TryCatchStatement ***************************/
3474 TryCatchStatement::TryCatchStatement(Loc loc
, Statement
*body
, Array
*catches
)
3478 this->catches
= catches
;
3481 Statement
*TryCatchStatement::syntaxCopy()
3483 Array
*a
= new Array();
3484 a
->setDim(catches
->dim
);
3485 for (int i
= 0; i
< a
->dim
; i
++)
3488 c
= (Catch
*)catches
->data
[i
];
3489 c
= c
->syntaxCopy();
3492 TryCatchStatement
*s
= new TryCatchStatement(loc
, body
->syntaxCopy(), a
);
3496 Statement
*TryCatchStatement::semantic(Scope
*sc
)
3498 body
= body
->semanticScope(sc
, NULL
/*this*/, NULL
);
3500 /* Even if body is NULL, still do semantic analysis on catches
3502 for (size_t i
= 0; i
< catches
->dim
; i
++)
3503 { Catch
*c
= (Catch
*)catches
->data
[i
];
3506 // Determine if current catch 'hides' any previous catches
3507 for (size_t j
= 0; j
< i
; j
++)
3508 { Catch
*cj
= (Catch
*)catches
->data
[j
];
3509 char *si
= c
->loc
.toChars();
3510 char *sj
= cj
->loc
.toChars();
3512 if (c
->type
->toBasetype()->implicitConvTo(cj
->type
->toBasetype()))
3513 error("catch at %s hides catch at %s", sj
, si
);
3523 int TryCatchStatement::hasBreak()
3525 return FALSE
; //TRUE;
3528 int TryCatchStatement::usesEH()
3533 int TryCatchStatement::blockExit()
3537 result
= body
->blockExit();
3539 for (size_t i
= 0; i
< catches
->dim
; i
++)
3541 Catch
*c
= (Catch
*)catches
->data
[i
];
3542 result
|= c
->blockExit();
3547 int TryCatchStatement::fallOffEnd()
3552 result
= body
->fallOffEnd();
3553 for (int i
= 0; i
< catches
->dim
; i
++)
3556 c
= (Catch
*)catches
->data
[i
];
3558 result
|= c
->handler
->fallOffEnd();
3563 void TryCatchStatement::toCBuffer(OutBuffer
*buf
, HdrGenState
*hgs
)
3565 buf
->writestring("try");
3568 body
->toCBuffer(buf
, hgs
);
3569 for (size_t i
= 0; i
< catches
->dim
; i
++)
3571 Catch
*c
= (Catch
*)catches
->data
[i
];
3572 c
->toCBuffer(buf
, hgs
);
3576 /******************************** Catch ***************************/
3578 Catch::Catch(Loc loc
, Type
*t
, Identifier
*id
, Statement
*handler
)
3580 //printf("Catch(%s, loc = %s)\n", id->toChars(), loc.toChars());
3584 this->handler
= handler
;
3588 Catch
*Catch::syntaxCopy()
3590 Catch
*c
= new Catch(loc
,
3591 (type
? type
->syntaxCopy() : NULL
),
3593 (handler
? handler
->syntaxCopy() : NULL
));
3597 void Catch::semantic(Scope
*sc
)
3598 { ScopeDsymbol
*sym
;
3600 //printf("Catch::semantic(%s)\n", ident->toChars());
3605 /* This is because the _d_local_unwind() gets the stack munged
3606 * up on this. The workaround is to place any try-catches into
3607 * a separate function, and call that.
3608 * To fix, have the compiler automatically convert the finally
3609 * body into a nested function.
3611 error(loc
, "cannot put catch statement inside finally block");
3615 sym
= new ScopeDsymbol();
3616 sym
->parent
= sc
->scopesym
;
3620 type
= new TypeIdentifier(0, Id::Object
);
3621 type
= type
->semantic(loc
, sc
);
3622 if (!type
->toBasetype()->isClassHandle())
3623 error("can only catch class objects, not '%s'", type
->toChars());
3626 var
= new VarDeclaration(loc
, type
, ident
, NULL
);
3627 var
->parent
= sc
->parent
;
3630 handler
= handler
->semantic(sc
);
3635 int Catch::blockExit()
3637 return handler
? handler
->blockExit() : BEfallthru
;
3640 void Catch::toCBuffer(OutBuffer
*buf
, HdrGenState
*hgs
)
3642 buf
->writestring("catch");
3644 { buf
->writebyte('(');
3645 type
->toCBuffer(buf
, ident
, hgs
);
3646 buf
->writebyte(')');
3649 buf
->writebyte('{');
3652 handler
->toCBuffer(buf
, hgs
);
3653 buf
->writebyte('}');
3657 /****************************** TryFinallyStatement ***************************/
3659 TryFinallyStatement::TryFinallyStatement(Loc loc
, Statement
*body
, Statement
*finalbody
)
3663 this->finalbody
= finalbody
;
3666 Statement
*TryFinallyStatement::syntaxCopy()
3668 TryFinallyStatement
*s
= new TryFinallyStatement(loc
,
3669 body
->syntaxCopy(), finalbody
->syntaxCopy());
3673 Statement
*TryFinallyStatement::semantic(Scope
*sc
)
3675 //printf("TryFinallyStatement::semantic()\n");
3676 body
= body
->semantic(sc
);
3680 sc
->scontinue
= NULL
; // no break or continue out of finally block
3681 finalbody
= finalbody
->semantic(sc
);
3687 if (body
->blockExit() == BEfallthru
)
3688 { Statement
*s
= new CompoundStatement(loc
, body
, finalbody
);
3694 void TryFinallyStatement::toCBuffer(OutBuffer
*buf
, HdrGenState
*hgs
)
3696 buf
->printf("try\n{\n");
3697 body
->toCBuffer(buf
, hgs
);
3698 buf
->printf("}\nfinally\n{\n");
3699 finalbody
->toCBuffer(buf
, hgs
);
3700 buf
->writeByte('}');
3704 int TryFinallyStatement::hasBreak()
3706 return FALSE
; //TRUE;
3709 int TryFinallyStatement::hasContinue()
3711 return FALSE
; //TRUE;
3714 int TryFinallyStatement::usesEH()
3719 int TryFinallyStatement::blockExit()
3721 int result
= body
->blockExit();
3725 int TryFinallyStatement::fallOffEnd()
3728 result
= body
->fallOffEnd();
3730 // result = finalbody->fallOffEnd();
3734 /****************************** OnScopeStatement ***************************/
3736 OnScopeStatement::OnScopeStatement(Loc loc
, TOK tok
, Statement
*statement
)
3740 this->statement
= statement
;
3743 Statement
*OnScopeStatement::syntaxCopy()
3745 OnScopeStatement
*s
= new OnScopeStatement(loc
,
3746 tok
, statement
->syntaxCopy());
3750 Statement
*OnScopeStatement::semantic(Scope
*sc
)
3752 /* semantic is called on results of scopeCode() */
3756 int OnScopeStatement::blockExit()
3757 { // At this point, this statement is just an empty placeholder
3761 void OnScopeStatement::toCBuffer(OutBuffer
*buf
, HdrGenState
*hgs
)
3763 buf
->writestring(Token::toChars(tok
));
3764 buf
->writebyte(' ');
3765 statement
->toCBuffer(buf
, hgs
);
3768 int OnScopeStatement::usesEH()
3773 void OnScopeStatement::scopeCode(Scope
*sc
, Statement
**sentry
, Statement
**sexception
, Statement
**sfinally
)
3775 //printf("OnScopeStatement::scopeCode()\n");
3782 case TOKon_scope_exit
:
3783 *sfinally
= statement
;
3786 case TOKon_scope_failure
:
3787 *sexception
= statement
;
3790 case TOKon_scope_success
:
3793 * sentry: int x = 0;
3794 * sexception: x = 1;
3795 * sfinally: if (!x) statement;
3797 Identifier
*id
= Lexer::uniqueId("__os");
3799 ExpInitializer
*ie
= new ExpInitializer(loc
, new IntegerExp(0));
3800 VarDeclaration
*v
= new VarDeclaration(loc
, Type::tint32
, id
, ie
);
3801 *sentry
= new DeclarationStatement(loc
, v
);
3803 Expression
*e
= new IntegerExp(1);
3804 e
= new AssignExp(0, new VarExp(0, v
), e
);
3805 *sexception
= new ExpStatement(0, e
);
3807 e
= new VarExp(0, v
);
3808 e
= new NotExp(0, e
);
3809 *sfinally
= new IfStatement(0, NULL
, e
, statement
, NULL
);
3819 /******************************** ThrowStatement ***************************/
3821 ThrowStatement::ThrowStatement(Loc loc
, Expression
*exp
)
3827 Statement
*ThrowStatement::syntaxCopy()
3829 ThrowStatement
*s
= new ThrowStatement(loc
, exp
->syntaxCopy());
3833 Statement
*ThrowStatement::semantic(Scope
*sc
)
3835 //printf("ThrowStatement::semantic()\n");
3837 FuncDeclaration
*fd
= sc
->parent
->isFuncDeclaration();
3838 fd
->hasReturnExp
|= 2;
3841 error("Throw statements cannot be in contracts");
3842 exp
= exp
->semantic(sc
);
3843 exp
= resolveProperties(sc
, exp
);
3844 if (!exp
->type
->toBasetype()->isClassHandle())
3845 error("can only throw class objects, not type %s", exp
->type
->toChars());
3849 int ThrowStatement::blockExit()
3851 return BEthrow
; // obviously
3854 int ThrowStatement::fallOffEnd()
3859 void ThrowStatement::toCBuffer(OutBuffer
*buf
, HdrGenState
*hgs
)
3861 buf
->printf("throw ");
3862 exp
->toCBuffer(buf
, hgs
);
3863 buf
->writeByte(';');
3867 /******************************** VolatileStatement **************************/
3869 VolatileStatement::VolatileStatement(Loc loc
, Statement
*statement
)
3872 this->statement
= statement
;
3875 Statement
*VolatileStatement::syntaxCopy()
3877 VolatileStatement
*s
= new VolatileStatement(loc
,
3878 statement
? statement
->syntaxCopy() : NULL
);
3882 Statement
*VolatileStatement::semantic(Scope
*sc
)
3885 statement
= statement
->semantic(sc
);
3889 Statements
*VolatileStatement::flatten(Scope
*sc
)
3893 a
= statement
? statement
->flatten(sc
) : NULL
;
3895 { for (int i
= 0; i
< a
->dim
; i
++)
3896 { Statement
*s
= (Statement
*)a
->data
[i
];
3898 s
= new VolatileStatement(loc
, s
);
3906 int VolatileStatement::blockExit()
3908 return statement
? statement
->blockExit() : BEfallthru
;
3911 int VolatileStatement::fallOffEnd()
3913 return statement
? statement
->fallOffEnd() : TRUE
;
3916 void VolatileStatement::toCBuffer(OutBuffer
*buf
, HdrGenState
*hgs
)
3918 buf
->writestring("volatile");
3920 { if (statement
->isScopeStatement())
3923 buf
->writebyte(' ');
3924 statement
->toCBuffer(buf
, hgs
);
3929 /******************************** GotoStatement ***************************/
3931 GotoStatement::GotoStatement(Loc loc
, Identifier
*ident
)
3934 this->ident
= ident
;
3939 Statement
*GotoStatement::syntaxCopy()
3941 GotoStatement
*s
= new GotoStatement(loc
, ident
);
3945 Statement
*GotoStatement::semantic(Scope
*sc
)
3946 { FuncDeclaration
*fd
= sc
->parent
->isFuncDeclaration();
3948 //printf("GotoStatement::semantic()\n");
3950 label
= fd
->searchLabel(ident
);
3951 if (!label
->statement
&& sc
->fes
)
3953 /* Either the goto label is forward referenced or it
3954 * is in the function that the enclosing foreach is in.
3955 * Can't know yet, so wrap the goto in a compound statement
3956 * so we can patch it later, and add it to a 'look at this later'
3959 Statements
*a
= new Statements();
3963 s
= new CompoundStatement(loc
, a
);
3964 sc
->fes
->gotos
.push(s
); // 'look at this later' list
3967 if (label
->statement
&& label
->statement
->tf
!= sc
->tf
)
3968 error("cannot goto in or out of finally block");
3972 int GotoStatement::blockExit()
3974 //printf("GotoStatement::blockExit(%p)\n", this);
3978 int GotoStatement::fallOffEnd()
3983 void GotoStatement::toCBuffer(OutBuffer
*buf
, HdrGenState
*hgs
)
3985 buf
->writestring("goto ");
3986 buf
->writestring(ident
->toChars());
3987 buf
->writebyte(';');
3991 /******************************** LabelStatement ***************************/
3993 LabelStatement::LabelStatement(Loc loc
, Identifier
*ident
, Statement
*statement
)
3996 this->ident
= ident
;
3997 this->statement
= statement
;
3999 this->lblock
= NULL
;
4000 this->isReturnLabel
= 0;
4003 Statement
*LabelStatement::syntaxCopy()
4005 LabelStatement
*s
= new LabelStatement(loc
, ident
, statement
->syntaxCopy());
4009 Statement
*LabelStatement::semantic(Scope
*sc
)
4011 FuncDeclaration
*fd
= sc
->parent
->isFuncDeclaration();
4013 //printf("LabelStatement::semantic()\n");
4014 ls
= fd
->searchLabel(ident
);
4016 error("Label '%s' already defined", ls
->toChars());
4018 ls
->statement
= this;
4021 sc
->scopesym
= sc
->enclosing
->scopesym
;
4022 sc
->callSuper
|= CSXlabel
;
4025 statement
= statement
->semantic(sc
);
4030 Statements
*LabelStatement::flatten(Scope
*sc
)
4032 Statements
*a
= NULL
;
4036 a
= statement
->flatten(sc
);
4041 a
->push(new ExpStatement(loc
, NULL
));
4043 Statement
*s
= (Statement
*)a
->data
[0];
4045 s
= new LabelStatement(loc
, ident
, s
);
4054 int LabelStatement::usesEH()
4056 return statement
? statement
->usesEH() : FALSE
;
4059 int LabelStatement::blockExit()
4061 //printf("LabelStatement::blockExit(%p)\n", this);
4062 return statement
? statement
->blockExit() : BEfallthru
;
4065 int LabelStatement::fallOffEnd()
4067 return statement
? statement
->fallOffEnd() : TRUE
;
4070 int LabelStatement::comeFrom()
4072 //printf("LabelStatement::comeFrom()\n");
4076 void LabelStatement::toCBuffer(OutBuffer
*buf
, HdrGenState
*hgs
)
4078 buf
->writestring(ident
->toChars());
4079 buf
->writebyte(':');
4082 statement
->toCBuffer(buf
, hgs
);
4086 /******************************** LabelDsymbol ***************************/
4088 LabelDsymbol::LabelDsymbol(Identifier
*ident
)
4097 LabelDsymbol
*LabelDsymbol::isLabel() // is this a LabelDsymbol()?