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