2 // Compiler implementation of the D programming language
3 // Copyright (c) 1999-2007 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"
36 /******************************** Statement ***************************/
38 Statement::Statement(Loc loc
)
42 // If this is an in{} contract scope statement (skip for determining
43 // inlineStatus of a function body for header content)
48 Statement
*Statement::syntaxCopy()
54 void Statement::print()
56 fprintf(stdmsg
, "%s\n", toChars());
60 char *Statement::toChars()
64 buf
= new OutBuffer();
66 return buf
->toChars();
69 void Statement::toCBuffer(OutBuffer
*buf
, HdrGenState
*hgs
)
71 buf
->printf("Statement::toCBuffer()");
75 Statement
*Statement::semantic(Scope
*sc
)
80 // Same as semantic(), but do create a new scope
82 Statement
*Statement::semanticScope(Scope
*sc
, Statement
*sbreak
, Statement
*scontinue
)
90 scd
->scontinue
= scontinue
;
96 void Statement::error(const char *format
, ...)
100 ::verror(loc
, format
, ap
);
104 int Statement::hasBreak()
106 //printf("Statement::hasBreak()\n");
110 int Statement::hasContinue()
115 // TRUE if statement uses exception handling
117 int Statement::usesEH()
122 // TRUE if statement may fall off the end without a throw or return
124 int Statement::fallOffEnd()
129 // TRUE if statement 'comes from' somewhere else, like a goto
131 int Statement::comeFrom()
133 //printf("Statement::comeFrom()\n");
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
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");
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
)
168 /******************************** ExpStatement ***************************/
170 ExpStatement::ExpStatement(Loc loc
, Expression
*exp
)
176 Statement
*ExpStatement::syntaxCopy()
178 Expression
*e
= exp
? exp
->syntaxCopy() : NULL
;
179 ExpStatement
*es
= new ExpStatement(loc
, e
);
183 void ExpStatement::toCBuffer(OutBuffer
*buf
, HdrGenState
*hgs
)
186 exp
->toCBuffer(buf
, hgs
);
188 if (!hgs
->FLinit
.init
)
192 Statement
*ExpStatement::semantic(Scope
*sc
)
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);
206 int ExpStatement::fallOffEnd()
210 if (exp
->op
== TOKassert
)
211 { AssertExp
*a
= (AssertExp
*)exp
;
213 if (a
->e1
->isBool(FALSE
)) // if it's an assert(0)
216 else if (exp
->op
== TOKhalt
)
222 /******************************** CompileStatement ***************************/
224 CompileStatement::CompileStatement(Loc loc
, Expression
*exp
)
230 Statement
*CompileStatement::syntaxCopy()
232 Expression
*e
= exp
->syntaxCopy();
233 CompileStatement
*es
= new CompileStatement(loc
, e
);
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
)
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());
256 StringExp
*se
= (StringExp
*)exp
;
258 Parser
p(sc
->module
, (unsigned char *)se
->string
, se
->len
, 0);
262 Statements
*statements
= new Statements();
263 while (p
.token
.value
!= TOKeof
)
265 Statement
*s
= p
.parseStatement(PSsemi
| PScurlyscope
);
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());
292 void DeclarationStatement::scopeCode(Statement
**sentry
, Statement
**sexception
, Statement
**sfinally
)
294 //printf("DeclarationStatement::scopeCode()\n");
303 if (exp
->op
== TOKdeclaration
)
305 DeclarationExp
*de
= (DeclarationExp
*)(exp
);
306 VarDeclaration
*v
= de
->declaration
->isVarDeclaration();
310 e
= v
->callAutoDtor();
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
));
340 // For everything else, call a getter in the _externals module
341 Expression
*getter
= new DotIdExp(loc
, externals
, arg
->ident
);
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
++) {
362 s
= (Dsymbol
*)mainClass
->members
->data
[i
];
364 CtorDeclaration
*thisCtor
= s
->isCtorDeclaration();
367 error("Multiple constructors for Main class!");
374 FuncDeclaration
*thisMethod
= s
->isFuncDeclaration();
375 if (thisMethod
&& thisMethod
->ident
== Id::main
) {
377 error("Multiple main methods for Main class!");
380 mainDecl
= thisMethod
;
385 if (mainDecl
== NULL
) {
386 error("No main method in Main class!");
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
)
422 CompoundStatement::CompoundStatement(Loc loc
, Statement
*s1
, Statement
*s2
)
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
];
441 CompoundStatement
*cs
= new CompoundStatement(loc
, a
);
446 Statement
*CompoundStatement::semantic(Scope
*sc
)
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
];
455 { Statements
*a
= s
->flatten(sc
);
459 statements
->remove(i
);
460 statements
->insert(i
, a
);
464 statements
->data
[i
] = s
;
468 Statement
*sexception
;
471 s
->scopeCode(&sentry
, &sexception
, &sfinally
);
474 sentry
= sentry
->semantic(sc
);
475 statements
->data
[i
] = sentry
;
479 if (i
+ 1 == statements
->dim
&& !sfinally
)
482 sexception
= sexception
->semantic(sc
);
484 statements
->push(sexception
);
486 // Assume sexception does not throw
487 statements
->push(sfinally
);
498 * { sexception; throw __o; }
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
);
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
);
521 s
= new TryCatchStatement(0, body
, catches
);
524 s
= new TryFinallyStatement(0, s
, sfinally
);
526 statements
->setDim(i
+ 1);
533 if (0 && i
+ 1 == statements
->dim
)
535 statements
->push(sfinally
);
542 * s; try { s1; s2; } finally { sfinally; }
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
);
554 statements
->setDim(i
+ 1);
563 if (statements
->dim
== 1)
568 Statements
*CompoundStatement::flatten(Scope
*sc
)
573 ReturnStatement
*CompoundStatement::isReturnStatement()
575 ReturnStatement
*rs
= NULL
;
577 for (i
= 0; i
< statements
->dim
; i
++)
580 s
= (Statement
*) statements
->data
[i
];
583 rs
= s
->isReturnStatement();
591 void CompoundStatement::toCBuffer(OutBuffer
*buf
, HdrGenState
*hgs
)
594 for (i
= 0; i
< statements
->dim
; i
++)
597 s
= (Statement
*) statements
->data
[i
];
599 s
->toCBuffer(buf
, hgs
);
603 int CompoundStatement::usesEH()
605 for (int i
= 0; i
< statements
->dim
; i
++)
608 s
= (Statement
*) statements
->data
[i
];
609 if (s
&& s
->usesEH())
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
];
625 if (!falloff
&& global
.params
.warnings
&& !s
->comeFrom())
627 fprintf(stdmsg
, "warning - ");
628 s
->error("statement is not reachable");
630 falloff
= s
->fallOffEnd();
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
];
645 comefrom
|= s
->comeFrom();
651 /**************************** UnrolledLoopStatement ***************************/
653 UnrolledLoopStatement::UnrolledLoopStatement(Loc loc
, 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
];
669 UnrolledLoopStatement
*cs
= new UnrolledLoopStatement(loc
, a
);
674 Statement
*UnrolledLoopStatement::semantic(Scope
*sc
)
676 //printf("UnrolledLoopStatement::semantic(this = %p, sc = %p)\n", this, sc);
679 Scope
*scd
= sc
->push();
681 scd
->scontinue
= this;
683 for (size_t i
= 0; i
< statements
->dim
; i
++)
685 Statement
*s
= (Statement
*) statements
->data
[i
];
688 s
= s
->semantic(scd
);
689 statements
->data
[i
] = s
;
698 void UnrolledLoopStatement::toCBuffer(OutBuffer
*buf
, HdrGenState
*hgs
)
700 buf
->writestring("unrolled {");
703 for (size_t i
= 0; i
< statements
->dim
; i
++)
706 s
= (Statement
*) statements
->data
[i
];
708 s
->toCBuffer(buf
, hgs
);
715 int UnrolledLoopStatement::hasBreak()
720 int UnrolledLoopStatement::hasContinue()
725 int UnrolledLoopStatement::usesEH()
727 for (size_t i
= 0; i
< statements
->dim
; i
++)
730 s
= (Statement
*) statements
->data
[i
];
731 if (s
&& s
->usesEH())
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
];
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
];
760 comefrom
|= s
->comeFrom();
766 /******************************** ScopeStatement ***************************/
768 ScopeStatement::ScopeStatement(Loc loc
, Statement
*s
)
774 Statement
*ScopeStatement::syntaxCopy()
778 s
= statement
? statement
->syntaxCopy() : NULL
;
779 s
= new ScopeStatement(loc
, s
);
784 Statement
*ScopeStatement::semantic(Scope
*sc
)
787 //printf("ScopeStatement::semantic(sc = %p)\n", sc);
791 sym
= new ScopeDsymbol();
792 sym
->parent
= sc
->scopesym
;
795 a
= statement
->flatten(sc
);
798 statement
= new CompoundStatement(loc
, a
);
801 statement
= statement
->semantic(sc
);
805 Statement
*sexception
;
808 statement
->scopeCode(&sentry
, &sexception
, &sfinally
);
811 //printf("adding sfinally\n");
812 statement
= new CompoundStatement(loc
, statement
, sfinally
);
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
)
854 statement
->toCBuffer(buf
, hgs
);
860 /******************************** WhileStatement ***************************/
862 WhileStatement::WhileStatement(Loc loc
, Expression
*c
, Statement
*b
)
869 Statement
*WhileStatement::syntaxCopy()
871 WhileStatement
*s
= new WhileStatement(loc
, condition
->syntaxCopy(), body
? body
->syntaxCopy() : NULL
);
876 Statement
*WhileStatement::semantic(Scope
*sc
)
879 if (condition
->op
== TOKmatch
)
881 /* Rewrite while (condition) body as:
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
);
901 condition
= condition
->semantic(sc
);
902 condition
= resolveProperties(sc
, condition
);
903 condition
= condition
->optimize(WANTvalue
);
904 condition
= condition
->checkToBoolean();
908 Scope
*scd
= sc
->push();
910 scd
->scontinue
= this;
912 body
= body
->semantic(scd
);
920 int WhileStatement::hasBreak()
925 int WhileStatement::hasContinue()
930 int WhileStatement::usesEH()
932 return body
? body
->usesEH() : 0;
935 int WhileStatement::fallOffEnd()
942 int WhileStatement::comeFrom()
945 return body
->comeFrom();
949 void WhileStatement::toCBuffer(OutBuffer
*buf
, HdrGenState
*hgs
)
951 buf
->writestring("while (");
952 condition
->toCBuffer(buf
, hgs
);
956 body
->toCBuffer(buf
, hgs
);
959 /******************************** DoStatement ***************************/
961 DoStatement::DoStatement(Loc loc
, Statement
*b
, Expression
*c
)
968 Statement
*DoStatement::syntaxCopy()
970 DoStatement
*s
= new DoStatement(loc
, body
? body
->syntaxCopy() : NULL
, condition
->syntaxCopy());
975 Statement
*DoStatement::semantic(Scope
*sc
)
979 body
= body
->semanticScope(sc
, this, this);
981 condition
= condition
->semantic(sc
);
982 condition
= resolveProperties(sc
, condition
);
983 condition
= condition
->optimize(WANTvalue
);
985 condition
= condition
->checkToBoolean();
990 int DoStatement::hasBreak()
995 int DoStatement::hasContinue()
1000 int DoStatement::usesEH()
1002 return body
? body
->usesEH() : 0;
1005 int DoStatement::fallOffEnd()
1012 int DoStatement::comeFrom()
1015 return body
->comeFrom();
1019 void DoStatement::toCBuffer(OutBuffer
*buf
, HdrGenState
*hgs
)
1021 buf
->writestring("do");
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
)
1036 this->condition
= condition
;
1037 this->increment
= increment
;
1041 Statement
*ForStatement::syntaxCopy()
1043 Statement
*i
= NULL
;
1045 i
= init
->syntaxCopy();
1046 Expression
*c
= NULL
;
1048 c
= condition
->syntaxCopy();
1049 Expression
*inc
= NULL
;
1051 inc
= increment
->syntaxCopy();
1052 ForStatement
*s
= new ForStatement(loc
, i
, c
, inc
, body
->syntaxCopy());
1056 Statement
*ForStatement::semantic(Scope
*sc
)
1058 ScopeDsymbol
*sym
= new ScopeDsymbol();
1059 sym
->parent
= sc
->scopesym
;
1062 init
= init
->semantic(sc
);
1064 // Use a default value
1065 condition
= new IntegerExp(loc
, 1, Type::tboolean
);
1067 condition
= condition
->semantic(sc
);
1068 condition
= resolveProperties(sc
, condition
);
1069 condition
= condition
->optimize(WANTvalue
);
1070 condition
= condition
->checkToBoolean();
1072 increment
= increment
->semantic(sc
);
1075 sc
->scontinue
= this;
1076 body
= body
->semantic(sc
);
1083 void ForStatement::scopeCode(Statement
**sentry
, Statement
**sexception
, Statement
**sfinally
)
1085 //printf("ForStatement::scopeCode()\n");
1088 init
->scopeCode(sentry
, sexception
, sfinally
);
1090 Statement::scopeCode(sentry
, sexception
, sfinally
);
1093 int ForStatement::hasBreak()
1095 //printf("ForStatement::hasBreak()\n");
1099 int ForStatement::hasContinue()
1104 int ForStatement::usesEH()
1106 return (init
&& init
->usesEH()) || body
->usesEH();
1109 int ForStatement::fallOffEnd()
1116 int ForStatement::comeFrom()
1118 //printf("ForStatement::comeFrom()\n");
1120 { int result
= body
->comeFrom();
1121 //printf("result = %d\n", result);
1127 void ForStatement::toCBuffer(OutBuffer
*buf
, HdrGenState
*hgs
)
1129 buf
->writestring("for (");
1133 hgs
->FLinit
.decl
= 0;
1134 init
->toCBuffer(buf
, hgs
);
1135 if (hgs
->FLinit
.decl
> 0)
1136 buf
->writebyte(';');
1137 hgs
->FLinit
.decl
= 0;
1141 buf
->writebyte(';');
1143 { buf
->writebyte(' ');
1144 condition
->toCBuffer(buf
, hgs
);
1146 buf
->writebyte(';');
1148 { buf
->writebyte(' ');
1149 increment
->toCBuffer(buf
, hgs
);
1151 buf
->writebyte(')');
1153 buf
->writebyte('{');
1155 body
->toCBuffer(buf
, hgs
);
1156 buf
->writebyte('}');
1160 /******************************** ForeachStatement ***************************/
1162 ForeachStatement::ForeachStatement(Loc loc
, enum TOK op
, Arguments
*arguments
,
1163 Expression
*aggr
, Statement
*body
)
1167 this->arguments
= arguments
;
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
);
1186 Statement
*ForeachStatement::semantic(Scope
*sc
)
1188 //printf("ForeachStatement::semantic() %p\n", this);
1190 Statement
*s
= this;
1191 int dim
= arguments
->dim
;
1193 TypeAArray
*taa
= NULL
;
1200 func
= func
->fes
->func
;
1202 aggr
= aggr
->semantic(sc
);
1203 aggr
= resolveProperties(sc
, aggr
);
1206 error("invalid foreach aggregate %s", aggr
->toChars());
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");
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");
1231 TypeTuple
*tuple
= (TypeTuple
*)tab
;
1232 Statements
*statements
= new Statements();
1233 //printf("aggr: op = %d, %s\n", aggr->op, aggr->toChars());
1235 TupleExp
*te
= NULL
;
1236 if (aggr
->op
== TOKtuple
) // expression tuple
1237 { te
= (TupleExp
*)aggr
;
1240 else if (aggr
->op
== TOKtype
) // type tuple
1242 n
= Argument::dim(tuple
->arguments
);
1246 for (size_t j
= 0; j
< n
; j
++)
1247 { size_t k
= (op
== TOKforeach
) ? j
: n
- 1 - j
;
1251 e
= (Expression
*)te
->exps
->data
[k
];
1253 t
= Argument::getNth(tuple
->arguments
, k
)->type
;
1254 Argument
*arg
= (Argument
*)arguments
->data
[0];
1255 Statements
*st
= new Statements();
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
1277 if (arg
->storageClass
& (STCout
| STCref
| STClazy
))
1278 error("no storage class for value %s", arg
->ident
->toChars());
1282 if (e
->type
->toBasetype()->ty
== Tfunction
&&
1284 { VarExp
*ve
= (VarExp
*)e
;
1285 var
= new AliasDeclaration(loc
, arg
->ident
, ve
->var
);
1289 arg
->type
= e
->type
;
1290 Initializer
*ie
= new ExpInitializer(0, e
);
1291 VarDeclaration
*v
= new VarDeclaration(loc
, arg
->type
, arg
->ident
, ie
);
1293 v
->storage_class
|= STCconst
;
1296 v
->storage_class
|= STCfinal
;
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
);
1319 for (i
= 0; i
< dim
; i
++)
1320 { Argument
*arg
= (Argument
*)arguments
->data
[i
];
1323 error("cannot infer type for %s", arg
->ident
->toChars());
1328 sym
= new ScopeDsymbol();
1329 sym
->parent
= sc
->scopesym
;
1338 if (dim
< 1 || dim
> 2)
1340 error("only one or two arguments for array foreach");
1344 /* Look for special case of parsing char types out of char type
1347 tn
= tab
->nextOf()->toBasetype();
1348 if (tn
->ty
== Tchar
|| tn
->ty
== Twchar
|| tn
->ty
== Tdchar
)
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");
1361 { arg
= (Argument
*)arguments
->data
[0];
1362 if (arg
->storageClass
& STCref
)
1363 error("foreach: key cannot be ref");
1369 for (i
= 0; i
< dim
; i
++)
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
);
1378 DeclarationExp
*de
= new DeclarationExp(loc
, var
);
1382 if (!sc
->insert(var
))
1383 error("%s already defined", var
->ident
->toChars());
1385 if (dim
== 2 && i
== 0)
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());
1400 error("foreach: %s is not an array of %s", tab
->toChars(), value
->type
->toChars());
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");
1418 taa
= (TypeAArray
*)tab
;
1419 if (dim
< 1 || dim
> 2)
1421 error("only one or two arguments for associative array foreach");
1424 if (op
== TOKforeach_reverse
)
1426 error("no reverse iteration on associative arrays");
1434 { FuncDeclaration
*fdapply
;
1438 FuncLiteralDeclaration
*fld
;
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
);
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
)
1471 { // Make a copy of the ref argument so it isn't
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
);
1488 t
= new TypeFunction(args
, Type::tint32
, 0, LINKd
);
1489 fld
= new FuncLiteralDeclaration(loc
, 0, t
, TOKdelegate
, this);
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
1502 s
= new ReturnStatement(0, new IntegerExp(cases
.dim
+ 1));
1503 cs
->statements
->data
[0] = (void *)s
;
1507 if (tab
->ty
== Taarray
)
1510 Argument
*arg
= (Argument
*)arguments
->data
[0];
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());
1523 * _aaApply(aggr, keysize, flde)
1526 fdapply
= FuncDeclaration::genCfunc(Type::tint32
, "_aaApply2",
1527 Type::tvoid
->arrayOf(), Type::tsize_t
, flde
->type
); // flde->type is not generic
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();
1534 size_t keysize
= taa
->key
->size();
1535 keysize
= (keysize
+ (PTRSIZE
-1)) & ~(PTRSIZE
-1);
1536 exps
->push(new IntegerExp(0, keysize
, Type::tsize_t
));
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
)
1544 * _aApply(aggr, flde)
1546 static char fntab
[9][3] =
1551 char fdname
[7+1+2+ sizeof(dim
)*3 + 1];
1556 case Tchar
: flag
= 0; break;
1557 case Twchar
: flag
= 3; break;
1558 case Tdchar
: flag
= 6; break;
1563 case Tchar
: flag
+= 0; break;
1564 case Twchar
: flag
+= 1; break;
1565 case Tdchar
: flag
+= 2; break;
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());
1580 e
= new CallExp(loc
, ec
, exps
);
1581 e
->type
= Type::tint32
; // don't run semantic() on e
1583 else if (tab
->ty
== Tdelegate
)
1588 Expressions
*exps
= new Expressions();
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());
1600 ec
= new DotIdExp(loc
, aggr
,
1601 (op
== TOKforeach_reverse
) ? Id::applyReverse
1603 Expressions
*exps
= new Expressions();
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());
1612 // Easy case, a clean exit from the loop
1613 s
= new ExpStatement(loc
, e
);
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
);
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
);
1632 s
= new CompoundStatement(loc
, a
);
1633 s
= new SwitchStatement(loc
, e
, s
);
1634 s
= s
->semantic(sc
);
1640 error("foreach: %s is not an aggregate type", aggr
->type
->toChars());
1648 int ForeachStatement::hasBreak()
1653 int ForeachStatement::hasContinue()
1658 int ForeachStatement::usesEH()
1660 return body
->usesEH();
1663 int ForeachStatement::fallOffEnd()
1670 int ForeachStatement::comeFrom()
1673 return body
->comeFrom();
1677 void ForeachStatement::toCBuffer(OutBuffer
*buf
, HdrGenState
*hgs
)
1679 buf
->writestring(Token::toChars(op
));
1680 buf
->writestring(" (");
1682 for (int i
= 0; i
< arguments
->dim
; i
++)
1684 Argument
*a
= (Argument
*)arguments
->data
[i
];
1686 buf
->writestring(", ");
1687 if (a
->storageClass
& STCref
)
1688 buf
->writestring((global
.params
.Dversion
== 1)
1689 ? (char*)"inout " : (char*)"ref ");
1691 a
->type
->toCBuffer(buf
, a
->ident
, hgs
);
1693 buf
->writestring(a
->ident
->toChars());
1695 buf
->writestring("; ");
1696 aggr
->toCBuffer(buf
, hgs
);
1697 buf
->writebyte(')');
1699 buf
->writebyte('{');
1702 body
->toCBuffer(buf
, hgs
);
1703 buf
->writebyte('}');
1707 /******************************** IfStatement ***************************/
1709 IfStatement::IfStatement(Loc loc
, Argument
*arg
, Expression
*condition
, Statement
*ifbody
, Statement
*elsebody
)
1713 this->condition
= condition
;
1714 this->ifbody
= ifbody
;
1715 this->elsebody
= elsebody
;
1719 Statement
*IfStatement::syntaxCopy()
1721 Statement
*i
= NULL
;
1723 i
= ifbody
->syntaxCopy();
1725 Statement
*e
= NULL
;
1727 e
= elsebody
->syntaxCopy();
1729 Argument
*a
= arg
? arg
->syntaxCopy() : NULL
;
1730 IfStatement
*s
= new IfStatement(loc
, a
, condition
->syntaxCopy(), i
, e
);
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
;
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
);
1761 match
->semantic(scd
);
1762 if (!scd
->insert(match
))
1764 match
->parent
= sc
->func
;
1769 VarExp
*v
= new VarExp(0, match
);
1770 condition
= new AssignExp(loc
, v
, condition
);
1771 condition
= condition
->semantic(scd
);
1775 ifbody
= ifbody
->semantic(scd
);
1778 cs1
= sc
->callSuper
;
1779 sc
->callSuper
= cs0
;
1781 elsebody
= elsebody
->semanticScope(sc
, NULL
, NULL
);
1782 sc
->mergeCallSuper(loc
, cs1
);
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())
1801 void IfStatement::toCBuffer(OutBuffer
*buf
, HdrGenState
*hgs
)
1803 buf
->writestring("if (");
1807 arg
->type
->toCBuffer(buf
, arg
->ident
, hgs
);
1809 buf
->writestring(arg
->ident
->toChars());
1810 buf
->writebyte(';');
1812 condition
->toCBuffer(buf
, hgs
);
1813 buf
->writebyte(')');
1815 ifbody
->toCBuffer(buf
, hgs
);
1817 { buf
->writestring("else");
1819 elsebody
->toCBuffer(buf
, hgs
);
1823 /******************************** ConditionalStatement ***************************/
1825 ConditionalStatement::ConditionalStatement(Loc loc
, Condition
*condition
, Statement
*ifbody
, Statement
*elsebody
)
1828 this->condition
= condition
;
1829 this->ifbody
= ifbody
;
1830 this->elsebody
= elsebody
;
1833 Statement
*ConditionalStatement::syntaxCopy()
1835 Statement
*e
= NULL
;
1837 e
= elsebody
->syntaxCopy();
1838 ConditionalStatement
*s
= new ConditionalStatement(loc
,
1839 condition
->syntaxCopy(), ifbody
->syntaxCopy(), e
);
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
);
1858 elsebody
= elsebody
->semantic(sc
);
1863 Statements
*ConditionalStatement::flatten(Scope
*sc
)
1867 if (condition
->include(sc
, NULL
))
1872 Statements
*a
= new Statements();
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
);
1887 ifbody
->toCBuffer(buf
, hgs
);
1890 buf
->writestring("else");
1892 elsebody
->toCBuffer(buf
, hgs
);
1898 /******************************** PragmaStatement ***************************/
1900 PragmaStatement::PragmaStatement(Loc loc
, Identifier
*ident
, Expressions
*args
, Statement
*body
)
1903 this->ident
= ident
;
1908 Statement
*PragmaStatement::syntaxCopy()
1910 Statement
*b
= NULL
;
1912 b
= body
->syntaxCopy();
1913 PragmaStatement
*s
= new PragmaStatement(loc
,
1914 ident
, Expression::arraySyntaxCopy(args
), b
);
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
)
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
);
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");
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
);
1962 printf("library %s\n", name
);
1968 error("unrecognized pragma(%s)", ident
->toChars());
1972 body
= body
->semantic(sc
);
1977 int PragmaStatement::usesEH()
1979 return body
&& body
->usesEH();
1982 int PragmaStatement::fallOffEnd()
1985 return body
->fallOffEnd();
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(')');
2002 buf
->writeByte('{');
2005 body
->toCBuffer(buf
, hgs
);
2007 buf
->writeByte('}');
2012 buf
->writeByte(';');
2018 /******************************** LogStatement ***************************/
2020 LogStatement::LogStatement(Loc loc
, int level
, Expressions
*args
)
2023 this->level
= level
;
2027 Statement
*LogStatement::semantic(Scope
*sc
)
2029 Expression
*logger
= new DotIdExp(loc
, new GetLoggerExp(loc
), Id::log
);
2032 for (Dsymbol
*s
= sc
->parent
; s
; s
= s
->parent
)
2034 ClassDeclaration
*cd
;
2035 StructDeclaration
*sd
;
2037 cd
= s
->isClassDeclaration();
2046 // We're a top-level function. Generate log messages from the module
2047 args
->shift(new StringExp(loc
, strdup(sc
->module
->ident
->string
)));
2049 args
->shift(new DotIdExp(loc
, new TypeExp(loc
, type
), Id::classinfo
));
2052 args
->shift(new IntegerExp(loc
, level
, Type::tint32
));
2053 Expression
*callLogger
= new CallExp(loc
, logger
, args
);
2055 Statement
*s
= new ExpStatement(loc
, callLogger
);
2057 return s
->semantic(sc
);
2060 void LogStatement::toCBuffer(OutBuffer
*buf
, HdrGenState
*hgs
)
2064 case 10: l
= "log_debug"; break;
2065 case 20: l
= "log_info"; break;
2066 case 30: l
= "log_warning"; break;
2067 case 40: l
= "log_error"; break;
2069 error("Unknown log level %d", level
);
2072 buf
->writestring(l
);
2073 buf
->writeByte('(');
2074 argsToCBuffer(buf
, args
, hgs
);
2075 buf
->writeByte(')');
2079 /******************************** StaticAssertStatement ***************************/
2081 StaticAssertStatement::StaticAssertStatement(StaticAssert
*sa
)
2082 : Statement(sa
->loc
)
2087 Statement
*StaticAssertStatement::syntaxCopy()
2089 StaticAssertStatement
*s
= new StaticAssertStatement((StaticAssert
*)sa
->syntaxCopy(NULL
));
2093 Statement
*StaticAssertStatement::semantic(Scope
*sc
)
2099 void StaticAssertStatement::toCBuffer(OutBuffer
*buf
, HdrGenState
*hgs
)
2101 sa
->toCBuffer(buf
, hgs
);
2105 /******************************** SwitchStatement ***************************/
2107 SwitchStatement::SwitchStatement(Loc loc
, Expression
*c
, Statement
*b
)
2117 Statement
*SwitchStatement::syntaxCopy()
2119 SwitchStatement
*s
= new SwitchStatement(loc
,
2120 condition
->syntaxCopy(), body
->syntaxCopy());
2124 Statement
*SwitchStatement::semantic(Scope
*sc
)
2126 //printf("SwitchStatement::semantic(%p)\n", this);
2127 assert(!cases
); // ensure semantic() is only run once
2128 condition
= condition
->semantic(sc
);
2129 condition
= resolveProperties(sc
, condition
);
2130 if (condition
->type
->isString())
2132 // If it's not an array, cast it to one
2133 if (condition
->type
->ty
!= Tarray
)
2135 condition
= condition
->implicitCastTo(sc
, condition
->type
->nextOf()->arrayOf());
2139 { condition
= condition
->integralPromotions(sc
);
2140 condition
->checkIntegral();
2142 condition
= condition
->optimize(WANTvalue
);
2148 cases
= new Array();
2149 sc
->noctor
++; // BUG: should use Scope::mergeCallSuper() for each case instead
2150 body
= body
->semantic(sc
);
2153 // Resolve any goto case's with exp
2154 for (int i
= 0; i
< gotoCases
.dim
; i
++)
2156 GotoCaseStatement
*gcs
= (GotoCaseStatement
*)gotoCases
.data
[i
];
2160 gcs
->error("no case statement following goto case;");
2164 for (Scope
*scx
= sc
; scx
; scx
= scx
->enclosing
)
2168 for (int j
= 0; j
< scx
->sw
->cases
->dim
; j
++)
2170 CaseStatement
*cs
= (CaseStatement
*)scx
->sw
->cases
->data
[j
];
2172 if (cs
->exp
->equals(gcs
->exp
))
2179 gcs
->error("case %s not found", gcs
->exp
->toChars());
2185 if (!sc
->sw
->sdefault
)
2188 if (global
.params
.warnings
)
2189 { fprintf(stdmsg
, "warning - ");
2190 error("switch statement has no default");
2193 // Generate runtime error if the default is hit
2194 Statements
*a
= new Statements();
2195 CompoundStatement
*cs
;
2198 if (global
.params
.useSwitchError
)
2199 s
= new SwitchErrorStatement(loc
);
2201 { Expression
*e
= new HaltExp(loc
);
2202 s
= new ExpStatement(loc
, e
);
2207 a
->push(new BreakStatement(loc
, NULL
));
2208 sc
->sw
->sdefault
= new DefaultStatement(loc
, s
);
2209 a
->push(sc
->sw
->sdefault
);
2210 cs
= new CompoundStatement(loc
, a
);
2218 int SwitchStatement::hasBreak()
2223 int SwitchStatement::usesEH()
2225 return body
? body
->usesEH() : 0;
2228 int SwitchStatement::fallOffEnd()
2232 return TRUE
; // need to do this better
2235 void SwitchStatement::toCBuffer(OutBuffer
*buf
, HdrGenState
*hgs
)
2237 buf
->writestring("switch (");
2238 condition
->toCBuffer(buf
, hgs
);
2239 buf
->writebyte(')');
2243 if (!body
->isScopeStatement())
2244 { buf
->writebyte('{');
2246 body
->toCBuffer(buf
, hgs
);
2247 buf
->writebyte('}');
2252 body
->toCBuffer(buf
, hgs
);
2257 /******************************** CaseStatement ***************************/
2259 CaseStatement::CaseStatement(Loc loc
, Expression
*exp
, Statement
*s
)
2263 this->statement
= s
;
2267 Statement
*CaseStatement::syntaxCopy()
2269 CaseStatement
*s
= new CaseStatement(loc
, exp
->syntaxCopy(), statement
->syntaxCopy());
2273 Statement
*CaseStatement::semantic(Scope
*sc
)
2274 { SwitchStatement
*sw
= sc
->sw
;
2276 //printf("CaseStatement::semantic() %s\n", toChars());
2277 exp
= exp
->semantic(sc
);
2281 exp
= exp
->implicitCastTo(sc
, sw
->condition
->type
);
2282 exp
= exp
->optimize(WANTvalue
| WANTinterpret
);
2283 if (exp
->op
!= TOKstring
&& exp
->op
!= TOKint64
)
2285 error("case must be a string or an integral constant, not %s", exp
->toChars());
2286 exp
= new IntegerExp(0);
2289 for (i
= 0; i
< sw
->cases
->dim
; i
++)
2291 CaseStatement
*cs
= (CaseStatement
*)sw
->cases
->data
[i
];
2293 //printf("comparing '%s' with '%s'\n", exp->toChars(), cs->exp->toChars());
2294 if (cs
->exp
->equals(exp
))
2295 { error("duplicate case %s in switch statement", exp
->toChars());
2300 sw
->cases
->push(this);
2302 // Resolve any goto case's with no exp to this case statement
2303 for (i
= 0; i
< sw
->gotoCases
.dim
; i
++)
2305 GotoCaseStatement
*gcs
= (GotoCaseStatement
*)sw
->gotoCases
.data
[i
];
2310 sw
->gotoCases
.remove(i
); // remove from array
2315 error("case not in switch statement");
2316 statement
= statement
->semantic(sc
);
2320 int CaseStatement::compare(Object
*obj
)
2322 // Sort cases so we can do an efficient lookup
2323 CaseStatement
*cs2
= (CaseStatement
*)(obj
);
2325 return exp
->compare(cs2
->exp
);
2328 int CaseStatement::usesEH()
2330 return statement
->usesEH();
2333 int CaseStatement::fallOffEnd()
2335 return statement
->fallOffEnd();
2338 int CaseStatement::comeFrom()
2343 void CaseStatement::toCBuffer(OutBuffer
*buf
, HdrGenState
*hgs
)
2345 buf
->writestring("case ");
2346 exp
->toCBuffer(buf
, hgs
);
2347 buf
->writebyte(':');
2349 statement
->toCBuffer(buf
, hgs
);
2352 /******************************** DefaultStatement ***************************/
2354 DefaultStatement::DefaultStatement(Loc loc
, Statement
*s
)
2357 this->statement
= s
;
2363 Statement
*DefaultStatement::syntaxCopy()
2365 DefaultStatement
*s
= new DefaultStatement(loc
, statement
->syntaxCopy());
2369 Statement
*DefaultStatement::semantic(Scope
*sc
)
2373 if (sc
->sw
->sdefault
)
2375 error("switch statement already has a default");
2377 sc
->sw
->sdefault
= this;
2380 error("default not in switch statement");
2381 statement
= statement
->semantic(sc
);
2385 int DefaultStatement::usesEH()
2387 return statement
->usesEH();
2390 int DefaultStatement::fallOffEnd()
2392 return statement
->fallOffEnd();
2395 int DefaultStatement::comeFrom()
2400 void DefaultStatement::toCBuffer(OutBuffer
*buf
, HdrGenState
*hgs
)
2402 buf
->writestring("default:\n");
2403 statement
->toCBuffer(buf
, hgs
);
2406 /******************************** GotoDefaultStatement ***************************/
2408 GotoDefaultStatement::GotoDefaultStatement(Loc loc
)
2414 Statement
*GotoDefaultStatement::syntaxCopy()
2416 GotoDefaultStatement
*s
= new GotoDefaultStatement(loc
);
2420 Statement
*GotoDefaultStatement::semantic(Scope
*sc
)
2424 error("goto default not in switch statement");
2428 int GotoDefaultStatement::fallOffEnd()
2433 void GotoDefaultStatement::toCBuffer(OutBuffer
*buf
, HdrGenState
*hgs
)
2435 buf
->writestring("goto default;\n");
2438 /******************************** GotoCaseStatement ***************************/
2440 GotoCaseStatement::GotoCaseStatement(Loc loc
, Expression
*exp
)
2447 Statement
*GotoCaseStatement::syntaxCopy()
2449 Expression
*e
= exp
? exp
->syntaxCopy() : NULL
;
2450 GotoCaseStatement
*s
= new GotoCaseStatement(loc
, e
);
2454 Statement
*GotoCaseStatement::semantic(Scope
*sc
)
2457 exp
= exp
->semantic(sc
);
2460 error("goto case not in switch statement");
2463 sc
->sw
->gotoCases
.push(this);
2466 exp
= exp
->implicitCastTo(sc
, sc
->sw
->condition
->type
);
2467 exp
= exp
->optimize(WANTvalue
);
2473 int GotoCaseStatement::fallOffEnd()
2478 void GotoCaseStatement::toCBuffer(OutBuffer
*buf
, HdrGenState
*hgs
)
2480 buf
->writestring("goto case");
2482 { buf
->writebyte(' ');
2483 exp
->toCBuffer(buf
, hgs
);
2485 buf
->writebyte(';');
2489 /******************************** SwitchErrorStatement ***************************/
2491 SwitchErrorStatement::SwitchErrorStatement(Loc loc
)
2496 int SwitchErrorStatement::fallOffEnd()
2501 void SwitchErrorStatement::toCBuffer(OutBuffer
*buf
, HdrGenState
*hgs
)
2503 buf
->writestring("SwitchErrorStatement::toCBuffer()");
2507 /******************************** ReturnStatement ***************************/
2509 ReturnStatement::ReturnStatement(Loc loc
, Expression
*exp
)
2515 Statement
*ReturnStatement::syntaxCopy()
2517 Expression
*e
= NULL
;
2519 e
= exp
->syntaxCopy();
2520 ReturnStatement
*s
= new ReturnStatement(loc
, e
);
2524 Statement
*ReturnStatement::semantic(Scope
*sc
)
2526 //printf("ReturnStatement::semantic() %s\n", toChars());
2528 FuncDeclaration
*fd
= sc
->parent
->isFuncDeclaration();
2534 // Find scope of function foreach is in
2535 for (; 1; scx
= scx
->enclosing
)
2538 if (scx
->func
!= fd
)
2539 { fd
= scx
->func
; // fd is now function enclosing foreach
2545 Type
*tret
= fd
->type
->nextOf();
2547 tret
= fd
->tintro
->nextOf();
2551 tbret
= tret
->toBasetype();
2553 // main() returns 0, even if it returns void
2554 if (!exp
&& (!tbret
|| tbret
->ty
== Tvoid
) && fd
->isMain())
2556 exp
= new IntegerExp(0);
2559 if (sc
->incontract
|| scx
->incontract
)
2560 error("return statements cannot be in contracts");
2561 if (sc
->tf
|| scx
->tf
)
2562 error("return statements cannot be in finally, scope(exit) or scope(success) bodies");
2564 if (fd
->isCtorDeclaration())
2566 // Constructors implicitly do:
2568 if (exp
&& exp
->op
!= TOKthis
)
2569 error("cannot return expression from constructor");
2570 exp
= new ThisExp(0);
2578 fd
->hasReturnExp
|= 1;
2580 exp
= exp
->semantic(sc
);
2581 exp
= resolveProperties(sc
, exp
);
2582 exp
= exp
->optimize(WANTvalue
);
2584 if (fd
->nrvo_can
&& exp
->op
== TOKvar
)
2585 { VarExp
*ve
= (VarExp
*)exp
;
2586 VarDeclaration
*v
= ve
->var
->isVarDeclaration();
2588 if (!v
|| v
->isOut() || v
->isRef())
2590 else if (fd
->nrvo_var
== NULL
)
2591 { if (!v
->isDataseg() && !v
->isParameter() && v
->toParent2() == fd
)
2596 else if (fd
->nrvo_var
!= v
)
2602 if (fd
->returnLabel
&& tbret
->ty
!= Tvoid
)
2605 else if (fd
->inferRetType
)
2607 if (fd
->type
->nextOf())
2609 if (!exp
->type
->equals(fd
->type
->nextOf()))
2610 error("mismatched function return type inference of %s and %s",
2611 exp
->type
->toChars(), fd
->type
->nextOf()->toChars());
2615 fd
->type
->next
= exp
->type
;
2616 fd
->type
= fd
->type
->semantic(loc
, sc
);
2618 { tret
= fd
->type
->nextOf();
2619 tbret
= tret
->toBasetype();
2623 else if (tbret
->ty
!= Tvoid
)
2625 exp
= exp
->implicitCastTo(sc
, tret
);
2628 else if (fd
->inferRetType
)
2630 if (fd
->type
->nextOf())
2632 if (fd
->type
->nextOf()->ty
!= Tvoid
)
2633 error("mismatched function return type inference of void and %s",
2634 fd
->type
->nextOf()->toChars());
2638 fd
->type
->next
= Type::tvoid
;
2639 fd
->type
= fd
->type
->semantic(loc
, sc
);
2641 { tret
= Type::tvoid
;
2646 else if (tbret
->ty
!= Tvoid
) // if non-void return
2647 error("return expression expected");
2653 if (exp
&& !implicit0
)
2655 exp
= exp
->implicitCastTo(sc
, tret
);
2657 if (!exp
|| exp
->op
== TOKint64
|| exp
->op
== TOKfloat64
||
2658 exp
->op
== TOKimaginary80
|| exp
->op
== TOKcomplex80
||
2659 exp
->op
== TOKthis
|| exp
->op
== TOKsuper
|| exp
->op
== TOKnull
||
2660 exp
->op
== TOKstring
)
2662 sc
->fes
->cases
.push(this);
2663 s
= new ReturnStatement(0, new IntegerExp(sc
->fes
->cases
.dim
+ 1));
2665 else if (fd
->type
->nextOf()->toBasetype() == Type::tvoid
)
2670 s
= new ReturnStatement(0, NULL
);
2671 sc
->fes
->cases
.push(s
);
2673 // Construct: { exp; return cases.dim + 1; }
2674 s1
= new ExpStatement(loc
, exp
);
2675 s2
= new ReturnStatement(0, new IntegerExp(sc
->fes
->cases
.dim
+ 1));
2676 s
= new CompoundStatement(loc
, s1
, s2
);
2684 // Construct: return vresult;
2686 { VarDeclaration
*v
;
2688 v
= new VarDeclaration(loc
, tret
, Id::result
, NULL
);
2691 if (!scx
->insert(v
))
2697 v
= new VarExp(0, fd
->vresult
);
2698 s
= new ReturnStatement(0, v
);
2699 sc
->fes
->cases
.push(s
);
2701 // Construct: { vresult = exp; return cases.dim + 1; }
2702 v
= new VarExp(0, fd
->vresult
);
2703 exp
= new AssignExp(loc
, v
, exp
);
2704 exp
= exp
->semantic(sc
);
2705 s1
= new ExpStatement(loc
, exp
);
2706 s2
= new ReturnStatement(0, new IntegerExp(sc
->fes
->cases
.dim
+ 1));
2707 s
= new CompoundStatement(loc
, s1
, s2
);
2714 if (fd
->returnLabel
&& tbret
->ty
!= Tvoid
)
2716 assert(fd
->vresult
);
2717 VarExp
*v
= new VarExp(0, fd
->vresult
);
2719 exp
= new AssignExp(loc
, v
, exp
);
2720 exp
= exp
->semantic(sc
);
2727 /* BUG: need to issue an error on:
2734 if (sc
->callSuper
& CSXany_ctor
&&
2735 !(sc
->callSuper
& (CSXthis_ctor
| CSXsuper_ctor
)))
2736 error("return without calling constructor");
2738 sc
->callSuper
|= CSXreturn
;
2740 // See if all returns are instead to be replaced with a goto returnLabel;
2741 if (fd
->returnLabel
)
2743 GotoStatement
*gs
= new GotoStatement(loc
, Id::returnLabel
);
2745 gs
->label
= fd
->returnLabel
;
2749 s
= new ExpStatement(0, exp
);
2750 return new CompoundStatement(loc
, s
, gs
);
2755 if (exp
&& tbret
->ty
== Tvoid
&& !fd
->isMain())
2758 s
= new ExpStatement(loc
, exp
);
2761 return new CompoundStatement(loc
, s
, this);
2767 int ReturnStatement::fallOffEnd()
2772 void ReturnStatement::toCBuffer(OutBuffer
*buf
, HdrGenState
*hgs
)
2774 buf
->printf("return ");
2776 exp
->toCBuffer(buf
, hgs
);
2777 buf
->writeByte(';');
2781 /******************************** BreakStatement ***************************/
2783 BreakStatement::BreakStatement(Loc loc
, Identifier
*ident
)
2786 this->ident
= ident
;
2789 Statement
*BreakStatement::syntaxCopy()
2791 BreakStatement
*s
= new BreakStatement(loc
, ident
);
2795 Statement
*BreakStatement::semantic(Scope
*sc
)
2798 // break Identifier;
2802 FuncDeclaration
*thisfunc
= sc
->func
;
2804 for (scx
= sc
; scx
; scx
= scx
->enclosing
)
2808 if (scx
->func
!= thisfunc
) // if in enclosing function
2810 if (sc
->fes
) // if this is the body of a foreach
2812 /* Post this statement to the fes, and replace
2813 * it with a return value that caller will put into
2814 * a switch. Caller will figure out where the break
2815 * label actually is.
2816 * Case numbers start with 2, not 0, as 0 is continue
2820 sc
->fes
->cases
.push(this);
2821 s
= new ReturnStatement(0, new IntegerExp(sc
->fes
->cases
.dim
+ 1));
2824 break; // can't break to it
2828 if (ls
&& ls
->ident
== ident
)
2830 Statement
*s
= ls
->statement
;
2833 error("label '%s' has no break", ident
->toChars());
2834 if (ls
->tf
!= sc
->tf
)
2835 error("cannot break out of finally block");
2839 error("enclosing label '%s' for break not found", ident
->toChars());
2841 else if (!sc
->sbreak
)
2846 // Replace break; with return 1;
2847 s
= new ReturnStatement(0, new IntegerExp(1));
2850 error("break is not inside a loop or switch");
2855 int BreakStatement::fallOffEnd()
2860 void BreakStatement::toCBuffer(OutBuffer
*buf
, HdrGenState
*hgs
)
2862 buf
->writestring("break");
2864 { buf
->writebyte(' ');
2865 buf
->writestring(ident
->toChars());
2867 buf
->writebyte(';');
2871 /******************************** ContinueStatement ***************************/
2873 ContinueStatement::ContinueStatement(Loc loc
, Identifier
*ident
)
2876 this->ident
= ident
;
2879 Statement
*ContinueStatement::syntaxCopy()
2881 ContinueStatement
*s
= new ContinueStatement(loc
, ident
);
2885 Statement
*ContinueStatement::semantic(Scope
*sc
)
2887 //printf("ContinueStatement::semantic() %p\n", this);
2891 FuncDeclaration
*thisfunc
= sc
->func
;
2893 for (scx
= sc
; scx
; scx
= scx
->enclosing
)
2897 if (scx
->func
!= thisfunc
) // if in enclosing function
2899 if (sc
->fes
) // if this is the body of a foreach
2901 for (; scx
; scx
= scx
->enclosing
)
2904 if (ls
&& ls
->ident
== ident
&& ls
->statement
== sc
->fes
)
2906 // Replace continue ident; with return 0;
2907 return new ReturnStatement(0, new IntegerExp(0));
2911 /* Post this statement to the fes, and replace
2912 * it with a return value that caller will put into
2913 * a switch. Caller will figure out where the break
2914 * label actually is.
2915 * Case numbers start with 2, not 0, as 0 is continue
2919 sc
->fes
->cases
.push(this);
2920 s
= new ReturnStatement(0, new IntegerExp(sc
->fes
->cases
.dim
+ 1));
2923 break; // can't continue to it
2927 if (ls
&& ls
->ident
== ident
)
2929 Statement
*s
= ls
->statement
;
2931 if (!s
->hasContinue())
2932 error("label '%s' has no continue", ident
->toChars());
2933 if (ls
->tf
!= sc
->tf
)
2934 error("cannot continue out of finally block");
2938 error("enclosing label '%s' for continue not found", ident
->toChars());
2940 else if (!sc
->scontinue
)
2945 // Replace continue; with return 0;
2946 s
= new ReturnStatement(0, new IntegerExp(0));
2949 error("continue is not inside a loop");
2954 int ContinueStatement::fallOffEnd()
2959 void ContinueStatement::toCBuffer(OutBuffer
*buf
, HdrGenState
*hgs
)
2961 buf
->writestring("continue");
2963 { buf
->writebyte(' ');
2964 buf
->writestring(ident
->toChars());
2966 buf
->writebyte(';');
2970 /******************************** SynchronizedStatement ***************************/
2972 SynchronizedStatement::SynchronizedStatement(Loc loc
, Expression
*exp
, Statement
*body
)
2980 SynchronizedStatement::SynchronizedStatement(Loc loc
, elem
*esync
, Statement
*body
)
2985 this->esync
= esync
;
2988 Statement
*SynchronizedStatement::syntaxCopy()
2990 Expression
*e
= exp
? exp
->syntaxCopy() : NULL
;
2991 SynchronizedStatement
*s
= new SynchronizedStatement(loc
, e
, body
? body
->syntaxCopy() : NULL
);
2995 Statement
*SynchronizedStatement::semantic(Scope
*sc
)
2998 { ClassDeclaration
*cd
;
3000 exp
= exp
->semantic(sc
);
3001 exp
= resolveProperties(sc
, exp
);
3002 cd
= exp
->type
->isClassHandle();
3004 error("can only synchronize on class objects, not '%s'", exp
->type
->toChars());
3005 else if (cd
->isInterfaceDeclaration())
3006 { Type
*t
= new TypeIdentifier(0, Id::Object
);
3008 t
= t
->semantic(0, sc
);
3009 exp
= new CastExp(loc
, exp
, t
);
3010 exp
= exp
->semantic(sc
);
3014 body
= body
->semantic(sc
);
3018 int SynchronizedStatement::hasBreak()
3020 return FALSE
; //TRUE;
3023 int SynchronizedStatement::hasContinue()
3025 return FALSE
; //TRUE;
3028 int SynchronizedStatement::usesEH()
3033 int SynchronizedStatement::fallOffEnd()
3035 return body
? body
->fallOffEnd() : TRUE
;
3038 void SynchronizedStatement::toCBuffer(OutBuffer
*buf
, HdrGenState
*hgs
)
3040 buf
->writestring("synchronized");
3042 { buf
->writebyte('(');
3043 exp
->toCBuffer(buf
, hgs
);
3044 buf
->writebyte(')');
3048 buf
->writebyte(' ');
3049 body
->toCBuffer(buf
, hgs
);
3053 /******************************** WithStatement ***************************/
3055 WithStatement::WithStatement(Loc loc
, Expression
*exp
, Statement
*body
)
3063 Statement
*WithStatement::syntaxCopy()
3065 WithStatement
*s
= new WithStatement(loc
, exp
->syntaxCopy(), body
? body
->syntaxCopy() : NULL
);
3069 Statement
*WithStatement::semantic(Scope
*sc
)
3070 { ScopeDsymbol
*sym
;
3073 //printf("WithStatement::semantic()\n");
3074 exp
= exp
->semantic(sc
);
3075 exp
= resolveProperties(sc
, exp
);
3076 if (exp
->op
== TOKimport
)
3077 { ScopeExp
*es
= (ScopeExp
*)exp
;
3081 else if (exp
->op
== TOKtype
)
3082 { TypeExp
*es
= (TypeExp
*)exp
;
3084 sym
= es
->type
->toDsymbol(sc
)->isScopeDsymbol();
3086 { error("%s has no members", es
->toChars());
3087 body
= body
->semantic(sc
);
3092 { Type
*t
= exp
->type
;
3095 t
= t
->toBasetype();
3096 if (t
->isClassHandle())
3098 init
= new ExpInitializer(loc
, exp
);
3099 wthis
= new VarDeclaration(loc
, exp
->type
, Id::withSym
, init
);
3100 wthis
->semantic(sc
);
3102 sym
= new WithScopeSymbol(this);
3103 sym
->parent
= sc
->scopesym
;
3105 else if (t
->ty
== Tstruct
)
3107 Expression
*e
= exp
->addressOf(sc
);
3108 init
= new ExpInitializer(loc
, e
);
3109 wthis
= new VarDeclaration(loc
, e
->type
, Id::withSym
, init
);
3110 wthis
->semantic(sc
);
3111 sym
= new WithScopeSymbol(this);
3112 sym
->parent
= sc
->scopesym
;
3115 { error("with expressions must be class objects, not '%s'", exp
->type
->toChars());
3122 body
= body
->semantic(sc
);
3129 void WithStatement::toCBuffer(OutBuffer
*buf
, HdrGenState
*hgs
)
3131 buf
->writestring("with (");
3132 exp
->toCBuffer(buf
, hgs
);
3133 buf
->writestring(")\n");
3135 body
->toCBuffer(buf
, hgs
);
3138 int WithStatement::usesEH()
3140 return body
? body
->usesEH() : 0;
3143 int WithStatement::fallOffEnd()
3145 return body
? body
->fallOffEnd() : TRUE
;
3148 /******************************** TryCatchStatement ***************************/
3150 TryCatchStatement::TryCatchStatement(Loc loc
, Statement
*body
, Array
*catches
)
3154 this->catches
= catches
;
3157 Statement
*TryCatchStatement::syntaxCopy()
3159 Array
*a
= new Array();
3160 a
->setDim(catches
->dim
);
3161 for (int i
= 0; i
< a
->dim
; i
++)
3164 c
= (Catch
*)catches
->data
[i
];
3165 c
= c
->syntaxCopy();
3168 TryCatchStatement
*s
= new TryCatchStatement(loc
, body
->syntaxCopy(), a
);
3172 Statement
*TryCatchStatement::semantic(Scope
*sc
)
3174 body
= body
->semanticScope(sc
, NULL
/*this*/, NULL
);
3176 for (int i
= 0; i
< catches
->dim
; i
++)
3179 c
= (Catch
*)catches
->data
[i
];
3182 // Determine if current catch 'hides' any previous catches
3183 for (int j
= 0; j
< i
; j
++)
3184 { Catch
*cj
= (Catch
*)catches
->data
[j
];
3185 char *si
= c
->loc
.toChars();
3186 char *sj
= cj
->loc
.toChars();
3188 if (c
->type
->toBasetype()->implicitConvTo(cj
->type
->toBasetype()))
3189 error("catch at %s hides catch at %s", sj
, si
);
3195 int TryCatchStatement::hasBreak()
3197 return FALSE
; //TRUE;
3200 int TryCatchStatement::usesEH()
3205 int TryCatchStatement::fallOffEnd()
3210 result
= body
->fallOffEnd();
3211 for (int i
= 0; i
< catches
->dim
; i
++)
3214 c
= (Catch
*)catches
->data
[i
];
3216 result
|= c
->handler
->fallOffEnd();
3221 void TryCatchStatement::toCBuffer(OutBuffer
*buf
, HdrGenState
*hgs
)
3223 buf
->writestring("try");
3226 body
->toCBuffer(buf
, hgs
);
3228 for (i
= 0; i
< catches
->dim
; i
++)
3230 Catch
*c
= (Catch
*)catches
->data
[i
];
3231 c
->toCBuffer(buf
, hgs
);
3235 /******************************** Catch ***************************/
3237 Catch::Catch(Loc loc
, Type
*t
, Identifier
*id
, Statement
*handler
)
3239 //printf("Catch(%s, loc = %s)\n", id->toChars(), loc.toChars());
3243 this->handler
= handler
;
3247 Catch
*Catch::syntaxCopy()
3249 Catch
*c
= new Catch(loc
,
3250 (type
? type
->syntaxCopy() : NULL
),
3252 (handler
? handler
->syntaxCopy() : NULL
));
3256 void Catch::semantic(Scope
*sc
)
3257 { ScopeDsymbol
*sym
;
3259 //printf("Catch::semantic(%s)\n", ident->toChars());
3264 /* This is because the _d_local_unwind() gets the stack munged
3265 * up on this. The workaround is to place any try-catches into
3266 * a separate function, and call that.
3267 * To fix, have the compiler automatically convert the finally
3268 * body into a nested function.
3270 error(loc
, "cannot put catch statement inside finally block");
3274 sym
= new ScopeDsymbol();
3275 sym
->parent
= sc
->scopesym
;
3279 type
= new TypeIdentifier(0, Id::Object
);
3280 type
= type
->semantic(loc
, sc
);
3281 if (!type
->toBasetype()->isClassHandle())
3282 error("can only catch class objects, not '%s'", type
->toChars());
3285 var
= new VarDeclaration(loc
, type
, ident
, NULL
);
3286 var
->parent
= sc
->parent
;
3289 handler
= handler
->semantic(sc
);
3294 void Catch::toCBuffer(OutBuffer
*buf
, HdrGenState
*hgs
)
3296 buf
->writestring("catch");
3298 { buf
->writebyte('(');
3299 type
->toCBuffer(buf
, ident
, hgs
);
3300 buf
->writebyte(')');
3303 buf
->writebyte('{');
3305 handler
->toCBuffer(buf
, hgs
);
3306 buf
->writebyte('}');
3310 /****************************** TryFinallyStatement ***************************/
3312 TryFinallyStatement::TryFinallyStatement(Loc loc
, Statement
*body
, Statement
*finalbody
)
3316 this->finalbody
= finalbody
;
3319 Statement
*TryFinallyStatement::syntaxCopy()
3321 TryFinallyStatement
*s
= new TryFinallyStatement(loc
,
3322 body
->syntaxCopy(), finalbody
->syntaxCopy());
3326 Statement
*TryFinallyStatement::semantic(Scope
*sc
)
3328 //printf("TryFinallyStatement::semantic()\n");
3329 body
= body
->semantic(sc
);
3333 sc
->scontinue
= NULL
; // no break or continue out of finally block
3334 finalbody
= finalbody
->semantic(sc
);
3339 void TryFinallyStatement::toCBuffer(OutBuffer
*buf
, HdrGenState
*hgs
)
3341 buf
->printf("try\n{\n");
3342 body
->toCBuffer(buf
, hgs
);
3343 buf
->printf("}\nfinally\n{\n");
3344 finalbody
->toCBuffer(buf
, hgs
);
3345 buf
->writeByte('}');
3349 int TryFinallyStatement::hasBreak()
3351 return FALSE
; //TRUE;
3354 int TryFinallyStatement::hasContinue()
3356 return FALSE
; //TRUE;
3359 int TryFinallyStatement::usesEH()
3364 int TryFinallyStatement::fallOffEnd()
3367 result
= body
? body
->fallOffEnd() : TRUE
;
3369 // result = finalbody->fallOffEnd();
3373 /****************************** OnScopeStatement ***************************/
3375 OnScopeStatement::OnScopeStatement(Loc loc
, TOK tok
, Statement
*statement
)
3379 this->statement
= statement
;
3382 Statement
*OnScopeStatement::syntaxCopy()
3384 OnScopeStatement
*s
= new OnScopeStatement(loc
,
3385 tok
, statement
->syntaxCopy());
3389 Statement
*OnScopeStatement::semantic(Scope
*sc
)
3391 /* semantic is called on results of scopeCode() */
3395 void OnScopeStatement::toCBuffer(OutBuffer
*buf
, HdrGenState
*hgs
)
3397 buf
->writestring(Token::toChars(tok
));
3398 buf
->writebyte(' ');
3399 statement
->toCBuffer(buf
, hgs
);
3402 int OnScopeStatement::usesEH()
3404 return (tok
!= TOKon_scope_success
);
3407 void OnScopeStatement::scopeCode(Statement
**sentry
, Statement
**sexception
, Statement
**sfinally
)
3409 //printf("OnScopeStatement::scopeCode()\n");
3416 case TOKon_scope_exit
:
3417 *sfinally
= statement
;
3420 case TOKon_scope_failure
:
3421 *sexception
= statement
;
3424 case TOKon_scope_success
:
3427 * sentry: int x = 0;
3428 * sexception: x = 1;
3429 * sfinally: if (!x) statement;
3432 char name
[5 + sizeof(num
) * 3 + 1];
3433 sprintf(name
, "__osf%d", ++num
);
3434 Identifier
*id
= Lexer::idPool(name
);
3436 ExpInitializer
*ie
= new ExpInitializer(loc
, new IntegerExp(0));
3437 VarDeclaration
*v
= new VarDeclaration(loc
, Type::tint32
, id
, ie
);
3438 *sentry
= new DeclarationStatement(loc
, v
);
3440 Expression
*e
= new IntegerExp(1);
3441 e
= new AssignExp(0, new VarExp(0, v
), e
);
3442 *sexception
= new ExpStatement(0, e
);
3444 e
= new VarExp(0, v
);
3445 e
= new NotExp(0, e
);
3446 *sfinally
= new IfStatement(0, NULL
, e
, statement
, NULL
);
3456 /******************************** ThrowStatement ***************************/
3458 ThrowStatement::ThrowStatement(Loc loc
, Expression
*exp
)
3464 Statement
*ThrowStatement::syntaxCopy()
3466 ThrowStatement
*s
= new ThrowStatement(loc
, exp
->syntaxCopy());
3470 Statement
*ThrowStatement::semantic(Scope
*sc
)
3472 //printf("ThrowStatement::semantic()\n");
3474 FuncDeclaration
*fd
= sc
->parent
->isFuncDeclaration();
3475 fd
->hasReturnExp
|= 2;
3478 error("Throw statements cannot be in contracts");
3479 exp
= exp
->semantic(sc
);
3480 exp
= resolveProperties(sc
, exp
);
3481 if (!exp
->type
->toBasetype()->isClassHandle())
3482 error("can only throw class objects, not type %s", exp
->type
->toChars());
3486 int ThrowStatement::fallOffEnd()
3491 void ThrowStatement::toCBuffer(OutBuffer
*buf
, HdrGenState
*hgs
)
3493 buf
->printf("throw ");
3494 exp
->toCBuffer(buf
, hgs
);
3495 buf
->writeByte(';');
3499 /******************************** VolatileStatement **************************/
3501 VolatileStatement::VolatileStatement(Loc loc
, Statement
*statement
)
3504 this->statement
= statement
;
3507 Statement
*VolatileStatement::syntaxCopy()
3509 VolatileStatement
*s
= new VolatileStatement(loc
,
3510 statement
? statement
->syntaxCopy() : NULL
);
3514 Statement
*VolatileStatement::semantic(Scope
*sc
)
3516 statement
= statement
? statement
->semantic(sc
) : NULL
;
3520 Statements
*VolatileStatement::flatten(Scope
*sc
)
3524 a
= statement
? statement
->flatten(sc
) : NULL
;
3526 { for (int i
= 0; i
< a
->dim
; i
++)
3527 { Statement
*s
= (Statement
*)a
->data
[i
];
3529 s
= new VolatileStatement(loc
, s
);
3537 int VolatileStatement::fallOffEnd()
3539 return statement
? statement
->fallOffEnd() : TRUE
;
3542 void VolatileStatement::toCBuffer(OutBuffer
*buf
, HdrGenState
*hgs
)
3544 buf
->writestring("volatile");
3546 { if (statement
->isScopeStatement())
3549 buf
->writebyte(' ');
3550 statement
->toCBuffer(buf
, hgs
);
3555 /******************************** GotoStatement ***************************/
3557 GotoStatement::GotoStatement(Loc loc
, Identifier
*ident
)
3560 this->ident
= ident
;
3565 Statement
*GotoStatement::syntaxCopy()
3567 GotoStatement
*s
= new GotoStatement(loc
, ident
);
3571 Statement
*GotoStatement::semantic(Scope
*sc
)
3572 { FuncDeclaration
*fd
= sc
->parent
->isFuncDeclaration();
3574 //printf("GotoStatement::semantic()\n");
3576 label
= fd
->searchLabel(ident
);
3577 if (!label
->statement
&& sc
->fes
)
3579 /* Either the goto label is forward referenced or it
3580 * is in the function that the enclosing foreach is in.
3581 * Can't know yet, so wrap the goto in a compound statement
3582 * so we can patch it later, and add it to a 'look at this later'
3585 Statements
*a
= new Statements();
3589 s
= new CompoundStatement(loc
, a
);
3590 sc
->fes
->gotos
.push(s
); // 'look at this later' list
3593 if (label
->statement
&& label
->statement
->tf
!= sc
->tf
)
3594 error("cannot goto in or out of finally block");
3598 int GotoStatement::fallOffEnd()
3603 void GotoStatement::toCBuffer(OutBuffer
*buf
, HdrGenState
*hgs
)
3605 buf
->writestring("goto ");
3606 buf
->writestring(ident
->toChars());
3607 buf
->writebyte(';');
3611 /******************************** LabelStatement ***************************/
3613 LabelStatement::LabelStatement(Loc loc
, Identifier
*ident
, Statement
*statement
)
3616 this->ident
= ident
;
3617 this->statement
= statement
;
3619 this->lblock
= NULL
;
3620 this->isReturnLabel
= 0;
3623 Statement
*LabelStatement::syntaxCopy()
3625 LabelStatement
*s
= new LabelStatement(loc
, ident
, statement
->syntaxCopy());
3629 Statement
*LabelStatement::semantic(Scope
*sc
)
3631 FuncDeclaration
*fd
= sc
->parent
->isFuncDeclaration();
3633 //printf("LabelStatement::semantic()\n");
3634 ls
= fd
->searchLabel(ident
);
3636 error("Label '%s' already defined", ls
->toChars());
3638 ls
->statement
= this;
3641 sc
->scopesym
= sc
->enclosing
->scopesym
;
3642 sc
->callSuper
|= CSXlabel
;
3645 statement
= statement
->semantic(sc
);
3650 Statements
*LabelStatement::flatten(Scope
*sc
)
3652 Statements
*a
= NULL
;
3656 a
= statement
->flatten(sc
);
3661 a
->push(new ExpStatement(loc
, NULL
));
3663 Statement
*s
= (Statement
*)a
->data
[0];
3665 s
= new LabelStatement(loc
, ident
, s
);
3674 int LabelStatement::usesEH()
3676 return statement
? statement
->usesEH() : FALSE
;
3679 int LabelStatement::fallOffEnd()
3681 return statement
? statement
->fallOffEnd() : TRUE
;
3684 int LabelStatement::comeFrom()
3686 //printf("LabelStatement::comeFrom()\n");
3690 void LabelStatement::toCBuffer(OutBuffer
*buf
, HdrGenState
*hgs
)
3692 buf
->writestring(ident
->toChars());
3693 buf
->writebyte(':');
3696 statement
->toCBuffer(buf
, hgs
);
3700 /******************************** LabelDsymbol ***************************/
3702 LabelDsymbol::LabelDsymbol(Identifier
*ident
)
3711 LabelDsymbol
*LabelDsymbol::isLabel() // is this a LabelDsymbol()?