1 | /* |
2 | * This file is part of the KDE libraries |
3 | * Copyright (C) 2002 Harri Porten (porten@kde.org) |
4 | * Copyright (C) 2003, 2004, 2005, 2006, 2007 Apple Inc. All rights reserved. |
5 | * Copyright (C) 2003 Apple Computer, Inc. |
6 | * |
7 | * This library is free software; you can redistribute it and/or |
8 | * modify it under the terms of the GNU Library General Public |
9 | * License as published by the Free Software Foundation; either |
10 | * version 2 of the License, or (at your option) any later version. |
11 | * |
12 | * This library is distributed in the hope that it will be useful, |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
15 | * Library General Public License for more details. |
16 | * |
17 | * You should have received a copy of the GNU Library General Public License |
18 | * along with this library; see the file COPYING.LIB. If not, write to |
19 | * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
20 | * Boston, MA 02110-1301, USA. |
21 | * |
22 | */ |
23 | |
24 | #include <ctype.h> |
25 | #include <stdio.h> |
26 | #include <config-kjs.h> |
27 | |
28 | #include "nodes.h" |
29 | #include "function.h" |
30 | #include "scriptfunction.h" |
31 | |
32 | #include <typeinfo> |
33 | |
34 | #define NOINLINE |
35 | #if COMPILER(CWP) |
36 | #pragma auto_inline off |
37 | #elif COMPILER(MSVC) |
38 | #pragma auto_inline(off) |
39 | #elif COMPILER(GCC) |
40 | // #undef NOINLINE |
41 | // #define NOINLINE __attribute__ (noinline) |
42 | #endif |
43 | |
44 | // GCC cstring uses these automatically, but not all implementations do. |
45 | using std::strlen; |
46 | using std::strcpy; |
47 | using std::strncpy; |
48 | using std::memset; |
49 | using std::memcpy; |
50 | |
51 | namespace KJS { |
52 | const bool kDontQuote = false, kQuote = true; |
53 | |
54 | /** |
55 | * A simple text streaming class that helps with code indentation. |
56 | */ |
57 | class SourceStream { |
58 | public: |
59 | enum eEndl { Endl }; |
60 | enum eIndent { Indent }; |
61 | enum eUnindent { Unindent }; |
62 | |
63 | static const int kBufSize = 2048; |
64 | typedef unsigned short UTF16; |
65 | SourceStream () : indent(0), bufUsed(0), reindentLine(0), reindenting(false) {} |
66 | const UString& toString() { flush(); return str; } |
67 | SourceStream& operator<<(const Identifier& s) NOINLINE; |
68 | SourceStream& operator<<(const UString& s) NOINLINE; |
69 | SourceStream& operator<<(const char* s) NOINLINE; |
70 | SourceStream& operator<<(char s) NOINLINE; |
71 | SourceStream& operator<<(eEndl) NOINLINE; |
72 | SourceStream& operator<<(const Node* n) NOINLINE; |
73 | SourceStream& operator<<(const StatementNode* n) NOINLINE; |
74 | SourceStream& operator<<(Operator op) NOINLINE; |
75 | inline SourceStream& operator<<(eIndent) { indent += 2; return *this; } |
76 | inline SourceStream& operator<<(eUnindent) { indent -= 2; return *this; } |
77 | SourceStream& append(const Node* expr1, const char* sep, const Node* expr2) NOINLINE; |
78 | SourceStream& append(const RefPtr<Node>& expr1, const char* sep, const RefPtr<Node>& expr2) NOINLINE; |
79 | SourceStream& append(const UTF16* src, int srcLen) NOINLINE; |
80 | SourceStream& append(const UString& inStr, bool quote) NOINLINE; |
81 | template <typename T> |
82 | inline SourceStream& operator<<(const RefPtr<T>& n) { return this->operator<<(n.get()); } |
83 | |
84 | void setReindenting(int baseLine) { reindenting = true; reindentLine = baseLine; } |
85 | private: |
86 | UString str; |
87 | int indent; |
88 | int bufUsed; |
89 | UTF16 buffer[kBufSize]; |
90 | void flush() NOINLINE; |
91 | void put(UTF16 ch) { buffer[bufUsed++] = ch; } |
92 | void put(char ch) { buffer[bufUsed++] = static_cast<unsigned char>(ch); } |
93 | |
94 | int reindentLine; |
95 | bool reindenting; |
96 | }; |
97 | } |
98 | |
99 | using namespace KJS; |
100 | |
101 | SourceStream& SourceStream::operator<<(Operator op) |
102 | { |
103 | assert(op == OpPlusPlus || op == OpMinusMinus); |
104 | return *this << ((op == OpPlusPlus) ? "++" : "--" ); |
105 | } |
106 | |
107 | void SourceStream::flush() |
108 | { |
109 | if (bufUsed) |
110 | { |
111 | str.append(UString(reinterpret_cast<const UChar*>(buffer), bufUsed)); |
112 | bufUsed = 0; |
113 | } |
114 | } |
115 | |
116 | SourceStream& SourceStream::operator<<(char c) |
117 | { |
118 | if (bufUsed == kBufSize) |
119 | flush(); |
120 | put(c); |
121 | return *this; |
122 | } |
123 | |
124 | SourceStream& SourceStream::operator<<(const char *s) |
125 | { |
126 | assert(strlen(s) < 100); |
127 | if (bufUsed > kBufSize - 100) |
128 | flush(); |
129 | |
130 | unsigned char ch; |
131 | int i = bufUsed; |
132 | --s; |
133 | for (UTF16* dst = &buffer[i] - 1; (ch = *++s) != 0; ++i) |
134 | *++dst = ch; |
135 | bufUsed = i; |
136 | |
137 | return *this; |
138 | } |
139 | |
140 | SourceStream& SourceStream::operator<<(const UString &s) |
141 | { |
142 | return append(&s.data()->uc, s.size()); |
143 | } |
144 | |
145 | SourceStream& SourceStream::operator<<(const Identifier &s) |
146 | { |
147 | return append(s.ustring(), kDontQuote); |
148 | } |
149 | |
150 | SourceStream& SourceStream::operator<<(const StatementNode *n) |
151 | { |
152 | if (n) { |
153 | // Update debug info with new line numbers if needed. |
154 | // Note that streamTo will output endLine first thing, |
155 | // so we want the next line in the debug info |
156 | int firstLine = reindentLine + 1; |
157 | n->streamTo(*this); |
158 | if (reindenting) |
159 | n->setLoc(firstLine, reindentLine - 1); |
160 | } |
161 | return *this; |
162 | } |
163 | |
164 | |
165 | SourceStream& SourceStream::operator<<(const Node *n) |
166 | { |
167 | if (n) |
168 | n->streamTo(*this); |
169 | return *this; |
170 | } |
171 | |
172 | SourceStream& SourceStream::operator<<(eEndl) |
173 | { |
174 | if (bufUsed > kBufSize - 1 - indent) |
175 | flush(); |
176 | put('\n'); |
177 | ++reindentLine; |
178 | |
179 | if (indent > 0) |
180 | { |
181 | UTF16* dst = &buffer[bufUsed]; |
182 | for (int i = indent; i > 0; --i) |
183 | *dst++ = ' '; |
184 | bufUsed += indent; |
185 | } |
186 | |
187 | return *this; |
188 | } |
189 | |
190 | SourceStream& SourceStream::append(const Node* expr1, const char* sep, const Node* expr2) |
191 | { |
192 | return *this << expr1 << sep << expr2; |
193 | } |
194 | |
195 | SourceStream& |
196 | SourceStream::append(const RefPtr<Node>& expr1, const char* sep, const RefPtr<Node>& expr2) |
197 | { |
198 | return *this << expr1 << sep << expr2; |
199 | } |
200 | |
201 | SourceStream& SourceStream::append(const UTF16* src, int srcLen) |
202 | { |
203 | if (kBufSize - bufUsed < srcLen) |
204 | flush(); |
205 | if (kBufSize - bufUsed < srcLen) |
206 | str.append(UString(reinterpret_cast<const UChar*>(src), srcLen)); |
207 | else |
208 | { |
209 | UTF16* dst = &buffer[bufUsed]; |
210 | bufUsed += srcLen; |
211 | // while (--srcLen >= 0) |
212 | while (srcLen-- > 0) |
213 | *dst++ = *src++; |
214 | } |
215 | |
216 | return *this; |
217 | } |
218 | |
219 | // Append a quoted string |
220 | SourceStream& SourceStream::append(const UString& inStr, bool quote) |
221 | { |
222 | if (quote) |
223 | *this << '"'; |
224 | const UTF16* src = &inStr.data()->uc; |
225 | const size_t size = inStr.size(); |
226 | for (size_t i = 0; i < size; ++i) { |
227 | if (bufUsed >= kBufSize - 8) |
228 | flush(); |
229 | UTF16 c = *src++, esc = '\\'; |
230 | switch (c) { |
231 | case '\"': break; |
232 | case '\n': c = 'n'; break; |
233 | case '\r': c = 'r'; break; |
234 | case '\t': c = 't'; break; |
235 | case '\\': break; |
236 | default: |
237 | if (c >= 128 || !isprint(c)) { // ### FIXME: use Unicode tables |
238 | char hexValue[8]; |
239 | int len = sprintf(hexValue, (c < 256) ? "\\x%02X" : "\\u%04X" , c); |
240 | UTF16* dst = &buffer[bufUsed]; |
241 | bufUsed += len; |
242 | for (int j = 0; j < len; ++j) |
243 | dst[j] = hexValue[j]; |
244 | continue; |
245 | } |
246 | esc = 0; // don't escape |
247 | break; |
248 | } |
249 | if (esc) put(esc); |
250 | put(c); |
251 | } |
252 | |
253 | if (quote) |
254 | *this << '"'; |
255 | return *this; |
256 | } |
257 | |
258 | UString FunctionImp::toSource() const |
259 | { |
260 | SourceStream str; |
261 | str << "function " ; |
262 | str.append(functionName().ustring(), kDontQuote) << '('; |
263 | const FunctionBodyNode* body = this->body.get(); |
264 | const int numParams = body->numParams(); |
265 | for (int i = 0; i < numParams; ++i) { |
266 | if (i > 0) |
267 | str << ", " ; |
268 | str << body->paramName(i).ustring(); |
269 | } |
270 | str << ") " ; |
271 | body->streamTo(str); |
272 | |
273 | return str.toString(); |
274 | } |
275 | |
276 | UString Node::toString() const |
277 | { |
278 | SourceStream str; |
279 | streamTo(str); |
280 | |
281 | return str.toString(); |
282 | } |
283 | |
284 | UString Node::reindent(int baseLine) const |
285 | { |
286 | SourceStream str; |
287 | str.setReindenting(baseLine); |
288 | |
289 | streamTo(str); |
290 | |
291 | return str.toString(); |
292 | } |
293 | |
294 | void NullNode::streamTo(SourceStream &s) const { s << "null" ; } |
295 | |
296 | void BooleanNode::streamTo(SourceStream &s) const |
297 | { |
298 | s << (value() ? "true" : "false" ); |
299 | } |
300 | |
301 | void NumberNode::streamTo(SourceStream &s) const |
302 | { |
303 | s << UString::from(value()); |
304 | } |
305 | |
306 | void StringNode::streamTo(SourceStream &s) const |
307 | { |
308 | s.append(value(), kQuote); |
309 | } |
310 | |
311 | void RegExpNode::streamTo(SourceStream &s) const |
312 | { |
313 | s << '/' << pattern << '/' << flags; |
314 | } |
315 | |
316 | void ThisNode::streamTo(SourceStream &s) const { s << "this" ; } |
317 | |
318 | void VarAccessNode::streamTo(SourceStream &s) const { s << ident; } |
319 | |
320 | void GroupNode::streamTo(SourceStream &s) const |
321 | { |
322 | s << '(' << group << ')'; |
323 | } |
324 | |
325 | void ElementNode::streamTo(SourceStream &s) const |
326 | { |
327 | for (const ElementNode *n = this; n; n = n->next.get()) { |
328 | for (int i = 0; i < n->elision; i++) |
329 | s << ','; |
330 | s << n->node; |
331 | if (n->next) |
332 | s << ','; |
333 | } |
334 | } |
335 | |
336 | void ArrayNode::streamTo(SourceStream &s) const |
337 | { |
338 | s << '[' << element; |
339 | for (int i = 0; i < elision; i++) |
340 | s << ','; |
341 | // Parser consumes one elision comma if there's array elements |
342 | // present in the expression. |
343 | if (opt && element) |
344 | s << ','; |
345 | s << ']'; |
346 | } |
347 | |
348 | void ObjectLiteralNode::streamTo(SourceStream &s) const |
349 | { |
350 | if (list) |
351 | s << "{ " << list << " }" ; |
352 | else |
353 | s << "{ }" ; |
354 | } |
355 | |
356 | void PropertyListNode::streamTo(SourceStream &s) const |
357 | { |
358 | s << node; |
359 | |
360 | for (const PropertyListNode *n = next.get(); n; n = n->next.get()) |
361 | s << ", " << n->node; |
362 | } |
363 | |
364 | void PropertyNode::streamTo(SourceStream &s) const |
365 | { |
366 | switch (type) { |
367 | case Constant: |
368 | s << name << ": " << assign; |
369 | break; |
370 | case Getter: |
371 | case Setter: { |
372 | const FuncExprNode *func = static_cast<const FuncExprNode *>(assign.get()); |
373 | if (type == Getter) |
374 | s << "get " ; |
375 | else |
376 | s << "set " ; |
377 | |
378 | s << name << '(' << func->param << ')' << func->body; |
379 | break; |
380 | } |
381 | } |
382 | } |
383 | |
384 | void PropertyNameNode::streamTo(SourceStream &s) const |
385 | { |
386 | s.append(str.ustring(), kQuote); |
387 | } |
388 | |
389 | void BracketAccessorNode::streamTo(SourceStream &s) const |
390 | { |
391 | s.append(expr1, "[" , expr2) << ']'; |
392 | } |
393 | |
394 | void DotAccessorNode::streamTo(SourceStream &s) const |
395 | { |
396 | s << expr << '.' << ident; |
397 | } |
398 | |
399 | void ArgumentListNode::streamTo(SourceStream &s) const |
400 | { |
401 | s << expr; |
402 | for (ArgumentListNode *n = next.get(); n; n = n->next.get()) |
403 | s << ", " << n->expr; |
404 | } |
405 | |
406 | void ArgumentsNode::streamTo(SourceStream &s) const |
407 | { |
408 | s << '(' << list << ')'; |
409 | } |
410 | |
411 | void NewExprNode::streamTo(SourceStream &s) const |
412 | { |
413 | s << "new " << expr << args; |
414 | } |
415 | |
416 | void FunctionCallValueNode::streamTo(SourceStream &s) const |
417 | { |
418 | s << expr << args; |
419 | } |
420 | |
421 | void FunctionCallReferenceNode::streamTo(SourceStream &s) const |
422 | { |
423 | s << expr << args; |
424 | } |
425 | |
426 | void PostfixNode::streamTo(SourceStream &s) const |
427 | { |
428 | s << m_loc << m_oper; |
429 | } |
430 | |
431 | void DeleteReferenceNode::streamTo(SourceStream &s) const |
432 | { |
433 | s << "delete " << loc; |
434 | } |
435 | |
436 | void DeleteValueNode::streamTo(SourceStream &s) const |
437 | { |
438 | s << "delete " << m_expr; |
439 | } |
440 | |
441 | void VoidNode::streamTo(SourceStream &s) const |
442 | { |
443 | s << "void " << expr; |
444 | } |
445 | |
446 | void TypeOfValueNode::streamTo(SourceStream &s) const |
447 | { |
448 | s << "typeof " << m_expr; |
449 | } |
450 | |
451 | void TypeOfVarNode::streamTo(SourceStream &s) const |
452 | { |
453 | s << "typeof " << loc; |
454 | } |
455 | |
456 | void PrefixNode::streamTo(SourceStream &s) const |
457 | { |
458 | s << m_oper << m_loc; |
459 | } |
460 | |
461 | void UnaryPlusNode::streamTo(SourceStream &s) const |
462 | { |
463 | s << "+ " << expr; |
464 | } |
465 | |
466 | void NegateNode::streamTo(SourceStream &s) const |
467 | { |
468 | s << "- " << expr; |
469 | } |
470 | |
471 | void BitwiseNotNode::streamTo(SourceStream &s) const |
472 | { |
473 | s << '~' << expr; |
474 | } |
475 | |
476 | void LogicalNotNode::streamTo(SourceStream &s) const |
477 | { |
478 | s << '!' << expr; |
479 | } |
480 | |
481 | void BinaryOperatorNode::streamTo(SourceStream& s) const |
482 | { |
483 | const char* opStr; |
484 | switch (oper) { |
485 | case OpMult: |
486 | opStr = " * " ; |
487 | break; |
488 | case OpDiv: |
489 | opStr = " / " ; |
490 | break; |
491 | case OpMod: |
492 | opStr = " % " ; |
493 | break; |
494 | case OpPlus: |
495 | opStr = " + " ; |
496 | break; |
497 | case OpMinus: |
498 | opStr = " - " ; |
499 | break; |
500 | case OpLShift: |
501 | opStr = " << " ; |
502 | break; |
503 | case OpRShift: |
504 | opStr = " >> " ; |
505 | break; |
506 | case OpURShift: |
507 | opStr = " >>> " ; |
508 | break; |
509 | case OpLess: |
510 | opStr = " < " ; |
511 | break; |
512 | case OpGreaterEq: |
513 | opStr = " >= " ; |
514 | break; |
515 | case OpGreater: |
516 | opStr = " > " ; |
517 | break; |
518 | case OpLessEq: |
519 | opStr = " <= " ; |
520 | break; |
521 | case OpIn: |
522 | opStr = " in " ; |
523 | break; |
524 | case OpInstanceOf: |
525 | opStr = " instanceof " ; |
526 | break; |
527 | case OpEqEq: |
528 | opStr = " == " ; |
529 | break; |
530 | case OpNotEq: |
531 | opStr = " != " ; |
532 | break; |
533 | case OpStrEq: |
534 | opStr = " === " ; |
535 | break; |
536 | case OpStrNEq: |
537 | opStr = " !== " ; |
538 | break; |
539 | case OpBitAnd: |
540 | opStr = " & " ; |
541 | break; |
542 | case OpBitXOr: |
543 | opStr = " ^ " ; |
544 | break; |
545 | case OpBitOr: |
546 | opStr = " | " ; |
547 | break; |
548 | default: |
549 | assert(!"Unhandled case in BinaryOperatorNode::streamTo()" ); |
550 | opStr = " ??? " ; |
551 | break; |
552 | } |
553 | s.append(expr1, opStr, expr2); |
554 | } |
555 | |
556 | void BinaryLogicalNode::streamTo(SourceStream &s) const |
557 | { |
558 | s.append(expr1, (oper == OpAnd ? " && " : " || " ), expr2); |
559 | } |
560 | |
561 | void ConditionalNode::streamTo(SourceStream &s) const |
562 | { |
563 | s << logical << " ? " ; |
564 | s.append(expr1, " : " , expr2); |
565 | } |
566 | |
567 | static void streamAssignmentOperatorTo(SourceStream &s, Operator oper) |
568 | { |
569 | const char *opStr; |
570 | switch (oper) { |
571 | case OpEqual: |
572 | opStr = " = " ; |
573 | break; |
574 | case OpMultEq: |
575 | opStr = " *= " ; |
576 | break; |
577 | case OpDivEq: |
578 | opStr = " /= " ; |
579 | break; |
580 | case OpPlusEq: |
581 | opStr = " += " ; |
582 | break; |
583 | case OpMinusEq: |
584 | opStr = " -= " ; |
585 | break; |
586 | case OpLShift: |
587 | opStr = " <<= " ; |
588 | break; |
589 | case OpRShift: |
590 | opStr = " >>= " ; |
591 | break; |
592 | case OpURShift: |
593 | opStr = " >>>= " ; |
594 | break; |
595 | case OpAndEq: |
596 | opStr = " &= " ; |
597 | break; |
598 | case OpXOrEq: |
599 | opStr = " ^= " ; |
600 | break; |
601 | case OpOrEq: |
602 | opStr = " |= " ; |
603 | break; |
604 | case OpModEq: |
605 | opStr = " %= " ; |
606 | break; |
607 | default: |
608 | opStr = " ?= " ; |
609 | } |
610 | s << opStr; |
611 | } |
612 | |
613 | void AssignNode::streamTo(SourceStream &s) const |
614 | { |
615 | s << m_loc; |
616 | streamAssignmentOperatorTo(s, m_oper); |
617 | s << m_right; |
618 | // s.append(m_ident, opStr, m_right); |
619 | } |
620 | |
621 | void CommaNode::streamTo(SourceStream &s) const |
622 | { |
623 | s.append(expr1, ", " , expr2); |
624 | } |
625 | |
626 | void AssignExprNode::streamTo(SourceStream &s) const |
627 | { |
628 | s << " = " << expr; |
629 | } |
630 | |
631 | void VarDeclNode::streamTo(SourceStream &s) const |
632 | { |
633 | s << ident << init; |
634 | } |
635 | |
636 | void VarDeclListNode::streamTo(SourceStream &s) const |
637 | { |
638 | s << "var " << var; |
639 | for (VarDeclListNode *n = next.get(); n; n = n->next.get()) |
640 | s << ", " << n->var; |
641 | } |
642 | |
643 | void VarStatementNode::streamTo(SourceStream &s) const |
644 | { |
645 | s << SourceStream::Endl << next << ';'; |
646 | } |
647 | |
648 | void BlockNode::streamTo(SourceStream &s) const |
649 | { |
650 | s << SourceStream::Endl << '{' << SourceStream::Indent |
651 | << source << SourceStream::Unindent << SourceStream::Endl << '}'; |
652 | } |
653 | |
654 | void ProgramNode::streamTo(SourceStream &s) const |
655 | { |
656 | // we don't want braces here, unlike in the above |
657 | s << source << SourceStream::Endl; |
658 | } |
659 | |
660 | void EmptyStatementNode::streamTo(SourceStream &s) const |
661 | { |
662 | s << SourceStream::Endl << ';'; |
663 | } |
664 | |
665 | void ExprStatementNode::streamTo(SourceStream &s) const |
666 | { |
667 | s << SourceStream::Endl << expr << ';'; |
668 | } |
669 | |
670 | void IfNode::streamTo(SourceStream &s) const |
671 | { |
672 | s << SourceStream::Endl << "if (" << expr << ')' << SourceStream::Indent |
673 | << statement1 << SourceStream::Unindent; |
674 | if (statement2) |
675 | s << SourceStream::Endl << "else" << SourceStream::Indent |
676 | << statement2 << SourceStream::Unindent; |
677 | } |
678 | |
679 | void DoWhileNode::streamTo(SourceStream &s) const |
680 | { |
681 | s << SourceStream::Endl << "do " << SourceStream::Indent |
682 | << statement << SourceStream::Unindent << SourceStream::Endl |
683 | << "while (" << expr << ");" ; |
684 | } |
685 | |
686 | void WhileNode::streamTo(SourceStream &s) const |
687 | { |
688 | s << SourceStream::Endl << "while (" << expr << ')' << SourceStream::Indent |
689 | << statement << SourceStream::Unindent; |
690 | } |
691 | |
692 | void ForNode::streamTo(SourceStream &s) const |
693 | { |
694 | s << SourceStream::Endl << "for (" |
695 | << expr1 |
696 | << "; " << expr2 |
697 | << "; " << expr3 |
698 | << ')' << SourceStream::Indent << statement << SourceStream::Unindent; |
699 | } |
700 | |
701 | void ForInNode::streamTo(SourceStream &s) const |
702 | { |
703 | s << SourceStream::Endl << "for (" ; |
704 | if (varDecl) |
705 | s << "var " << varDecl; |
706 | else |
707 | s << lexpr; |
708 | |
709 | s << " in " << expr << ')' << SourceStream::Indent |
710 | << statement << SourceStream::Unindent; |
711 | } |
712 | |
713 | void ContinueNode::streamTo(SourceStream &s) const |
714 | { |
715 | s << SourceStream::Endl << "continue" ; |
716 | if (!ident.isNull()) |
717 | s << ' ' << ident; |
718 | s << ';'; |
719 | } |
720 | |
721 | void BreakNode::streamTo(SourceStream &s) const |
722 | { |
723 | s << SourceStream::Endl << "break" ; |
724 | if (!ident.isNull()) |
725 | s << ' ' << ident; |
726 | s << ';'; |
727 | } |
728 | |
729 | void ReturnNode::streamTo(SourceStream &s) const |
730 | { |
731 | s << SourceStream::Endl << "return" ; |
732 | if (value) |
733 | s << ' ' << value; |
734 | s << ';'; |
735 | } |
736 | |
737 | void WithNode::streamTo(SourceStream &s) const |
738 | { |
739 | s << SourceStream::Endl << "with (" << expr << ") " |
740 | << statement; |
741 | } |
742 | |
743 | void CaseClauseNode::streamTo(SourceStream &s) const |
744 | { |
745 | s << SourceStream::Endl; |
746 | if (expr) |
747 | s << "case " << expr; |
748 | else |
749 | s << "default" ; |
750 | s << ':' << SourceStream::Indent; |
751 | if (source) |
752 | s << source; |
753 | s << SourceStream::Unindent; |
754 | } |
755 | |
756 | void ClauseListNode::streamTo(SourceStream &s) const |
757 | { |
758 | for (const ClauseListNode *n = this; n; n = n->getNext()) |
759 | s << n->getClause(); |
760 | } |
761 | |
762 | void CaseBlockNode::streamTo(SourceStream &s) const |
763 | { |
764 | for (const ClauseListNode *n = list1.get(); n; n = n->getNext()) |
765 | s << n->getClause(); |
766 | if (def) |
767 | s << def; |
768 | for (const ClauseListNode *n = list2.get(); n; n = n->getNext()) |
769 | s << n->getClause(); |
770 | } |
771 | |
772 | void SwitchNode::streamTo(SourceStream &s) const |
773 | { |
774 | s << SourceStream::Endl << "switch (" << expr << ") {" |
775 | << SourceStream::Indent << block << SourceStream::Unindent |
776 | << SourceStream::Endl << '}'; |
777 | } |
778 | |
779 | void LabelNode::streamTo(SourceStream &s) const |
780 | { |
781 | s << SourceStream::Endl << label << ':' << SourceStream::Indent |
782 | << statement << SourceStream::Unindent; |
783 | } |
784 | |
785 | void ThrowNode::streamTo(SourceStream &s) const |
786 | { |
787 | s << SourceStream::Endl << "throw " << expr << ';'; |
788 | } |
789 | |
790 | void TryNode::streamTo(SourceStream &s) const |
791 | { |
792 | s << SourceStream::Endl << "try " << tryBlock; |
793 | if (catchBlock) |
794 | s << SourceStream::Endl << "catch (" << exceptionIdent << ')' << catchBlock; |
795 | if (finallyBlock) |
796 | s << SourceStream::Endl << "finally " << finallyBlock; |
797 | } |
798 | |
799 | void ParameterNode::streamTo(SourceStream &s) const |
800 | { |
801 | s << id; |
802 | for (ParameterNode *n = next.get(); n; n = n->next.get()) |
803 | s << ", " << n->id; |
804 | } |
805 | |
806 | void FuncDeclNode::streamTo(SourceStream &s) const |
807 | { |
808 | s << SourceStream::Endl << "function " << ident << '(' << param << ')' << body; |
809 | } |
810 | |
811 | void FuncExprNode::streamTo(SourceStream &s) const |
812 | { |
813 | s << "function " << ident << '(' << param << ')' << body; |
814 | } |
815 | |
816 | void SourceElementsNode::streamTo(SourceStream &s) const |
817 | { |
818 | for (const SourceElementsNode *n = this; n; n = n->next.get()) |
819 | s << n->node; |
820 | } |
821 | |
822 | void PackageNameNode::streamTo(SourceStream &s) const |
823 | { |
824 | if (names) |
825 | s << names << '.'; |
826 | s << id; |
827 | } |
828 | |
829 | void ImportStatement::streamTo(SourceStream &s) const |
830 | { |
831 | s << SourceStream::Endl << "import " ; |
832 | if (!al.isEmpty()) |
833 | s << al << " = " ; |
834 | s << name << (wld ? ".*;" : ";" ); |
835 | } |
836 | |
837 | |