File indexing completed on 2024-05-12 15:43:29

0001 /*
0002  *  This file is part of the KDE libraries
0003  *  Copyright (C) 2002 Harri Porten (porten@kde.org)
0004  *  Copyright (C) 2003, 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
0005  *  Copyright (C) 2003 Apple Computer, Inc.
0006  *
0007  *  This library is free software; you can redistribute it and/or
0008  *  modify it under the terms of the GNU Library General Public
0009  *  License as published by the Free Software Foundation; either
0010  *  version 2 of the License, or (at your option) any later version.
0011  *
0012  *  This library is distributed in the hope that it will be useful,
0013  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
0014  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0015  *  Library General Public License for more details.
0016  *
0017  *  You should have received a copy of the GNU Library General Public License
0018  *  along with this library; see the file COPYING.LIB.  If not, write to
0019  *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0020  *  Boston, MA 02110-1301, USA.
0021  *
0022  */
0023 
0024 #include <ctype.h>
0025 #include <stdio.h>
0026 
0027 #include "nodes.h"
0028 #include "function.h"
0029 #include "scriptfunction.h"
0030 
0031 #include <typeinfo>
0032 
0033 #define NOINLINE
0034 #if defined(WTF_COMPILER_CWP)
0035 #pragma auto_inline off
0036 #elif defined(WTF_COMPILER_MSVC)
0037 #pragma auto_inline(off)
0038 #elif defined(WTF_COMPILER_GCC)
0039 // #undef  NOINLINE
0040 // #define NOINLINE    __attribute__ (noinline)
0041 #endif
0042 
0043 // GCC cstring uses these automatically, but not all implementations do.
0044 using std::strlen;
0045 using std::strcpy;
0046 using std::strncpy;
0047 using std::memset;
0048 using std::memcpy;
0049 
0050 namespace KJS
0051 {
0052 const bool kDontQuote = false, kQuote = true;
0053 
0054 /**
0055  * A simple text streaming class that helps with code indentation.
0056  */
0057 class SourceStream
0058 {
0059 public:
0060     enum eEndl     { Endl };
0061     enum eIndent   { Indent };
0062     enum eUnindent { Unindent };
0063 
0064     static const int kBufSize = 2048;
0065     typedef unsigned short UTF16;
0066     SourceStream() : indent(0), bufUsed(0), reindentLine(0), reindenting(false) {}
0067     const UString &toString()
0068     {
0069         flush();
0070         return str;
0071     }
0072     SourceStream &operator<<(const Identifier &s) NOINLINE;
0073     SourceStream &operator<<(const UString &s) NOINLINE;
0074     SourceStream &operator<<(const char *s) NOINLINE;
0075     SourceStream &operator<<(char s) NOINLINE;
0076     SourceStream &operator<<(eEndl) NOINLINE;
0077     SourceStream &operator<<(const Node *n) NOINLINE;
0078     SourceStream &operator<<(const StatementNode *n) NOINLINE;
0079     SourceStream &operator<<(Operator op) NOINLINE;
0080     inline SourceStream &operator<<(eIndent)
0081     {
0082         indent += 2;
0083         return *this;
0084     }
0085     inline SourceStream &operator<<(eUnindent)
0086     {
0087         indent -= 2;
0088         return *this;
0089     }
0090     SourceStream &append(const Node *expr1, const char *sep, const Node *expr2) NOINLINE;
0091     SourceStream &append(const RefPtr<Node> &expr1, const char *sep, const RefPtr<Node> &expr2) NOINLINE;
0092     SourceStream &append(const UTF16 *src, int srcLen) NOINLINE;
0093     SourceStream &append(const UString &inStr, bool quote) NOINLINE;
0094     template <typename T>
0095     inline SourceStream &operator<<(const RefPtr<T> &n)
0096     {
0097         return this->operator<<(n.get());
0098     }
0099 
0100     void setReindenting(int baseLine)
0101     {
0102         reindenting = true;
0103         reindentLine = baseLine;
0104     }
0105 private:
0106     UString str;
0107     int indent;
0108     int bufUsed;
0109     UTF16 buffer[kBufSize];
0110     void flush() NOINLINE;
0111     void put(UTF16 ch)
0112     {
0113         buffer[bufUsed++] = ch;
0114     }
0115     void put(char ch)
0116     {
0117         buffer[bufUsed++] = static_cast<unsigned char>(ch);
0118     }
0119 
0120     int  reindentLine;
0121     bool reindenting;
0122 };
0123 }
0124 
0125 using namespace KJS;
0126 
0127 SourceStream &SourceStream::operator<<(Operator op)
0128 {
0129     assert(op == OpPlusPlus || op == OpMinusMinus);
0130     return *this << ((op == OpPlusPlus) ? "++" : "--");
0131 }
0132 
0133 void SourceStream::flush()
0134 {
0135     if (bufUsed) {
0136         str.append(UString(reinterpret_cast<const UChar *>(buffer), bufUsed));
0137         bufUsed = 0;
0138     }
0139 }
0140 
0141 SourceStream &SourceStream::operator<<(char c)
0142 {
0143     if (bufUsed == kBufSize) {
0144         flush();
0145     }
0146     put(c);
0147     return *this;
0148 }
0149 
0150 SourceStream &SourceStream::operator<<(const char *s)
0151 {
0152     assert(strlen(s) < 100);
0153     if (bufUsed > kBufSize - 100) {
0154         flush();
0155     }
0156 
0157     unsigned char ch;
0158     int i = bufUsed;
0159     --s;
0160     for (UTF16 *dst = &buffer[i] - 1; (ch = *++s) != 0; ++i) {
0161         *++dst = ch;
0162     }
0163     bufUsed = i;
0164 
0165     return *this;
0166 }
0167 
0168 SourceStream &SourceStream::operator<<(const UString &s)
0169 {
0170     return append(&s.data()->uc, s.size());
0171 }
0172 
0173 SourceStream &SourceStream::operator<<(const Identifier &s)
0174 {
0175     return append(s.ustring(), kDontQuote);
0176 }
0177 
0178 SourceStream &SourceStream::operator<<(const StatementNode *n)
0179 {
0180     if (n) {
0181         // Update debug info with new line numbers if needed.
0182         // Note that streamTo will output endLine first thing,
0183         // so we want the next line in the debug info
0184         int firstLine = reindentLine + 1;
0185         n->streamTo(*this);
0186         if (reindenting) {
0187             n->setLoc(firstLine, reindentLine - 1);
0188         }
0189     }
0190     return *this;
0191 }
0192 
0193 SourceStream &SourceStream::operator<<(const Node *n)
0194 {
0195     if (n) {
0196         n->streamTo(*this);
0197     }
0198     return *this;
0199 }
0200 
0201 SourceStream &SourceStream::operator<<(eEndl)
0202 {
0203     if (bufUsed > kBufSize - 1 - indent) {
0204         flush();
0205     }
0206     put('\n');
0207     ++reindentLine;
0208 
0209     if (indent > 0) {
0210         UTF16 *dst = &buffer[bufUsed];
0211         for (int i = indent; i > 0; --i) {
0212             *dst++ = ' ';
0213         }
0214         bufUsed += indent;
0215     }
0216 
0217     return *this;
0218 }
0219 
0220 SourceStream &SourceStream::append(const Node *expr1, const char *sep, const Node *expr2)
0221 {
0222     return *this << expr1 << sep << expr2;
0223 }
0224 
0225 SourceStream &
0226 SourceStream::append(const RefPtr<Node> &expr1, const char *sep, const RefPtr<Node> &expr2)
0227 {
0228     return *this << expr1 << sep << expr2;
0229 }
0230 
0231 SourceStream &SourceStream::append(const UTF16 *src, int srcLen)
0232 {
0233     if (kBufSize - bufUsed < srcLen) {
0234         flush();
0235     }
0236     if (kBufSize - bufUsed < srcLen) {
0237         str.append(UString(reinterpret_cast<const UChar *>(src), srcLen));
0238     } else {
0239         UTF16 *dst = &buffer[bufUsed];
0240         bufUsed += srcLen;
0241 //    while (--srcLen >= 0)
0242         while (srcLen-- > 0) {
0243             *dst++ = *src++;
0244         }
0245     }
0246 
0247     return *this;
0248 }
0249 
0250 // Append a quoted string
0251 SourceStream &SourceStream::append(const UString &inStr, bool quote)
0252 {
0253     if (quote) {
0254         *this << '"';
0255     }
0256     const UTF16 *src = &inStr.data()->uc;
0257     const size_t size = inStr.size();
0258     for (size_t i = 0; i < size; ++i) {
0259         if (bufUsed >= kBufSize - 8) {
0260             flush();
0261         }
0262         UTF16 c = *src++, esc = '\\';
0263         switch (c) {
0264         case '\"':                break;
0265         case '\n':    c = 'n';    break;
0266         case '\r':    c = 'r';    break;
0267         case '\t':    c = 't';    break;
0268         case '\\':                break;
0269         default:
0270             if (c >= 128 || !isprint(c)) { // ### FIXME: use Unicode tables
0271                 char hexValue[8];
0272                 int len = sprintf(hexValue, (c < 256) ? "\\x%02X" : "\\u%04X", c);
0273                 UTF16 *dst = &buffer[bufUsed];
0274                 bufUsed += len;
0275                 for (int j = 0; j < len; ++j) {
0276                     dst[j] = hexValue[j];
0277                 }
0278                 continue;
0279             }
0280             esc = 0;    // don't escape
0281             break;
0282         }
0283         if (esc) {
0284             put(esc);
0285         }
0286         put(c);
0287     }
0288 
0289     if (quote) {
0290         *this << '"';
0291     }
0292     return *this;
0293 }
0294 
0295 UString FunctionImp::toSource() const
0296 {
0297     SourceStream str;
0298     str << "function ";
0299     str.append(functionName().ustring(), kDontQuote) << '(';
0300     const FunctionBodyNode *body = this->body.get();
0301     const int numParams = body->numParams();
0302     for (int i = 0; i < numParams; ++i) {
0303         if (i > 0) {
0304             str << ", ";
0305         }
0306         str << body->paramName(i).ustring();
0307     }
0308     str << ") ";
0309     body->streamTo(str);
0310 
0311     return str.toString();
0312 }
0313 
0314 UString Node::toString() const
0315 {
0316     SourceStream str;
0317     streamTo(str);
0318 
0319     return str.toString();
0320 }
0321 
0322 UString Node::reindent(int baseLine) const
0323 {
0324     SourceStream str;
0325     str.setReindenting(baseLine);
0326 
0327     streamTo(str);
0328 
0329     return str.toString();
0330 }
0331 
0332 void NullNode::streamTo(SourceStream &s) const
0333 {
0334     s << "null";
0335 }
0336 
0337 void BooleanNode::streamTo(SourceStream &s) const
0338 {
0339     s << (value() ? "true" : "false");
0340 }
0341 
0342 void NumberNode::streamTo(SourceStream &s) const
0343 {
0344     s << UString::from(value());
0345 }
0346 
0347 void StringNode::streamTo(SourceStream &s) const
0348 {
0349     s.append(value(), kQuote);
0350 }
0351 
0352 void RegExpNode::streamTo(SourceStream &s) const
0353 {
0354     s <<  '/' << pattern << '/' << flags;
0355 }
0356 
0357 void ThisNode::streamTo(SourceStream &s) const
0358 {
0359     s << "this";
0360 }
0361 
0362 void VarAccessNode::streamTo(SourceStream &s) const
0363 {
0364     s << ident;
0365 }
0366 
0367 void GroupNode::streamTo(SourceStream &s) const
0368 {
0369     s << '(' << group << ')';
0370 }
0371 
0372 void ElementNode::streamTo(SourceStream &s) const
0373 {
0374     for (const ElementNode *n = this; n; n = n->next.get()) {
0375         for (int i = 0; i < n->elision; i++) {
0376             s << ',';
0377         }
0378         s << n->node;
0379         if (n->next) {
0380             s << ',';
0381         }
0382     }
0383 }
0384 
0385 void ArrayNode::streamTo(SourceStream &s) const
0386 {
0387     s << '[' << element;
0388     for (int i = 0; i < elision; i++) {
0389         s << ',';
0390     }
0391     // Parser consumes one elision comma if there's array elements
0392     // present in the expression.
0393     if (opt && element) {
0394         s << ',';
0395     }
0396     s << ']';
0397 }
0398 
0399 void ObjectLiteralNode::streamTo(SourceStream &s) const
0400 {
0401     if (list) {
0402         s << "{ " << list << " }";
0403     } else {
0404         s << "{ }";
0405     }
0406 }
0407 
0408 void PropertyListNode::streamTo(SourceStream &s) const
0409 {
0410     s << node;
0411 
0412     for (const PropertyListNode *n = next.get(); n; n = n->next.get()) {
0413         s << ", " << n->node;
0414     }
0415 }
0416 
0417 void PropertyNode::streamTo(SourceStream &s) const
0418 {
0419     switch (type) {
0420     case Constant:
0421         s << name << ": " << assign;
0422         break;
0423     case Getter:
0424     case Setter: {
0425         const FuncExprNode *func = static_cast<const FuncExprNode *>(assign.get());
0426         if (type == Getter) {
0427             s << "get ";
0428         } else {
0429             s << "set ";
0430         }
0431 
0432         s << name << '(' << func->param << ')' << func->body;
0433         break;
0434     }
0435     }
0436 }
0437 
0438 void PropertyNameNode::streamTo(SourceStream &s) const
0439 {
0440     s.append(str.ustring(), kQuote);
0441 }
0442 
0443 void BracketAccessorNode::streamTo(SourceStream &s) const
0444 {
0445     s.append(expr1, "[", expr2) << ']';
0446 }
0447 
0448 void DotAccessorNode::streamTo(SourceStream &s) const
0449 {
0450     s << expr << '.' << ident;
0451 }
0452 
0453 void ArgumentListNode::streamTo(SourceStream &s) const
0454 {
0455     s << expr;
0456     for (ArgumentListNode *n = next.get(); n; n = n->next.get()) {
0457         s << ", " << n->expr;
0458     }
0459 }
0460 
0461 void ArgumentsNode::streamTo(SourceStream &s) const
0462 {
0463     s << '(' << list << ')';
0464 }
0465 
0466 void NewExprNode::streamTo(SourceStream &s) const
0467 {
0468     s << "new " << expr << args;
0469 }
0470 
0471 void FunctionCallValueNode::streamTo(SourceStream &s) const
0472 {
0473     s << expr << args;
0474 }
0475 
0476 void FunctionCallReferenceNode::streamTo(SourceStream &s) const
0477 {
0478     s << expr << args;
0479 }
0480 
0481 void PostfixNode::streamTo(SourceStream &s) const
0482 {
0483     s << m_loc << m_oper;
0484 }
0485 
0486 void DeleteReferenceNode::streamTo(SourceStream &s) const
0487 {
0488     s << "delete " << loc;
0489 }
0490 
0491 void DeleteValueNode::streamTo(SourceStream &s) const
0492 {
0493     s << "delete " << m_expr;
0494 }
0495 
0496 void VoidNode::streamTo(SourceStream &s) const
0497 {
0498     s << "void " << expr;
0499 }
0500 
0501 void TypeOfValueNode::streamTo(SourceStream &s) const
0502 {
0503     s << "typeof " << m_expr;
0504 }
0505 
0506 void TypeOfVarNode::streamTo(SourceStream &s) const
0507 {
0508     s << "typeof " << loc;
0509 }
0510 
0511 void PrefixNode::streamTo(SourceStream &s) const
0512 {
0513     s << m_oper << m_loc;
0514 }
0515 
0516 void UnaryPlusNode::streamTo(SourceStream &s) const
0517 {
0518     s << "+ " << expr;
0519 }
0520 
0521 void NegateNode::streamTo(SourceStream &s) const
0522 {
0523     s << "- " << expr;
0524 }
0525 
0526 void BitwiseNotNode::streamTo(SourceStream &s) const
0527 {
0528     s << '~' << expr;
0529 }
0530 
0531 void LogicalNotNode::streamTo(SourceStream &s) const
0532 {
0533     s << '!' << expr;
0534 }
0535 
0536 void BinaryOperatorNode::streamTo(SourceStream &s) const
0537 {
0538     const char *opStr;
0539     switch (oper) {
0540     case OpMult:
0541         opStr = " * ";
0542         break;
0543     case OpDiv:
0544         opStr = " / ";
0545         break;
0546     case OpMod:
0547         opStr = " % ";
0548         break;
0549     case OpPlus:
0550         opStr = " + ";
0551         break;
0552     case OpMinus:
0553         opStr = " - ";
0554         break;
0555     case OpLShift:
0556         opStr = " << ";
0557         break;
0558     case OpRShift:
0559         opStr = " >> ";
0560         break;
0561     case OpURShift:
0562         opStr = " >>> ";
0563         break;
0564     case OpLess:
0565         opStr = " < ";
0566         break;
0567     case OpGreaterEq:
0568         opStr = " >= ";
0569         break;
0570     case OpGreater:
0571         opStr = " > ";
0572         break;
0573     case OpLessEq:
0574         opStr = " <= ";
0575         break;
0576     case OpIn:
0577         opStr = " in ";
0578         break;
0579     case OpInstanceOf:
0580         opStr = " instanceof ";
0581         break;
0582     case OpEqEq:
0583         opStr = " == ";
0584         break;
0585     case OpNotEq:
0586         opStr = " != ";
0587         break;
0588     case OpStrEq:
0589         opStr = " === ";
0590         break;
0591     case OpStrNEq:
0592         opStr = " !== ";
0593         break;
0594     case OpBitAnd:
0595         opStr = " & ";
0596         break;
0597     case OpBitXOr:
0598         opStr = " ^ ";
0599         break;
0600     case OpBitOr:
0601         opStr = " | ";
0602         break;
0603     default:
0604         assert(!"Unhandled case in BinaryOperatorNode::streamTo()");
0605         opStr = " ??? ";
0606         break;
0607     }
0608     s.append(expr1, opStr, expr2);
0609 }
0610 
0611 void BinaryLogicalNode::streamTo(SourceStream &s) const
0612 {
0613     s.append(expr1, (oper == OpAnd ? " && " : " || "), expr2);
0614 }
0615 
0616 void ConditionalNode::streamTo(SourceStream &s) const
0617 {
0618     s << logical << " ? ";
0619     s.append(expr1, " : ", expr2);
0620 }
0621 
0622 static void streamAssignmentOperatorTo(SourceStream &s, Operator oper)
0623 {
0624     const char *opStr;
0625     switch (oper) {
0626     case OpEqual:
0627         opStr = " = ";
0628         break;
0629     case OpMultEq:
0630         opStr = " *= ";
0631         break;
0632     case OpDivEq:
0633         opStr = " /= ";
0634         break;
0635     case OpPlusEq:
0636         opStr = " += ";
0637         break;
0638     case OpMinusEq:
0639         opStr = " -= ";
0640         break;
0641     case OpLShift:
0642         opStr = " <<= ";
0643         break;
0644     case OpRShift:
0645         opStr = " >>= ";
0646         break;
0647     case OpURShift:
0648         opStr = " >>>= ";
0649         break;
0650     case OpAndEq:
0651         opStr = " &= ";
0652         break;
0653     case OpXOrEq:
0654         opStr = " ^= ";
0655         break;
0656     case OpOrEq:
0657         opStr = " |= ";
0658         break;
0659     case OpModEq:
0660         opStr = " %= ";
0661         break;
0662     default:
0663         opStr = " ?= ";
0664     }
0665     s << opStr;
0666 }
0667 
0668 void AssignNode::streamTo(SourceStream &s) const
0669 {
0670     s << m_loc;
0671     streamAssignmentOperatorTo(s, m_oper);
0672     s << m_right;
0673 //  s.append(m_ident, opStr, m_right);
0674 }
0675 
0676 void CommaNode::streamTo(SourceStream &s) const
0677 {
0678     s.append(expr1, ", ", expr2);
0679 }
0680 
0681 void AssignExprNode::streamTo(SourceStream &s) const
0682 {
0683     s << " = " << expr;
0684 }
0685 
0686 void VarDeclNode::streamTo(SourceStream &s) const
0687 {
0688     s << ident << init;
0689 }
0690 
0691 void VarDeclListNode::streamTo(SourceStream &s) const
0692 {
0693     s << "var " << var;
0694     for (VarDeclListNode *n = next.get(); n; n = n->next.get()) {
0695         s << ", " << n->var;
0696     }
0697 }
0698 
0699 void VarStatementNode::streamTo(SourceStream &s) const
0700 {
0701     s << SourceStream::Endl << next << ';';
0702 }
0703 
0704 void BlockNode::streamTo(SourceStream &s) const
0705 {
0706     s << SourceStream::Endl << '{' << SourceStream::Indent
0707       << source << SourceStream::Unindent << SourceStream::Endl << '}';
0708 }
0709 
0710 void ProgramNode::streamTo(SourceStream &s) const
0711 {
0712     // we don't want braces here, unlike in the above
0713     s << source << SourceStream::Endl;
0714 }
0715 
0716 void EmptyStatementNode::streamTo(SourceStream &s) const
0717 {
0718     s << SourceStream::Endl << ';';
0719 }
0720 
0721 void ExprStatementNode::streamTo(SourceStream &s) const
0722 {
0723     s << SourceStream::Endl << expr << ';';
0724 }
0725 
0726 void IfNode::streamTo(SourceStream &s) const
0727 {
0728     s << SourceStream::Endl << "if (" << expr << ')' << SourceStream::Indent
0729       << statement1 << SourceStream::Unindent;
0730     if (statement2)
0731         s << SourceStream::Endl << "else" << SourceStream::Indent
0732           << statement2 << SourceStream::Unindent;
0733 }
0734 
0735 void DoWhileNode::streamTo(SourceStream &s) const
0736 {
0737     s << SourceStream::Endl << "do " << SourceStream::Indent
0738       << statement << SourceStream::Unindent << SourceStream::Endl
0739       << "while (" << expr << ");";
0740 }
0741 
0742 void WhileNode::streamTo(SourceStream &s) const
0743 {
0744     s << SourceStream::Endl << "while (" << expr << ')' << SourceStream::Indent
0745       << statement << SourceStream::Unindent;
0746 }
0747 
0748 void ForNode::streamTo(SourceStream &s) const
0749 {
0750     s << SourceStream::Endl << "for ("
0751       << expr1
0752       << "; " << expr2
0753       << "; " << expr3
0754       << ')' << SourceStream::Indent << statement << SourceStream::Unindent;
0755 }
0756 
0757 void ForInNode::streamTo(SourceStream &s) const
0758 {
0759     s << SourceStream::Endl << "for (";
0760     if (varDecl) {
0761         s << "var " << varDecl;
0762     } else {
0763         s << lexpr;
0764     }
0765 
0766     s << " in " << expr << ')' << SourceStream::Indent
0767       << statement << SourceStream::Unindent;
0768 }
0769 
0770 void ContinueNode::streamTo(SourceStream &s) const
0771 {
0772     s << SourceStream::Endl << "continue";
0773     if (!ident.isNull()) {
0774         s << ' ' << ident;
0775     }
0776     s << ';';
0777 }
0778 
0779 void BreakNode::streamTo(SourceStream &s) const
0780 {
0781     s << SourceStream::Endl << "break";
0782     if (!ident.isNull()) {
0783         s << ' ' << ident;
0784     }
0785     s << ';';
0786 }
0787 
0788 void ReturnNode::streamTo(SourceStream &s) const
0789 {
0790     s << SourceStream::Endl << "return";
0791     if (value) {
0792         s << ' ' << value;
0793     }
0794     s << ';';
0795 }
0796 
0797 void WithNode::streamTo(SourceStream &s) const
0798 {
0799     s << SourceStream::Endl << "with (" << expr << ") "
0800       << statement;
0801 }
0802 
0803 void CaseClauseNode::streamTo(SourceStream &s) const
0804 {
0805     s << SourceStream::Endl;
0806     if (expr) {
0807         s << "case " << expr;
0808     } else {
0809         s << "default";
0810     }
0811     s << ':' << SourceStream::Indent;
0812     if (source) {
0813         s << source;
0814     }
0815     s << SourceStream::Unindent;
0816 }
0817 
0818 void ClauseListNode::streamTo(SourceStream &s) const
0819 {
0820     for (const ClauseListNode *n = this; n; n = n->getNext()) {
0821         s << n->getClause();
0822     }
0823 }
0824 
0825 void CaseBlockNode::streamTo(SourceStream &s) const
0826 {
0827     for (const ClauseListNode *n = list1.get(); n; n = n->getNext()) {
0828         s << n->getClause();
0829     }
0830     if (def) {
0831         s << def;
0832     }
0833     for (const ClauseListNode *n = list2.get(); n; n = n->getNext()) {
0834         s << n->getClause();
0835     }
0836 }
0837 
0838 void SwitchNode::streamTo(SourceStream &s) const
0839 {
0840     s << SourceStream::Endl << "switch (" << expr << ") {"
0841       << SourceStream::Indent << block << SourceStream::Unindent
0842       << SourceStream::Endl << '}';
0843 }
0844 
0845 void LabelNode::streamTo(SourceStream &s) const
0846 {
0847     s << SourceStream::Endl << label << ':' << SourceStream::Indent
0848       << statement << SourceStream::Unindent;
0849 }
0850 
0851 void ThrowNode::streamTo(SourceStream &s) const
0852 {
0853     s << SourceStream::Endl << "throw " << expr << ';';
0854 }
0855 
0856 void TryNode::streamTo(SourceStream &s) const
0857 {
0858     s << SourceStream::Endl << "try " << tryBlock;
0859     if (catchBlock) {
0860         s << SourceStream::Endl << "catch (" << exceptionIdent << ')' << catchBlock;
0861     }
0862     if (finallyBlock) {
0863         s << SourceStream::Endl << "finally " << finallyBlock;
0864     }
0865 }
0866 
0867 void ParameterNode::streamTo(SourceStream &s) const
0868 {
0869     s << id;
0870     for (ParameterNode *n = next.get(); n; n = n->next.get()) {
0871         s << ", " << n->id;
0872     }
0873 }
0874 
0875 void FuncDeclNode::streamTo(SourceStream &s) const
0876 {
0877     s << SourceStream::Endl << "function " << ident << '(' << param << ')' << body;
0878 }
0879 
0880 void FuncExprNode::streamTo(SourceStream &s) const
0881 {
0882     s << "function " << ident << '(' << param << ')' << body;
0883 }
0884 
0885 void SourceElementsNode::streamTo(SourceStream &s) const
0886 {
0887     for (const SourceElementsNode *n = this; n; n = n->next.get()) {
0888         s << n->node;
0889     }
0890 }
0891 
0892 void PackageNameNode::streamTo(SourceStream &s) const
0893 {
0894     if (names) {
0895         s << names << '.';
0896     }
0897     s << id;
0898 }
0899 
0900 void ImportStatement::streamTo(SourceStream &s) const
0901 {
0902     s << SourceStream::Endl << "import ";
0903     if (!al.isEmpty()) {
0904         s << al << " = ";
0905     }
0906     s << name << (wld ? ".*;" : ";");
0907 }
0908