JavaScriptCore:
[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 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() : m_numberNeedsParens(false), m_atStartOfStatement(true), m_precedence(PrecExpression) { }
45     UString toString() const { return m_string; }
46     SourceStream& operator<<(const Identifier&);
47     SourceStream& operator<<(const UString&);
48     SourceStream& operator<<(const char*);
49     SourceStream& operator<<(double);
50     SourceStream& operator<<(char);
51     SourceStream& operator<<(EndlType);
52     SourceStream& operator<<(IndentType);
53     SourceStream& operator<<(UnindentType);
54     SourceStream& operator<<(DotExprType);
55     SourceStream& operator<<(Precedence);
56     SourceStream& operator<<(const Node*);
57     template <typename T> SourceStream& operator<<(const RefPtr<T>& n) { return *this << n.get(); }
58
59 private:
60     UString m_string;
61     UString m_spacesForIndentation;
62     bool m_numberNeedsParens;
63     bool m_atStartOfStatement;
64     Precedence m_precedence;
65 };
66
67 // --------
68
69 static UString escapeStringForPrettyPrinting(const UString& s)
70 {
71     UString escapedString;
72
73     for (int i = 0; i < s.size(); i++) {
74         unsigned short c = s.data()[i].unicode();
75         switch (c) {
76             case '\"':
77                 escapedString += "\\\"";
78                 break;
79             case '\n':
80                 escapedString += "\\n";
81                 break;
82             case '\r':
83                 escapedString += "\\r";
84                 break;
85             case '\t':
86                 escapedString += "\\t";
87                 break;
88             case '\\':
89                 escapedString += "\\\\";
90                 break;
91             default:
92                 if (c < 128 && isPrintableChar(c))
93                     escapedString.append(c);
94                 else {
95                     char hexValue[7];
96                     snprintf(hexValue, 7, "\\u%04x", c);
97                     escapedString += hexValue;
98                 }
99         }
100     }
101
102     return escapedString;    
103 }
104
105 static const char* operatorString(Operator oper)
106 {
107     switch (oper) {
108         case OpEqual:
109             return "=";
110         case OpMultEq:
111             return "*=";
112         case OpDivEq:
113             return "/=";
114         case OpPlusEq:
115             return "+=";
116         case OpMinusEq:
117             return "-=";
118         case OpLShift:
119             return "<<=";
120         case OpRShift:
121             return ">>=";
122         case OpURShift:
123             return ">>>=";
124         case OpAndEq:
125             return "&=";
126         case OpXOrEq:
127             return "^=";
128         case OpOrEq:
129             return "|=";
130         case OpModEq:
131             return "%=";
132         case OpPlusPlus:
133             return "++";
134         case OpMinusMinus:
135             return "--";
136     }
137     ASSERT_NOT_REACHED();
138     return "???";
139 }
140
141 static bool isParserRoundTripNumber(const UString& string)
142 {
143     double number = string.toDouble(false, false);
144     if (isnan(number) || isinf(number))
145         return false;
146     return string == UString::from(number);
147 }
148
149 // --------
150
151 SourceStream& SourceStream::operator<<(char c)
152 {
153     m_numberNeedsParens = false;
154     m_atStartOfStatement = false;
155     UChar ch(c);
156     m_string.append(ch);
157     return *this;
158 }
159
160 SourceStream& SourceStream::operator<<(const char* s)
161 {
162     m_numberNeedsParens = false;
163     m_atStartOfStatement = false;
164     m_string += s;
165     return *this;
166 }
167
168 SourceStream& SourceStream::operator<<(double value)
169 {
170     bool needParens = m_numberNeedsParens;
171     m_numberNeedsParens = false;
172     m_atStartOfStatement = false;
173
174     if (needParens)
175         m_string.append('(');
176     m_string += UString::from(value);
177     if (needParens)
178         m_string.append(')');
179
180     return *this;
181 }
182
183 SourceStream& SourceStream::operator<<(const UString& s)
184 {
185     m_numberNeedsParens = false;
186     m_atStartOfStatement = false;
187     m_string += s;
188     return *this;
189 }
190
191 SourceStream& SourceStream::operator<<(const Identifier& s)
192 {
193     m_numberNeedsParens = false;
194     m_atStartOfStatement = false;
195     m_string += s.ustring();
196     return *this;
197 }
198
199 SourceStream& SourceStream::operator<<(const Node* n)
200 {
201     bool needParens = (m_precedence != PrecExpression && n->precedence() > m_precedence) || (m_atStartOfStatement && n->needsParensIfLeftmost());
202     m_precedence = PrecExpression;
203     if (n) {
204         if (needParens)
205             m_string.append('(');
206         n->streamTo(*this);
207         if (needParens)
208             m_string.append(')');
209     }
210     return *this;
211 }
212
213 SourceStream& SourceStream::operator<<(EndlType)
214 {
215     m_numberNeedsParens = false;
216     m_atStartOfStatement = true;
217     m_string.append('\n');
218     m_string.append(m_spacesForIndentation);
219     return *this;
220 }
221
222 SourceStream& SourceStream::operator<<(IndentType)
223 {
224     m_numberNeedsParens = false;
225     m_atStartOfStatement = false;
226     m_spacesForIndentation += "  ";
227     return *this;
228 }
229
230 SourceStream& SourceStream::operator<<(UnindentType)
231 {
232     m_numberNeedsParens = false;
233     m_atStartOfStatement = false;
234     m_spacesForIndentation = m_spacesForIndentation.substr(0, m_spacesForIndentation.size() - 2);
235     return *this;
236 }
237
238 inline SourceStream& SourceStream::operator<<(DotExprType)
239 {
240     m_numberNeedsParens = true;
241     return *this;
242 }
243
244 inline SourceStream& SourceStream::operator<<(Precedence precedence)
245 {
246     m_precedence = precedence;
247     return *this;
248 }
249
250 static void streamLeftAssociativeBinaryOperator(SourceStream& s, Precedence precedence,
251     const char* operatorString, const Node* left, const Node* right)
252 {
253     s << precedence << left
254         << ' ' << operatorString << ' '
255         << static_cast<Precedence>(precedence - 1) << right;
256 }
257
258 template <typename T> static inline void streamLeftAssociativeBinaryOperator(SourceStream& s,
259     Precedence p, const char* o, const RefPtr<T>& l, const RefPtr<T>& r)
260 {
261     streamLeftAssociativeBinaryOperator(s, p, o, l.get(), r.get());
262 }
263
264 // --------
265
266 UString Node::toString() const
267 {
268     SourceStream stream;
269     streamTo(stream);
270     return stream.toString();
271 }
272
273 // --------
274
275 void NullNode::streamTo(SourceStream& s) const
276 {
277     s << "null";
278 }
279
280 void FalseNode::streamTo(SourceStream& s) const
281 {
282     s << "false";
283 }
284
285 void TrueNode::streamTo(SourceStream& s) const
286 {
287     s << "true";
288 }
289
290 void PlaceholderTrueNode::streamTo(SourceStream&) const
291 {
292 }
293
294 void NumberNode::streamTo(SourceStream& s) const
295 {
296     s << value();
297 }
298
299 void StringNode::streamTo(SourceStream& s) const
300 {
301     s << '"' << escapeStringForPrettyPrinting(m_value) << '"';
302 }
303
304 void RegExpNode::streamTo(SourceStream& s) const
305
306     s << '/' <<  m_regExp->pattern() << '/' << m_regExp->flags();
307 }
308
309 void ThisNode::streamTo(SourceStream& s) const
310 {
311     s << "this";
312 }
313
314 void ResolveNode::streamTo(SourceStream& s) const
315 {
316     s << ident;
317 }
318
319 void ElementNode::streamTo(SourceStream& s) const
320 {
321     for (const ElementNode* n = this; n; n = n->next.get()) {
322         for (int i = 0; i < n->elision; i++)
323             s << ',';
324         s << PrecAssignment << n->node;
325         if (n->next)
326             s << ',';
327     }
328 }
329
330 void ArrayNode::streamTo(SourceStream& s) const
331 {
332     s << '[' << element;
333     for (int i = 0; i < elision; i++)
334         s << ',';
335     // Parser consumes one elision comma if there's array elements 
336     // present in the expression.
337     if (opt && element)
338         s << ',';
339     s << ']';
340 }
341
342 void ObjectLiteralNode::streamTo(SourceStream& s) const
343 {
344     if (list)
345         s << "{ " << list << " }";
346     else
347         s << "{ }";
348 }
349
350 void PropertyListNode::streamTo(SourceStream& s) const
351 {
352     s << node;
353     for (const PropertyListNode* n = next.get(); n; n = n->next.get())
354         s << ", " << n->node;
355 }
356
357 void PropertyNode::streamTo(SourceStream& s) const
358 {
359     switch (type) {
360         case Constant: {
361             UString propertyName = name().ustring();
362             if (isParserRoundTripNumber(propertyName))
363                 s << propertyName;
364             else
365                 s << '"' << escapeStringForPrettyPrinting(propertyName) << '"';
366             s << ": " << PrecAssignment << assign;
367             break;
368         }
369         case Getter:
370         case Setter: {
371             const FuncExprNode* func = static_cast<const FuncExprNode*>(assign.get());
372             if (type == Getter)
373                 s << "get \""; 
374             else
375                 s << "set \"";
376             s << escapeStringForPrettyPrinting(name().ustring())
377                 << "\"(" << func->param << ')' << func->body;
378             break;
379         }
380     }
381 }
382
383 void BracketAccessorNode::streamTo(SourceStream& s) const
384 {
385     s << PrecCall << expr1 << "[" << expr2 << "]";
386 }
387
388 void DotAccessorNode::streamTo(SourceStream& s) const
389 {
390     s << DotExpr << PrecCall << expr << "." << ident;
391 }
392
393 void ArgumentListNode::streamTo(SourceStream& s) const
394 {
395     s << PrecAssignment << expr;
396     for (ArgumentListNode* n = next.get(); n; n = n->next.get())
397         s << ", " << PrecAssignment << n->expr;
398 }
399
400 void ArgumentsNode::streamTo(SourceStream& s) const
401 {
402     s << '(' << listNode << ')';
403 }
404
405 void NewExprNode::streamTo(SourceStream& s) const
406 {
407     s << "new " << PrecMember << expr << args;
408 }
409
410 void FunctionCallValueNode::streamTo(SourceStream& s) const
411 {
412     s << PrecCall << expr << args;
413 }
414
415 void FunctionCallResolveNode::streamTo(SourceStream& s) const
416 {
417     s << ident << args;
418 }
419
420 void FunctionCallBracketNode::streamTo(SourceStream& s) const
421 {
422     s << PrecCall << base << "[" << subscript << "]" << args;
423 }
424
425 void FunctionCallDotNode::streamTo(SourceStream& s) const
426 {
427     s << DotExpr << PrecCall << base << "." << ident << args;
428 }
429
430 void PostIncResolveNode::streamTo(SourceStream& s) const
431 {
432     s << m_ident << "++";
433 }
434
435 void PostDecResolveNode::streamTo(SourceStream& s) const
436 {
437     s << m_ident << "--";
438 }
439
440 void PostfixBracketNode::streamTo(SourceStream& s) const
441 {
442     s << PrecCall << m_base << "[" << m_subscript << "]";
443     if (isIncrement())
444         s << "++";
445     else
446         s << "--";
447 }
448
449 void PostfixDotNode::streamTo(SourceStream& s) const
450 {
451     s << DotExpr << PrecCall << m_base << "." << m_ident;
452     if (isIncrement())
453         s << "++";
454     else
455         s << "--";
456 }
457
458 void PostfixErrorNode::streamTo(SourceStream& s) const
459 {
460     s << PrecLeftHandSide << m_expr;
461     if (m_oper == OpPlusPlus)
462         s << "++";
463     else
464         s << "--";
465 }
466
467 void DeleteResolveNode::streamTo(SourceStream& s) const
468 {
469     s << "delete " << m_ident;
470 }
471
472 void DeleteBracketNode::streamTo(SourceStream& s) const
473 {
474     s << "delete " << PrecCall << m_base << "[" << m_subscript << "]";
475 }
476
477 void DeleteDotNode::streamTo(SourceStream& s) const
478 {
479     s << "delete " << DotExpr << PrecCall << m_base << "." << m_ident;
480 }
481
482 void DeleteValueNode::streamTo(SourceStream& s) const
483 {
484     s << "delete " << PrecUnary << m_expr;
485 }
486
487 void VoidNode::streamTo(SourceStream& s) const
488 {
489     s << "void " << PrecUnary << expr;
490 }
491
492 void TypeOfValueNode::streamTo(SourceStream& s) const
493 {
494     s << "typeof " << PrecUnary << m_expr;
495 }
496
497 void TypeOfResolveNode::streamTo(SourceStream& s) const
498 {
499     s << "typeof " << m_ident;
500 }
501
502 void PreIncResolveNode::streamTo(SourceStream& s) const
503 {
504     s << "++" << m_ident;
505 }
506
507 void PreDecResolveNode::streamTo(SourceStream& s) const
508 {
509     s << "--" << m_ident;
510 }
511
512 void PrefixBracketNode::streamTo(SourceStream& s) const
513 {
514     if (isIncrement())
515         s << "++";
516     else
517         s << "--";
518     s << PrecCall << m_base << "[" << m_subscript << "]";
519 }
520
521 void PrefixDotNode::streamTo(SourceStream& s) const
522 {
523     if (isIncrement())
524         s << "++";
525     else
526         s << "--";
527     s << DotExpr << PrecCall << m_base << "." << m_ident;
528 }
529
530 void PrefixErrorNode::streamTo(SourceStream& s) const
531 {
532     if (m_oper == OpPlusPlus)
533         s << "++" << PrecUnary << m_expr;
534     else
535         s << "--" << PrecUnary << m_expr;
536 }
537
538 void UnaryPlusNode::streamTo(SourceStream& s) const
539 {
540     s << "+ " << PrecUnary << m_expr;
541 }
542
543 void NegateNode::streamTo(SourceStream& s) const
544 {
545     s << "- " << PrecUnary << expr;
546 }
547
548 void BitwiseNotNode::streamTo(SourceStream& s) const
549 {
550     s << "~" << PrecUnary << expr;
551 }
552
553 void LogicalNotNode::streamTo(SourceStream& s) const
554 {
555     s << "!" << PrecUnary << expr;
556 }
557
558 void MultNode::streamTo(SourceStream& s) const
559 {
560     streamLeftAssociativeBinaryOperator(s, precedence(), "*", term1, term2);
561 }
562
563 void DivNode::streamTo(SourceStream& s) const
564 {
565     streamLeftAssociativeBinaryOperator(s, precedence(), "/", term1, term2);
566 }
567
568 void ModNode::streamTo(SourceStream& s) const
569 {
570     streamLeftAssociativeBinaryOperator(s, precedence(), "%", term1, term2);
571 }
572
573 void AddNode::streamTo(SourceStream& s) const
574 {
575     streamLeftAssociativeBinaryOperator(s, precedence(), "+", term1, term2);
576 }
577
578 void SubNode::streamTo(SourceStream& s) const
579 {
580     streamLeftAssociativeBinaryOperator(s, precedence(), "-", term1, term2);
581 }
582
583 void LeftShiftNode::streamTo(SourceStream& s) const
584 {
585     streamLeftAssociativeBinaryOperator(s, precedence(), "<<", term1, term2);
586 }
587
588 void RightShiftNode::streamTo(SourceStream& s) const
589 {
590     streamLeftAssociativeBinaryOperator(s, precedence(), ">>", term1, term2);
591 }
592
593 void UnsignedRightShiftNode::streamTo(SourceStream& s) const
594 {
595     streamLeftAssociativeBinaryOperator(s, precedence(), ">>>", term1, term2);
596 }
597
598 void LessNode::streamTo(SourceStream& s) const
599 {
600     streamLeftAssociativeBinaryOperator(s, precedence(), "<", expr1, expr2);
601 }
602
603 void GreaterNode::streamTo(SourceStream& s) const
604 {
605     streamLeftAssociativeBinaryOperator(s, precedence(), ">", expr1, expr2);
606 }
607
608 void LessEqNode::streamTo(SourceStream& s) const
609 {
610     streamLeftAssociativeBinaryOperator(s, precedence(), "<=", expr1, expr2);
611 }
612
613 void GreaterEqNode::streamTo(SourceStream& s) const
614 {
615     streamLeftAssociativeBinaryOperator(s, precedence(), ">=", expr1, expr2);
616 }
617
618 void InstanceOfNode::streamTo(SourceStream& s) const
619 {
620     streamLeftAssociativeBinaryOperator(s, precedence(), "instanceof", expr1, expr2);
621 }
622
623 void InNode::streamTo(SourceStream& s) const
624 {
625     streamLeftAssociativeBinaryOperator(s, precedence(), "in", expr1, expr2);
626 }
627
628 void EqualNode::streamTo(SourceStream& s) const
629 {
630     streamLeftAssociativeBinaryOperator(s, precedence(), "==", expr1, expr2);
631 }
632
633 void NotEqualNode::streamTo(SourceStream& s) const
634 {
635     streamLeftAssociativeBinaryOperator(s, precedence(), "!=", expr1, expr2);
636 }
637
638 void StrictEqualNode::streamTo(SourceStream& s) const
639 {
640     streamLeftAssociativeBinaryOperator(s, precedence(), "===", expr1, expr2);
641 }
642
643 void NotStrictEqualNode::streamTo(SourceStream& s) const
644 {
645     streamLeftAssociativeBinaryOperator(s, precedence(), "!==", expr1, expr2);
646 }
647
648 void BitAndNode::streamTo(SourceStream& s) const
649 {
650     streamLeftAssociativeBinaryOperator(s, precedence(), "&", expr1, expr2);
651 }
652
653 void BitXOrNode::streamTo(SourceStream& s) const
654 {
655     streamLeftAssociativeBinaryOperator(s, precedence(), "^", expr1, expr2);
656 }
657
658 void BitOrNode::streamTo(SourceStream& s) const
659 {
660     streamLeftAssociativeBinaryOperator(s, precedence(), "|", expr1, expr2);
661 }
662
663 void LogicalAndNode::streamTo(SourceStream& s) const
664 {
665     streamLeftAssociativeBinaryOperator(s, precedence(), "&&", expr1, expr2);
666 }
667
668 void LogicalOrNode::streamTo(SourceStream& s) const
669 {
670     streamLeftAssociativeBinaryOperator(s, precedence(), "||", expr1, expr2);
671 }
672
673 void ConditionalNode::streamTo(SourceStream& s) const
674 {
675     s << PrecLogicalOr << logical
676         << " ? " << PrecAssignment << expr1
677         << " : " << PrecAssignment << expr2;
678 }
679
680 void ReadModifyResolveNode::streamTo(SourceStream& s) const
681 {
682     s << m_ident << ' ' << operatorString(m_oper) << ' ' << PrecAssignment << m_right;
683 }
684
685 void AssignResolveNode::streamTo(SourceStream& s) const
686 {
687     s << m_ident << " = " << PrecAssignment << m_right;
688 }
689
690 void ReadModifyBracketNode::streamTo(SourceStream& s) const
691 {
692     s << PrecCall << m_base << '[' << m_subscript << "] "
693         << operatorString(m_oper) << ' ' << PrecAssignment << m_right;
694 }
695
696 void AssignBracketNode::streamTo(SourceStream& s) const
697 {
698     s << PrecCall << m_base << '[' << m_subscript << "] = " << PrecAssignment << m_right;
699 }
700
701 void ReadModifyDotNode::streamTo(SourceStream& s) const
702 {
703     s << DotExpr << PrecCall << m_base << "." << m_ident << ' '
704         << operatorString(m_oper) << ' ' << PrecAssignment << m_right;
705 }
706
707 void AssignDotNode::streamTo(SourceStream& s) const
708 {
709     s << DotExpr << PrecCall << m_base << "." << m_ident << " = " << PrecAssignment << m_right;
710 }
711
712 void AssignErrorNode::streamTo(SourceStream& s) const
713 {
714     s << PrecLeftHandSide << m_left << ' '
715         << operatorString(m_oper) << ' ' << PrecAssignment << m_right;
716 }
717
718 void CommaNode::streamTo(SourceStream& s) const
719 {
720     s << PrecAssignment << expr1 << ", " << PrecAssignment << expr2;
721 }
722
723 void ConstDeclNode::streamTo(SourceStream& s) const
724 {
725     s << ident;
726     if (init)
727         s << " = " << init;
728     for (ConstDeclNode* n = next.get(); n; n = n->next.get()) {
729         s << ", " << ident;
730         if (init)
731             s << " = " << init;
732     }
733 }
734
735 void ConstStatementNode::streamTo(SourceStream& s) const
736 {
737     s << Endl << "const " << next << ';';
738 }
739
740 static inline void statementListStreamTo(const Vector<RefPtr<StatementNode> >& nodes, SourceStream& s)
741 {
742     for (Vector<RefPtr<StatementNode> >::const_iterator ptr = nodes.begin(); ptr != nodes.end(); ptr++)
743         s << *ptr;
744 }
745     
746 void BlockNode::streamTo(SourceStream& s) const
747 {
748     s << Endl << "{" << Indent;
749     statementListStreamTo(m_children, s); 
750     s << Unindent << Endl << "}";
751 }
752
753 void ScopeNode::streamTo(SourceStream& s) const
754 {
755     s << Endl << "{" << Indent;
756
757     bool printedVar = false;
758     for (size_t i = 0; i < m_varStack.size(); ++i) {
759         if (m_varStack[i].second == 0) {
760             if (!printedVar) {
761                 s << Endl << "var ";
762                 printedVar = true;
763             } else
764                 s << ", ";
765             s << m_varStack[i].first;
766         }
767     }
768     if (printedVar)
769         s << ';';
770
771     statementListStreamTo(m_children, s); 
772     s << Unindent << Endl << "}";
773 }
774
775 void EmptyStatementNode::streamTo(SourceStream& s) const
776 {
777     s << Endl << ';';
778 }
779
780 void ExprStatementNode::streamTo(SourceStream& s) const
781 {
782     s << Endl << expr << ';';
783 }
784
785 void VarStatementNode::streamTo(SourceStream& s) const
786 {
787     s << Endl << "var " << expr << ';';
788 }
789
790 void IfNode::streamTo(SourceStream& s) const
791 {
792     s << Endl << "if (" << m_condition << ')' << Indent << m_ifBlock << Unindent;
793 }
794
795 void IfElseNode::streamTo(SourceStream& s) const
796 {
797     IfNode::streamTo(s);
798     s << Endl << "else" << Indent << m_elseBlock << Unindent;
799 }
800
801 void DoWhileNode::streamTo(SourceStream& s) const
802 {
803     s << Endl << "do " << Indent << statement << Unindent << Endl
804         << "while (" << expr << ");";
805 }
806
807 void WhileNode::streamTo(SourceStream& s) const
808 {
809   s << Endl << "while (" << expr << ')' << Indent << statement << Unindent;
810 }
811
812 void ForNode::streamTo(SourceStream& s) const
813 {
814     s << Endl << "for ("
815         << (expr1WasVarDecl ? "var " : "")
816         << expr1
817         << "; " << expr2
818         << "; " << expr3
819         << ')' << Indent << statement << Unindent;
820 }
821
822 void ForInNode::streamTo(SourceStream& s) const
823 {
824     s << Endl << "for (";
825     if (identIsVarDecl) {
826         s << "var ";
827         if (init)
828             s << init;
829         else
830             s << PrecLeftHandSide << lexpr;
831     } else
832         s << PrecLeftHandSide << lexpr;
833
834     s << " in " << expr << ')' << Indent << statement << Unindent;
835 }
836
837 void ContinueNode::streamTo(SourceStream& s) const
838 {
839     s << Endl << "continue";
840     if (!ident.isNull())
841         s << ' ' << ident;
842     s << ';';
843 }
844
845 void BreakNode::streamTo(SourceStream& s) const
846 {
847     s << Endl << "break";
848     if (!ident.isNull())
849         s << ' ' << ident;
850     s << ';';
851 }
852
853 void ReturnNode::streamTo(SourceStream& s) const
854 {
855     s << Endl << "return";
856     if (value)
857         s << ' ' << value;
858     s << ';';
859 }
860
861 void WithNode::streamTo(SourceStream& s) const
862 {
863     s << Endl << "with (" << expr << ") " << statement;
864 }
865
866 void CaseClauseNode::streamTo(SourceStream& s) const
867 {
868     s << Endl;
869     if (expr)
870         s << "case " << expr;
871     else
872         s << "default";
873     s << ":" << Indent;
874     statementListStreamTo(m_children, s);
875     s << Unindent;
876 }
877
878 void ClauseListNode::streamTo(SourceStream& s) const
879 {
880     for (const ClauseListNode* n = this; n; n = n->getNext())
881         s << n->getClause();
882 }
883
884 void CaseBlockNode::streamTo(SourceStream& s) const
885 {
886     for (const ClauseListNode* n = list1.get(); n; n = n->getNext())
887         s << n->getClause();
888     s << def;
889     for (const ClauseListNode* n = list2.get(); n; n = n->getNext())
890         s << n->getClause();
891 }
892
893 void SwitchNode::streamTo(SourceStream& s) const
894 {
895     s << Endl << "switch (" << expr << ") {"
896         << Indent << block << Unindent
897         << Endl << "}";
898 }
899
900 void LabelNode::streamTo(SourceStream& s) const
901 {
902     s << Endl << label << ":" << Indent << statement << Unindent;
903 }
904
905 void ThrowNode::streamTo(SourceStream& s) const
906 {
907     s << Endl << "throw " << expr << ';';
908 }
909
910 void TryNode::streamTo(SourceStream& s) const
911 {
912     s << Endl << "try " << tryBlock;
913     if (catchBlock)
914         s << Endl << "catch (" << exceptionIdent << ')' << catchBlock;
915     if (finallyBlock)
916         s << Endl << "finally " << finallyBlock;
917 }
918
919 void ParameterNode::streamTo(SourceStream& s) const
920 {
921     s << id;
922     for (ParameterNode* n = next.get(); n; n = n->next.get())
923         s << ", " << n->id;
924 }
925
926 void FuncDeclNode::streamTo(SourceStream& s) const
927 {
928     s << Endl << "function " << ident << '(' << param << ')' << body;
929 }
930
931 void FuncExprNode::streamTo(SourceStream& s) const
932 {
933     s << "function " << ident << '(' << param << ')' << body;
934 }
935
936 }