blob: e90b9f2c3f40120bd57289afa23e5a9451455401 [file] [log] [blame]
Reid Spencer5f016e22007-07-11 17:01:13 +00001//===--- StmtPrinter.cpp - Printing implementation for Stmt ASTs ----------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file was developed by Chris Lattner and is distributed under
6// the University of Illinois Open Source License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file implements the Stmt::dump/Stmt::print methods.
11//
12//===----------------------------------------------------------------------===//
13
14#include "clang/AST/StmtVisitor.h"
15#include "clang/AST/Decl.h"
16#include "clang/AST/ExprCXX.h"
17#include "clang/Lex/IdentifierTable.h"
18#include "llvm/Support/Compiler.h"
19#include <iostream>
20using namespace clang;
21
22//===----------------------------------------------------------------------===//
23// StmtPrinter Visitor
24//===----------------------------------------------------------------------===//
25
26namespace {
27 class VISIBILITY_HIDDEN StmtPrinter : public StmtVisitor {
28 std::ostream &OS;
29 unsigned IndentLevel;
30 public:
31 StmtPrinter(std::ostream &os) : OS(os), IndentLevel(0) {}
32
33 void PrintStmt(Stmt *S, int SubIndent = 1) {
34 IndentLevel += SubIndent;
35 if (S && isa<Expr>(S)) {
36 // If this is an expr used in a stmt context, indent and newline it.
37 Indent();
38 S->visit(*this);
39 OS << ";\n";
40 } else if (S) {
41 S->visit(*this);
42 } else {
43 Indent() << "<<<NULL STATEMENT>>>\n";
44 }
45 IndentLevel -= SubIndent;
46 }
47
48 void PrintRawCompoundStmt(CompoundStmt *S);
49 void PrintRawDecl(Decl *D);
50 void PrintRawIfStmt(IfStmt *If);
51
52 void PrintExpr(Expr *E) {
53 if (E)
54 E->visit(*this);
55 else
56 OS << "<null expr>";
57 }
58
59 std::ostream &Indent(int Delta = 0) const {
60 for (int i = 0, e = IndentLevel+Delta; i < e; ++i)
61 OS << " ";
62 return OS;
63 }
64
65 virtual void VisitStmt(Stmt *Node);
66#define STMT(N, CLASS, PARENT) \
67 virtual void Visit##CLASS(CLASS *Node);
68#include "clang/AST/StmtNodes.def"
69 };
70}
71
72//===----------------------------------------------------------------------===//
73// Stmt printing methods.
74//===----------------------------------------------------------------------===//
75
76void StmtPrinter::VisitStmt(Stmt *Node) {
77 Indent() << "<<unknown stmt type>>\n";
78}
79
80/// PrintRawCompoundStmt - Print a compound stmt without indenting the {, and
81/// with no newline after the }.
82void StmtPrinter::PrintRawCompoundStmt(CompoundStmt *Node) {
83 OS << "{\n";
84 for (CompoundStmt::body_iterator I = Node->body_begin(), E = Node->body_end();
85 I != E; ++I)
86 PrintStmt(*I);
87
88 Indent() << "}";
89}
90
91void StmtPrinter::PrintRawDecl(Decl *D) {
92 // FIXME: Need to complete/beautify this... this code simply shows the
93 // nodes are where they need to be.
94 if (TypedefDecl *localType = dyn_cast<TypedefDecl>(D)) {
95 OS << "typedef " << localType->getUnderlyingType().getAsString();
96 OS << " " << localType->getName();
97 } else if (ValueDecl *VD = dyn_cast<ValueDecl>(D)) {
98 // Emit storage class for vardecls.
99 if (VarDecl *V = dyn_cast<VarDecl>(VD)) {
100 switch (V->getStorageClass()) {
101 default: assert(0 && "Unknown storage class!");
102 case VarDecl::None: break;
103 case VarDecl::Extern: OS << "extern "; break;
104 case VarDecl::Static: OS << "static "; break;
105 case VarDecl::Auto: OS << "auto "; break;
106 case VarDecl::Register: OS << "register "; break;
107 }
108 }
109
110 std::string Name = VD->getName();
111 VD->getType().getAsStringInternal(Name);
112 OS << Name;
113
114 // FIXME: Initializer for vardecl
115 } else {
116 // FIXME: "struct x;"
117 assert(0 && "Unexpected decl");
118 }
119}
120
121
122void StmtPrinter::VisitNullStmt(NullStmt *Node) {
123 Indent() << ";\n";
124}
125
126void StmtPrinter::VisitDeclStmt(DeclStmt *Node) {
127 for (Decl *D = Node->getDecl(); D; D = D->getNextDeclarator()) {
128 Indent();
129 PrintRawDecl(D);
130 OS << ";\n";
131 }
132}
133
134void StmtPrinter::VisitCompoundStmt(CompoundStmt *Node) {
135 Indent();
136 PrintRawCompoundStmt(Node);
137 OS << "\n";
138}
139
140void StmtPrinter::VisitCaseStmt(CaseStmt *Node) {
141 Indent(-1) << "case ";
142 PrintExpr(Node->getLHS());
143 if (Node->getRHS()) {
144 OS << " ... ";
145 PrintExpr(Node->getRHS());
146 }
147 OS << ":\n";
148
149 PrintStmt(Node->getSubStmt(), 0);
150}
151
152void StmtPrinter::VisitDefaultStmt(DefaultStmt *Node) {
153 Indent(-1) << "default:\n";
154 PrintStmt(Node->getSubStmt(), 0);
155}
156
157void StmtPrinter::VisitLabelStmt(LabelStmt *Node) {
158 Indent(-1) << Node->getName() << ":\n";
159 PrintStmt(Node->getSubStmt(), 0);
160}
161
162void StmtPrinter::PrintRawIfStmt(IfStmt *If) {
163 OS << "if ";
164 PrintExpr(If->getCond());
165
166 if (CompoundStmt *CS = dyn_cast<CompoundStmt>(If->getThen())) {
167 OS << ' ';
168 PrintRawCompoundStmt(CS);
169 OS << (If->getElse() ? ' ' : '\n');
170 } else {
171 OS << '\n';
172 PrintStmt(If->getThen());
173 if (If->getElse()) Indent();
174 }
175
176 if (Stmt *Else = If->getElse()) {
177 OS << "else";
178
179 if (CompoundStmt *CS = dyn_cast<CompoundStmt>(Else)) {
180 OS << ' ';
181 PrintRawCompoundStmt(CS);
182 OS << '\n';
183 } else if (IfStmt *ElseIf = dyn_cast<IfStmt>(Else)) {
184 OS << ' ';
185 PrintRawIfStmt(ElseIf);
186 } else {
187 OS << '\n';
188 PrintStmt(If->getElse());
189 }
190 }
191}
192
193void StmtPrinter::VisitIfStmt(IfStmt *If) {
194 Indent();
195 PrintRawIfStmt(If);
196}
197
198void StmtPrinter::VisitSwitchStmt(SwitchStmt *Node) {
199 Indent() << "switch (";
200 PrintExpr(Node->getCond());
201 OS << ")";
202
203 // Pretty print compoundstmt bodies (very common).
204 if (CompoundStmt *CS = dyn_cast<CompoundStmt>(Node->getBody())) {
205 OS << " ";
206 PrintRawCompoundStmt(CS);
207 OS << "\n";
208 } else {
209 OS << "\n";
210 PrintStmt(Node->getBody());
211 }
212}
213
214void StmtPrinter::VisitWhileStmt(WhileStmt *Node) {
215 Indent() << "while (";
216 PrintExpr(Node->getCond());
217 OS << ")\n";
218 PrintStmt(Node->getBody());
219}
220
221void StmtPrinter::VisitDoStmt(DoStmt *Node) {
222 Indent() << "do\n";
223 PrintStmt(Node->getBody());
224 Indent() << "while ";
225 PrintExpr(Node->getCond());
226 OS << ";\n";
227}
228
229void StmtPrinter::VisitForStmt(ForStmt *Node) {
230 Indent() << "for (";
231 if (Node->getInit()) {
232 if (DeclStmt *DS = dyn_cast<DeclStmt>(Node->getInit()))
233 PrintRawDecl(DS->getDecl());
234 else
235 PrintExpr(cast<Expr>(Node->getInit()));
236 }
237 OS << "; ";
238 if (Node->getCond())
239 PrintExpr(Node->getCond());
240 OS << "; ";
241 if (Node->getInc())
242 PrintExpr(Node->getInc());
243 OS << ")\n";
244 PrintStmt(Node->getBody());
245}
246
247void StmtPrinter::VisitGotoStmt(GotoStmt *Node) {
248 Indent() << "goto " << Node->getLabel()->getName() << ";\n";
249}
250
251void StmtPrinter::VisitIndirectGotoStmt(IndirectGotoStmt *Node) {
252 Indent() << "goto *";
253 PrintExpr(Node->getTarget());
254 OS << ";\n";
255}
256
257void StmtPrinter::VisitContinueStmt(ContinueStmt *Node) {
258 Indent() << "continue;\n";
259}
260
261void StmtPrinter::VisitBreakStmt(BreakStmt *Node) {
262 Indent() << "break;\n";
263}
264
265
266void StmtPrinter::VisitReturnStmt(ReturnStmt *Node) {
267 Indent() << "return";
268 if (Node->getRetValue()) {
269 OS << " ";
270 PrintExpr(Node->getRetValue());
271 }
272 OS << ";\n";
273}
274
275//===----------------------------------------------------------------------===//
276// Expr printing methods.
277//===----------------------------------------------------------------------===//
278
279void StmtPrinter::VisitExpr(Expr *Node) {
280 OS << "<<unknown expr type>>";
281}
282
283void StmtPrinter::VisitDeclRefExpr(DeclRefExpr *Node) {
284 OS << Node->getDecl()->getName();
285}
286
287void StmtPrinter::VisitCharacterLiteral(CharacterLiteral *Node) {
288 // FIXME: print value.
289 OS << "x";
290}
291
292void StmtPrinter::VisitIntegerLiteral(IntegerLiteral *Node) {
293 bool isSigned = Node->getType()->isSignedIntegerType();
294 OS << Node->getValue().toString(10, isSigned);
295
296 // Emit suffixes. Integer literals are always a builtin integer type.
297 switch (cast<BuiltinType>(Node->getType().getCanonicalType())->getKind()) {
298 default: assert(0 && "Unexpected type for integer literal!");
299 case BuiltinType::Int: break; // no suffix.
300 case BuiltinType::UInt: OS << 'U'; break;
301 case BuiltinType::Long: OS << 'L'; break;
302 case BuiltinType::ULong: OS << "UL"; break;
303 case BuiltinType::LongLong: OS << "LL"; break;
304 case BuiltinType::ULongLong: OS << "ULL"; break;
305 }
306}
307void StmtPrinter::VisitFloatingLiteral(FloatingLiteral *Node) {
308 // FIXME: print value.
309 OS << "~1.0~";
310}
311void StmtPrinter::VisitStringLiteral(StringLiteral *Str) {
312 if (Str->isWide()) OS << 'L';
313 OS << '"';
314
315 // FIXME: this doesn't print wstrings right.
316 for (unsigned i = 0, e = Str->getByteLength(); i != e; ++i) {
317 switch (Str->getStrData()[i]) {
318 default: OS << Str->getStrData()[i]; break;
319 // Handle some common ones to make dumps prettier.
320 case '\\': OS << "\\\\"; break;
321 case '"': OS << "\\\""; break;
322 case '\n': OS << "\\n"; break;
323 case '\t': OS << "\\t"; break;
324 case '\a': OS << "\\a"; break;
325 case '\b': OS << "\\b"; break;
326 }
327 }
328 OS << '"';
329}
330void StmtPrinter::VisitParenExpr(ParenExpr *Node) {
331 OS << "(";
332 PrintExpr(Node->getSubExpr());
333 OS << ")";
334}
335void StmtPrinter::VisitUnaryOperator(UnaryOperator *Node) {
336 if (!Node->isPostfix())
337 OS << UnaryOperator::getOpcodeStr(Node->getOpcode());
338 PrintExpr(Node->getSubExpr());
339
340 if (Node->isPostfix())
341 OS << UnaryOperator::getOpcodeStr(Node->getOpcode());
342
343}
344void StmtPrinter::VisitSizeOfAlignOfTypeExpr(SizeOfAlignOfTypeExpr *Node) {
345 OS << (Node->isSizeOf() ? "sizeof(" : "__alignof(");
346 OS << Node->getArgumentType().getAsString() << ")";
347}
348void StmtPrinter::VisitArraySubscriptExpr(ArraySubscriptExpr *Node) {
349 PrintExpr(Node->getBase());
350 OS << "[";
351 PrintExpr(Node->getIdx());
352 OS << "]";
353}
354
355void StmtPrinter::VisitCallExpr(CallExpr *Call) {
356 PrintExpr(Call->getCallee());
357 OS << "(";
358 for (unsigned i = 0, e = Call->getNumArgs(); i != e; ++i) {
359 if (i) OS << ", ";
360 PrintExpr(Call->getArg(i));
361 }
362 OS << ")";
363}
364void StmtPrinter::VisitMemberExpr(MemberExpr *Node) {
365 PrintExpr(Node->getBase());
366 OS << (Node->isArrow() ? "->" : ".");
367
368 FieldDecl *Field = Node->getMemberDecl();
369 assert(Field && "MemberExpr should alway reference a field!");
370 OS << Field->getName();
371}
372void StmtPrinter::VisitCastExpr(CastExpr *Node) {
373 OS << "(" << Node->getDestType().getAsString() << ")";
374 PrintExpr(Node->getSubExpr());
375}
376void StmtPrinter::VisitBinaryOperator(BinaryOperator *Node) {
377 PrintExpr(Node->getLHS());
378 OS << " " << BinaryOperator::getOpcodeStr(Node->getOpcode()) << " ";
379 PrintExpr(Node->getRHS());
380}
381void StmtPrinter::VisitConditionalOperator(ConditionalOperator *Node) {
382 PrintExpr(Node->getCond());
383 OS << " ? ";
384 PrintExpr(Node->getLHS());
385 OS << " : ";
386 PrintExpr(Node->getRHS());
387}
388
389// GNU extensions.
390
391void StmtPrinter::VisitAddrLabel(AddrLabel *Node) {
392 OS << "&&" << Node->getLabel()->getName();
393
394}
395
396// C++
397
398void StmtPrinter::VisitCXXCastExpr(CXXCastExpr *Node) {
399 switch (Node->getOpcode()) {
400 default:
401 assert(0 && "Not a C++ cast expression");
402 abort();
403 case CXXCastExpr::ConstCast: OS << "const_cast<"; break;
404 case CXXCastExpr::DynamicCast: OS << "dynamic_cast<"; break;
405 case CXXCastExpr::ReinterpretCast: OS << "reinterpret_cast<"; break;
406 case CXXCastExpr::StaticCast: OS << "static_cast<"; break;
407 }
408
409 OS << Node->getDestType().getAsString() << ">(";
410 PrintExpr(Node->getSubExpr());
411 OS << ")";
412}
413
414void StmtPrinter::VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *Node) {
415 OS << (Node->getValue() ? "true" : "false");
416}
417
418
419//===----------------------------------------------------------------------===//
420// Stmt method implementations
421//===----------------------------------------------------------------------===//
422
423void Stmt::dump() const {
424 // FIXME: eliminate use of <iostream>
425 print(std::cerr);
426}
427
428void Stmt::print(std::ostream &OS) const {
429 if (this == 0) {
430 OS << "<NULL>";
431 return;
432 }
433
434 StmtPrinter P(OS);
435 const_cast<Stmt*>(this)->visit(P);
436}