2008-06-13 Cameron Zwarich <cwzwarich@uwaterloo.ca>
[WebKit-https.git] / JavaScriptCore / kjs / nodes2string.cpp
1 /*
2  *  Copyright (C) 2002 Harri Porten (porten@kde.org)
3  *  Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
4  *  Copyright (C) 2007 Eric Seidel <eric@webkit.org>
5  *
6  *  This library is free software; you can redistribute it and/or
7  *  modify it under the terms of the GNU Library General Public
8  *  License as published by the Free Software Foundation; either
9  *  version 2 of the License, or (at your option) any later version.
10  *
11  *  This library is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  *  Library General Public License for more details.
15  *
16  *  You should have received a copy of the GNU Library General Public License
17  *  along with this library; see the file COPYING.LIB.  If not, write to
18  *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  *  Boston, MA 02110-1301, USA.
20  *
21  */
22
23 #include "config.h"
24 #include "nodes.h"
25
26 #include <wtf/MathExtras.h>
27 #include <wtf/StringExtras.h>
28 #include <wtf/unicode/Unicode.h>
29
30 using namespace WTF;
31 using namespace Unicode;
32
33 namespace KJS {
34
35 // A simple text streaming class that helps with code indentation.
36
37 enum EndlType { Endl };
38 enum IndentType { Indent };
39 enum UnindentType { Unindent };
40 enum DotExprType { DotExpr };
41
42 class SourceStream {
43 public:
44     SourceStream()
45         : m_numberNeedsParens(false)
46         , m_atStartOfStatement(true)
47         , m_precedence(PrecExpression)
48     {
49     }
50
51     UString toString() const { return m_string; }
52
53     SourceStream& operator<<(const Identifier&);
54     SourceStream& operator<<(const UString&);
55     SourceStream& operator<<(const char*);
56     SourceStream& operator<<(double);
57     SourceStream& operator<<(char);
58     SourceStream& operator<<(EndlType);
59     SourceStream& operator<<(IndentType);
60     SourceStream& operator<<(UnindentType);
61     SourceStream& operator<<(DotExprType);
62     SourceStream& operator<<(Precedence);
63     SourceStream& operator<<(const Node*);
64     template <typename T> SourceStream& operator<<(const RefPtr<T>& n) { return *this << n.get(); }
65
66 private:
67     UString m_string;
68     UString m_spacesForIndentation;
69     bool m_numberNeedsParens;
70     bool m_atStartOfStatement;
71     Precedence m_precedence;
72 };
73
74 // --------
75
76 static UString escapeStringForPrettyPrinting(const UString& s)
77 {
78     UString escapedString;
79
80     for (int i = 0; i < s.size(); i++) {
81         UChar c = s.data()[i];
82         switch (c) {
83             case '\"':
84                 escapedString += "\\\"";
85                 break;
86             case '\n':
87                 escapedString += "\\n";
88                 break;
89             case '\r':
90                 escapedString += "\\r";
91                 break;
92             case '\t':
93                 escapedString += "\\t";
94                 break;
95             case '\\':
96                 escapedString += "\\\\";
97                 break;
98             default:
99                 if (c < 128 && isPrintableChar(c))
100                     escapedString.append(c);
101                 else {
102                     char hexValue[7];
103                     snprintf(hexValue, 7, "\\u%04x", c);
104                     escapedString += hexValue;
105                 }
106         }
107     }
108
109     return escapedString;
110 }
111
112 static const char* operatorString(Operator oper)
113 {
114     switch (oper) {
115         case OpEqual:
116             return "=";
117         case OpMultEq:
118             return "*=";
119         case OpDivEq:
120             return "/=";
121         case OpPlusEq:
122             return "+=";
123         case OpMinusEq:
124             return "-=";
125         case OpLShift:
126             return "<<=";
127         case OpRShift:
128             return ">>=";
129         case OpURShift:
130             return ">>>=";
131         case OpAndEq:
132             return "&=";
133         case OpXOrEq:
134             return "^=";
135         case OpOrEq:
136             return "|=";
137         case OpModEq:
138             return "%=";
139         case OpPlusPlus:
140             return "++";
141         case OpMinusMinus:
142             return "--";
143     }
144     ASSERT_NOT_REACHED();
145     return "???";
146 }
147
148 static bool isParserRoundTripNumber(const UString& string)
149 {
150     double number = string.toDouble(false, false);
151     if (isnan(number) || isinf(number))
152         return false;
153     return string == UString::from(number);
154 }
155
156 // --------
157
158 SourceStream& SourceStream::operator<<(char c)
159 {
160     m_numberNeedsParens = false;
161     m_atStartOfStatement = false;
162     // use unsigned char to zero-extend instead of sign-extend
163     UChar ch(static_cast<unsigned char>(c));
164     m_string.append(ch);
165     return *this;
166 }
167
168 SourceStream& SourceStream::operator<<(const char* s)
169 {
170     m_numberNeedsParens = false;
171     m_atStartOfStatement = false;
172     m_string += s;
173     return *this;
174 }
175
176 SourceStream& SourceStream::operator<<(double value)
177 {
178     bool needParens = m_numberNeedsParens;
179     m_numberNeedsParens = false;
180     m_atStartOfStatement = false;
181
182     if (needParens)
183         m_string.append('(');
184     m_string += UString::from(value);
185     if (needParens)
186         m_string.append(')');
187
188     return *this;
189 }
190
191 SourceStream& SourceStream::operator<<(const UString& s)
192 {
193     m_numberNeedsParens = false;
194     m_atStartOfStatement = false;
195     m_string += s;
196     return *this;
197 }
198
199 SourceStream& SourceStream::operator<<(const Identifier& s)
200 {
201     m_numberNeedsParens = false;
202     m_atStartOfStatement = false;
203     m_string += s.ustring();
204     return *this;
205 }
206
207 SourceStream& SourceStream::operator<<(const Node* n)
208 {
209     bool needParens = (m_precedence != PrecExpression && n->precedence() > m_precedence) || (m_atStartOfStatement && n->needsParensIfLeftmost());
210     m_precedence = PrecExpression;
211     if (!n)
212         return *this;
213     if (needParens) {
214         m_numberNeedsParens = false;
215         m_string.append('(');
216     }
217     n->streamTo(*this);
218     if (needParens)
219         m_string.append(')');
220     return *this;
221 }
222
223 SourceStream& SourceStream::operator<<(EndlType)
224 {
225     m_numberNeedsParens = false;
226     m_atStartOfStatement = true;
227     m_string.append('\n');
228     m_string.append(m_spacesForIndentation);
229     return *this;
230 }
231
232 SourceStream& SourceStream::operator<<(IndentType)
233 {
234     m_numberNeedsParens = false;
235     m_atStartOfStatement = false;
236     m_spacesForIndentation += "  ";
237     return *this;
238 }
239
240 SourceStream& SourceStream::operator<<(UnindentType)
241 {
242     m_numberNeedsParens = false;
243     m_atStartOfStatement = false;
244     m_spacesForIndentation = m_spacesForIndentation.substr(0, m_spacesForIndentation.size() - 2);
245     return *this;
246 }
247
248 inline SourceStream& SourceStream::operator<<(DotExprType)
249 {
250     m_numberNeedsParens = true;
251     return *this;
252 }
253
254 inline SourceStream& SourceStream::operator<<(Precedence precedence)
255 {
256     m_precedence = precedence;
257     return *this;
258 }
259
260 static void streamLeftAssociativeBinaryOperator(SourceStream& s, Precedence precedence,
261     const char* operatorString, const Node* left, const Node* right)
262 {
263     s << precedence << left
264         << ' ' << operatorString << ' '
265         << static_cast<Precedence>(precedence - 1) << right;
266 }
267
268 template <typename T> static inline void streamLeftAssociativeBinaryOperator(SourceStream& s,
269     Precedence p, const char* o, const RefPtr<T>& l, const RefPtr<T>& r)
270 {
271     streamLeftAssociativeBinaryOperator(s, p, o, l.get(), r.get());
272 }
273
274 static inline void bracketNodeStreamTo(SourceStream& s, const RefPtr<ExpressionNode>& base, const RefPtr<ExpressionNode>& subscript)
275 {
276     s << PrecCall << base.get() << "[" << subscript.get() << "]";
277 }
278
279 static inline void dotNodeStreamTo(SourceStream& s, const RefPtr<ExpressionNode>& base, const Identifier& ident)
280 {
281     s << DotExpr << PrecCall << base.get() << "." << ident;
282 }
283
284 // --------
285
286 UString Node::toString() const
287 {
288     SourceStream stream;
289     streamTo(stream);
290     return stream.toString();
291 }
292
293 // --------
294
295 void NullNode::streamTo(SourceStream& s) const
296 {
297     s << "null";
298 }
299
300 void BooleanNode::streamTo(SourceStream& s) const
301 {
302     s << (m_value ? "true" : "false");
303 }
304
305 void NumberNode::streamTo(SourceStream& s) const
306 {
307     s << value();
308 }
309
310 void StringNode::streamTo(SourceStream& s) const
311 {
312     s << '"' << escapeStringForPrettyPrinting(m_value) << '"';
313 }
314
315 void RegExpNode::streamTo(SourceStream& s) const
316 {
317     s << '/' <<  m_regExp->pattern() << '/' << m_regExp->flags();
318 }
319
320 void ThisNode::streamTo(SourceStream& s) const
321 {
322     s << "this";
323 }
324
325 void ResolveNode::streamTo(SourceStream& s) const
326 {
327     s << m_ident;
328 }
329
330 void ElementNode::streamTo(SourceStream& s) const
331 {
332     for (const ElementNode* n = this; n; n = n->m_next.get()) {
333         for (int i = 0; i < n->m_elision; i++)
334             s << ',';
335         s << PrecAssignment << n->m_node;
336         if (n->m_next)
337             s << ',';
338     }
339 }
340
341 void ArrayNode::streamTo(SourceStream& s) const
342 {
343     s << '[' << m_element;
344     for (int i = 0; i < m_elision; i++)
345         s << ',';
346     // Parser consumes one elision comma if there's array elements
347     // present in the expression.
348     if (m_optional && m_element)
349         s << ',';
350     s << ']';
351 }
352
353 void ObjectLiteralNode::streamTo(SourceStream& s) const
354 {
355     if (m_list)
356         s << "{ " << m_list << " }";
357     else
358         s << "{ }";
359 }
360
361 void PropertyListNode::streamTo(SourceStream& s) const
362 {
363     s << m_node;
364     for (const PropertyListNode* n = m_next.get(); n; n = n->m_next.get())
365         s << ", " << n->m_node;
366 }
367
368 void PropertyNode::streamTo(SourceStream& s) const
369 {
370     switch (m_type) {
371         case Constant: {
372             UString propertyName = name().ustring();
373             if (isParserRoundTripNumber(propertyName))
374                 s << propertyName;
375             else
376                 s << '"' << escapeStringForPrettyPrinting(propertyName) << '"';
377             s << ": " << PrecAssignment << m_assign;
378             break;
379         }
380         case Getter:
381         case Setter: {
382             const FuncExprNode* func = static_cast<const FuncExprNode*>(m_assign.get());
383             if (m_type == Getter)
384                 s << "get ";
385             else
386                 s << "set ";
387             s << escapeStringForPrettyPrinting(name().ustring())
388                 << "(" << func->m_parameter << ')' << func->m_body;
389             break;
390         }
391     }
392 }
393
394 void BracketAccessorNode::streamTo(SourceStream& s) const
395 {
396     bracketNodeStreamTo(s, m_base, m_subscript);
397 }
398
399 void DotAccessorNode::streamTo(SourceStream& s) const
400 {
401     dotNodeStreamTo(s, m_base, m_ident);
402 }
403
404 void ArgumentListNode::streamTo(SourceStream& s) const
405 {
406     s << PrecAssignment << m_expr;
407     for (ArgumentListNode* n = m_next.get(); n; n = n->m_next.get())
408         s << ", " << PrecAssignment << n->m_expr;
409 }
410
411 void ArgumentsNode::streamTo(SourceStream& s) const
412 {
413     s << '(' << m_listNode << ')';
414 }
415
416 void NewExprNode::streamTo(SourceStream& s) const
417 {
418     s << "new " << PrecMember << m_expr << m_args;
419 }
420
421 void EvalFunctionCallNode::streamTo(SourceStream& s) const
422 {
423     s << "eval" << m_args;
424 }
425
426 void FunctionCallValueNode::streamTo(SourceStream& s) const
427 {
428     s << PrecCall << m_expr << m_args;
429 }
430
431 void FunctionCallResolveNode::streamTo(SourceStream& s) const
432 {
433     s << m_ident << m_args;
434 }
435
436 void FunctionCallBracketNode::streamTo(SourceStream& s) const
437 {
438     bracketNodeStreamTo(s, m_base, m_subscript);
439     s << m_args;
440 }
441
442 void FunctionCallDotNode::streamTo(SourceStream& s) const
443 {
444     dotNodeStreamTo(s, m_base, m_ident);
445     s << m_args;
446 }
447
448 void PostIncResolveNode::streamTo(SourceStream& s) const
449 {
450     s << m_ident << "++";
451 }
452
453 void PostDecResolveNode::streamTo(SourceStream& s) const
454 {
455     s << m_ident << "--";
456 }
457
458 void PostIncBracketNode::streamTo(SourceStream& s) const
459 {
460     bracketNodeStreamTo(s, m_base, m_subscript);
461     s << "++";
462 }
463
464 void PostDecBracketNode::streamTo(SourceStream& s) const
465 {
466     bracketNodeStreamTo(s, m_base, m_subscript);
467     s << "--";
468 }
469
470 void PostIncDotNode::streamTo(SourceStream& s) const
471 {
472     dotNodeStreamTo(s, m_base, m_ident);
473     s << "++";
474 }
475
476 void PostDecDotNode::streamTo(SourceStream& s) const
477 {
478     dotNodeStreamTo(s, m_base, m_ident);
479     s << "--";
480 }
481
482 void PostfixErrorNode::streamTo(SourceStream& s) const
483 {
484     s << PrecLeftHandSide << m_expr;
485     if (m_operator == OpPlusPlus)
486         s << "++";
487     else
488         s << "--";
489 }
490
491 void DeleteResolveNode::streamTo(SourceStream& s) const
492 {
493     s << "delete " << m_ident;
494 }
495
496 void DeleteBracketNode::streamTo(SourceStream& s) const
497 {
498     s << "delete ";
499     bracketNodeStreamTo(s, m_base, m_subscript);
500 }
501
502 void DeleteDotNode::streamTo(SourceStream& s) const
503 {
504     s << "delete ";
505     dotNodeStreamTo(s, m_base, m_ident);
506 }
507
508 void DeleteValueNode::streamTo(SourceStream& s) const
509 {
510     s << "delete " << PrecUnary << m_expr;
511 }
512
513 void VoidNode::streamTo(SourceStream& s) const
514 {
515     s << "void " << PrecUnary << m_expr;
516 }
517
518 void TypeOfValueNode::streamTo(SourceStream& s) const
519 {
520     s << "typeof " << PrecUnary << m_expr;
521 }
522
523 void TypeOfResolveNode::streamTo(SourceStream& s) const
524 {
525     s << "typeof " << m_ident;
526 }
527
528 void PreIncResolveNode::streamTo(SourceStream& s) const
529 {
530     s << "++" << m_ident;
531 }
532
533 void PreDecResolveNode::streamTo(SourceStream& s) const
534 {
535     s << "--" << m_ident;
536 }
537
538 void PreIncBracketNode::streamTo(SourceStream& s) const
539 {
540     s << "++";
541     bracketNodeStreamTo(s, m_base, m_subscript);
542 }
543
544 void PreDecBracketNode::streamTo(SourceStream& s) const
545 {
546     s << "--";
547     bracketNodeStreamTo(s, m_base, m_subscript);
548 }
549
550 void PreIncDotNode::streamTo(SourceStream& s) const
551 {
552     s << "++";
553     dotNodeStreamTo(s, m_base, m_ident);
554 }
555
556 void PreDecDotNode::streamTo(SourceStream& s) const
557 {
558     s << "--";
559     dotNodeStreamTo(s, m_base, m_ident);
560 }
561
562 void PrefixErrorNode::streamTo(SourceStream& s) const
563 {
564     if (m_operator == OpPlusPlus)
565         s << "++" << PrecUnary << m_expr;
566     else
567         s << "--" << PrecUnary << m_expr;
568 }
569
570 void UnaryPlusNode::streamTo(SourceStream& s) const
571 {
572     s << "+ " << PrecUnary << m_expr;
573 }
574
575 void NegateNode::streamTo(SourceStream& s) const
576 {
577     s << "- " << PrecUnary << m_expr;
578 }
579
580 void BitwiseNotNode::streamTo(SourceStream& s) const
581 {
582     s << "~" << PrecUnary << m_expr;
583 }
584
585 void LogicalNotNode::streamTo(SourceStream& s) const
586 {
587     s << "!" << PrecUnary << m_expr;
588 }
589
590 void MultNode::streamTo(SourceStream& s) const
591 {
592     streamLeftAssociativeBinaryOperator(s, precedence(), "*", m_term1, m_term2);
593 }
594
595 void DivNode::streamTo(SourceStream& s) const
596 {
597     streamLeftAssociativeBinaryOperator(s, precedence(), "/", m_term1, m_term2);
598 }
599
600 void ModNode::streamTo(SourceStream& s) const
601 {
602     streamLeftAssociativeBinaryOperator(s, precedence(), "%", m_term1, m_term2);
603 }
604
605 void AddNode::streamTo(SourceStream& s) const
606 {
607     streamLeftAssociativeBinaryOperator(s, precedence(), "+", m_term1, m_term2);
608 }
609
610 void SubNode::streamTo(SourceStream& s) const
611 {
612     streamLeftAssociativeBinaryOperator(s, precedence(), "-", m_term1, m_term2);
613 }
614
615 void LeftShiftNode::streamTo(SourceStream& s) const
616 {
617     streamLeftAssociativeBinaryOperator(s, precedence(), "<<", m_term1, m_term2);
618 }
619
620 void RightShiftNode::streamTo(SourceStream& s) const
621 {
622     streamLeftAssociativeBinaryOperator(s, precedence(), ">>", m_term1, m_term2);
623 }
624
625 void UnsignedRightShiftNode::streamTo(SourceStream& s) const
626 {
627     streamLeftAssociativeBinaryOperator(s, precedence(), ">>>", m_term1, m_term2);
628 }
629
630 void LessNode::streamTo(SourceStream& s) const
631 {
632     streamLeftAssociativeBinaryOperator(s, precedence(), "<", m_expr1, m_expr2);
633 }
634
635 void GreaterNode::streamTo(SourceStream& s) const
636 {
637     streamLeftAssociativeBinaryOperator(s, precedence(), ">", m_expr1, m_expr2);
638 }
639
640 void LessEqNode::streamTo(SourceStream& s) const
641 {
642     streamLeftAssociativeBinaryOperator(s, precedence(), "<=", m_expr1, m_expr2);
643 }
644
645 void GreaterEqNode::streamTo(SourceStream& s) const
646 {
647     streamLeftAssociativeBinaryOperator(s, precedence(), ">=", m_expr1, m_expr2);
648 }
649
650 void InstanceOfNode::streamTo(SourceStream& s) const
651 {
652     streamLeftAssociativeBinaryOperator(s, precedence(), "instanceof", m_expr1, m_expr2);
653 }
654
655 void InNode::streamTo(SourceStream& s) const
656 {
657     streamLeftAssociativeBinaryOperator(s, precedence(), "in", m_expr1, m_expr2);
658 }
659
660 void EqualNode::streamTo(SourceStream& s) const
661 {
662     streamLeftAssociativeBinaryOperator(s, precedence(), "==", m_expr1, m_expr2);
663 }
664
665 void NotEqualNode::streamTo(SourceStream& s) const
666 {
667     streamLeftAssociativeBinaryOperator(s, precedence(), "!=", m_expr1, m_expr2);
668 }
669
670 void StrictEqualNode::streamTo(SourceStream& s) const
671 {
672     streamLeftAssociativeBinaryOperator(s, precedence(), "===", m_expr1, m_expr2);
673 }
674
675 void NotStrictEqualNode::streamTo(SourceStream& s) const
676 {
677     streamLeftAssociativeBinaryOperator(s, precedence(), "!==", m_expr1, m_expr2);
678 }
679
680 void BitAndNode::streamTo(SourceStream& s) const
681 {
682     streamLeftAssociativeBinaryOperator(s, precedence(), "&", m_expr1, m_expr2);
683 }
684
685 void BitXOrNode::streamTo(SourceStream& s) const
686 {
687     streamLeftAssociativeBinaryOperator(s, precedence(), "^", m_expr1, m_expr2);
688 }
689
690 void BitOrNode::streamTo(SourceStream& s) const
691 {
692     streamLeftAssociativeBinaryOperator(s, precedence(), "|", m_expr1, m_expr2);
693 }
694
695 void LogicalAndNode::streamTo(SourceStream& s) const
696 {
697     streamLeftAssociativeBinaryOperator(s, precedence(), "&&", m_expr1, m_expr2);
698 }
699
700 void LogicalOrNode::streamTo(SourceStream& s) const
701 {
702     streamLeftAssociativeBinaryOperator(s, precedence(), "||", m_expr1, m_expr2);
703 }
704
705 void ConditionalNode::streamTo(SourceStream& s) const
706 {
707     s << PrecLogicalOr << m_logical
708         << " ? " << PrecAssignment << m_expr1
709         << " : " << PrecAssignment << m_expr2;
710 }
711
712 void ReadModifyResolveNode::streamTo(SourceStream& s) const
713 {
714     s << m_ident << ' ' << operatorString(m_operator) << ' ' << PrecAssignment << m_right;
715 }
716
717 void AssignResolveNode::streamTo(SourceStream& s) const
718 {
719     s << m_ident << " = " << PrecAssignment << m_right;
720 }
721
722 void ReadModifyBracketNode::streamTo(SourceStream& s) const
723 {
724     bracketNodeStreamTo(s, m_base, m_subscript);
725     s << ' ' << operatorString(m_operator) << ' ' << PrecAssignment << m_right;
726 }
727
728 void AssignBracketNode::streamTo(SourceStream& s) const
729 {
730     bracketNodeStreamTo(s, m_base, m_subscript);
731     s << " = " << PrecAssignment << m_right;
732 }
733
734 void ReadModifyDotNode::streamTo(SourceStream& s) const
735 {
736     dotNodeStreamTo(s, m_base, m_ident);
737     s << ' ' << operatorString(m_operator) << ' ' << PrecAssignment << m_right;
738 }
739
740 void AssignDotNode::streamTo(SourceStream& s) const
741 {
742     dotNodeStreamTo(s, m_base, m_ident);
743     s << " = " << PrecAssignment << m_right;
744 }
745
746 void AssignErrorNode::streamTo(SourceStream& s) const
747 {
748     s << PrecLeftHandSide << m_left << ' '
749         << operatorString(m_operator) << ' ' << PrecAssignment << m_right;
750 }
751
752 void CommaNode::streamTo(SourceStream& s) const
753 {
754     s << PrecAssignment << m_expr1 << ", " << PrecAssignment << m_expr2;
755 }
756
757 void ConstDeclNode::streamTo(SourceStream& s) const
758 {
759     s << m_ident;
760     if (m_init)
761         s << " = " << PrecAssignment << m_init;
762     for (ConstDeclNode* n = m_next.get(); n; n = n->m_next.get()) {
763         s << ", " << n->m_ident;
764         if (n->m_init)
765             s << " = " << PrecAssignment << n->m_init;
766     }
767 }
768
769 void ConstStatementNode::streamTo(SourceStream& s) const
770 {
771     s << Endl << "const " << m_next << ';';
772 }
773
774 static inline void statementListStreamTo(const Vector<RefPtr<StatementNode> >& nodes, SourceStream& s)
775 {
776     for (Vector<RefPtr<StatementNode> >::const_iterator ptr = nodes.begin(); ptr != nodes.end(); ptr++)
777         s << *ptr;
778 }
779
780 void BlockNode::streamTo(SourceStream& s) const
781 {
782     s << Endl << "{" << Indent;
783     statementListStreamTo(m_children, s);
784     s << Unindent << Endl << "}";
785 }
786
787 void ScopeNode::streamTo(SourceStream& s) const
788 {
789     s << Endl << "{" << Indent;
790
791     bool printedVar = false;
792     for (size_t i = 0; i < m_varStack.size(); ++i) {
793         if (m_varStack[i].second == 0) {
794             if (!printedVar) {
795                 s << Endl << "var ";
796                 printedVar = true;
797             } else
798                 s << ", ";
799             s << m_varStack[i].first;
800         }
801     }
802     if (printedVar)
803         s << ';';
804
805     statementListStreamTo(m_children, s);
806     s << Unindent << Endl << "}";
807 }
808
809 void EmptyStatementNode::streamTo(SourceStream& s) const
810 {
811     s << Endl << ';';
812 }
813
814 void DebuggerStatementNode::streamTo(SourceStream& s) const
815 {
816     s << Endl << "debugger;";
817 }
818
819 void ExprStatementNode::streamTo(SourceStream& s) const
820 {
821     s << Endl << m_expr << ';';
822 }
823
824 void VarStatementNode::streamTo(SourceStream& s) const
825 {
826     s << Endl << "var " << m_expr << ';';
827 }
828
829 void IfNode::streamTo(SourceStream& s) const
830 {
831     s << Endl << "if (" << m_condition << ')' << Indent << m_ifBlock << Unindent;
832 }
833
834 void IfElseNode::streamTo(SourceStream& s) const
835 {
836     IfNode::streamTo(s);
837     s << Endl << "else" << Indent << m_elseBlock << Unindent;
838 }
839
840 void DoWhileNode::streamTo(SourceStream& s) const
841 {
842     s << Endl << "do " << Indent << m_statement << Unindent << Endl
843         << "while (" << m_expr << ");";
844 }
845
846 void WhileNode::streamTo(SourceStream& s) const
847 {
848     s << Endl << "while (" << m_expr << ')' << Indent << m_statement << Unindent;
849 }
850
851 void ForNode::streamTo(SourceStream& s) const
852 {
853     s << Endl << "for ("
854         << (m_expr1WasVarDecl ? "var " : "")
855         << m_expr1
856         << "; " << m_expr2
857         << "; " << m_expr3
858         << ')' << Indent << m_statement << Unindent;
859 }
860
861 void ForInNode::streamTo(SourceStream& s) const
862 {
863     s << Endl << "for (";
864     if (m_identIsVarDecl) {
865         s << "var ";
866         if (m_init)
867             s << m_init;
868         else
869             s << PrecLeftHandSide << m_lexpr;
870     } else
871         s << PrecLeftHandSide << m_lexpr;
872
873     s << " in " << m_expr << ')' << Indent << m_statement << Unindent;
874 }
875
876 void ContinueNode::streamTo(SourceStream& s) const
877 {
878     s << Endl << "continue";
879     if (!m_ident.isNull())
880         s << ' ' << m_ident;
881     s << ';';
882 }
883
884 void BreakNode::streamTo(SourceStream& s) const
885 {
886     s << Endl << "break";
887     if (!m_ident.isNull())
888         s << ' ' << m_ident;
889     s << ';';
890 }
891
892 void ReturnNode::streamTo(SourceStream& s) const
893 {
894     s << Endl << "return";
895     if (m_value)
896         s << ' ' << m_value;
897     s << ';';
898 }
899
900 void WithNode::streamTo(SourceStream& s) const
901 {
902     s << Endl << "with (" << m_expr << ") " << m_statement;
903 }
904
905 void CaseClauseNode::streamTo(SourceStream& s) const
906 {
907     s << Endl;
908     if (m_expr)
909         s << "case " << m_expr;
910     else
911         s << "default";
912     s << ":" << Indent;
913     statementListStreamTo(m_children, s);
914     s << Unindent;
915 }
916
917 void ClauseListNode::streamTo(SourceStream& s) const
918 {
919     for (const ClauseListNode* n = this; n; n = n->getNext())
920         s << n->getClause();
921 }
922
923 void CaseBlockNode::streamTo(SourceStream& s) const
924 {
925     for (const ClauseListNode* n = m_list1.get(); n; n = n->getNext())
926         s << n->getClause();
927     s << m_defaultClause;
928     for (const ClauseListNode* n = m_list2.get(); n; n = n->getNext())
929         s << n->getClause();
930 }
931
932 void SwitchNode::streamTo(SourceStream& s) const
933 {
934     s << Endl << "switch (" << m_expr << ") {"
935         << Indent << m_block << Unindent
936         << Endl << "}";
937 }
938
939 void LabelNode::streamTo(SourceStream& s) const
940 {
941     s << Endl << m_label << ":" << Indent << m_statement << Unindent;
942 }
943
944 void ThrowNode::streamTo(SourceStream& s) const
945 {
946     s << Endl << "throw " << m_expr << ';';
947 }
948
949 void TryNode::streamTo(SourceStream& s) const
950 {
951     s << Endl << "try " << m_tryBlock;
952     if (m_catchBlock)
953         s << Endl << "catch (" << m_exceptionIdent << ')' << m_catchBlock;
954     if (m_finallyBlock)
955         s << Endl << "finally " << m_finallyBlock;
956 }
957
958 void ParameterNode::streamTo(SourceStream& s) const
959 {
960     s << m_ident;
961     for (ParameterNode* n = m_next.get(); n; n = n->m_next.get())
962         s << ", " << n->m_ident;
963 }
964
965 void FuncDeclNode::streamTo(SourceStream& s) const
966 {
967     s << Endl << "function " << m_ident << '(' << m_parameter << ')' << m_body;
968 }
969
970 void FuncExprNode::streamTo(SourceStream& s) const
971 {
972     s << "function " << m_ident << '(' << m_parameter << ')' << m_body;
973 }
974
975 } // namespace KJS