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