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