90c02a26b88db40ba63d0066983fb1c0a0afd356
[WebKit-https.git] / JavaScriptCore / kjs / nodes2string.cpp
1 /*
2  *  This file is part of the KDE libraries
3  *  Copyright (C) 2002 Harri Porten (porten@kde.org)
4  *  Copyright (C) 2003 Apple Computer, Inc.
5  *
6  *  This library is free software; you can redistribute it and/or
7  *  modify it under the terms of the GNU Library General Public
8  *  License as published by the Free Software Foundation; either
9  *  version 2 of the License, or (at your option) any later version.
10  *
11  *  This library is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  *  Library General Public License for more details.
15  *
16  *  You should have received a copy of the GNU Library General Public License
17  *  along with this library; see the file COPYING.LIB.  If not, write to
18  *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  *  Boston, MA 02110-1301, USA.
20  *
21  */
22
23 #include "config.h"
24 #include "nodes.h"
25 #include "function.h"
26
27 namespace KJS {
28   /**
29    * A simple text streaming class that helps with code indentation.
30    */
31   class SourceStream {
32   public:
33     enum Format {
34       Endl, Indent, Unindent
35     };
36
37     UString toString() const { return str; }
38     SourceStream& operator<<(const Identifier &);
39     SourceStream& operator<<(const UString &);
40     SourceStream& operator<<(const char *);
41     SourceStream& operator<<(char);
42     SourceStream& operator<<(Format f);
43     SourceStream& operator<<(const Node *);
44     template <typename T> SourceStream& operator<<(RefPtr<T> n) { return this->operator<<(n.get()); }
45   private:
46     UString str; /* TODO: buffer */
47     UString ind;
48   };
49 }
50
51 using namespace KJS;
52
53 SourceStream& SourceStream::operator<<(char c)
54 {
55   str += UString(c);
56   return *this;
57 }
58
59 SourceStream& SourceStream::operator<<(const char *s)
60 {
61   str += UString(s);
62   return *this;
63 }
64
65 SourceStream& SourceStream::operator<<(const UString &s)
66 {
67   str += s;
68   return *this;
69 }
70
71 SourceStream& SourceStream::operator<<(const Identifier &s)
72 {
73   str += s.ustring();
74   return *this;
75 }
76
77 SourceStream& SourceStream::operator<<(const Node *n)
78 {
79   if (n)
80     n->streamTo(*this);
81   return *this;
82 }
83
84 SourceStream& SourceStream::operator<<(Format f)
85 {
86   switch (f) {
87     case Endl:
88       str += "\n" + ind;
89       break;
90     case Indent:
91       ind += "  ";
92       break;
93     case Unindent:
94       ind = ind.substr(0, ind.size() - 2);
95       break;
96   }
97
98   return *this;
99 }
100
101 UString Node::toString() const
102 {
103   SourceStream str;
104   streamTo(str);
105
106   return str.toString();
107 }
108
109 void NullNode::streamTo(SourceStream &s) const { s << "null"; }
110
111 void BooleanNode::streamTo(SourceStream &s) const
112 {
113   s << (value ? "true" : "false");
114 }
115
116 void NumberNode::streamTo(SourceStream &s) const { s << UString::from(value); }
117
118 void StringNode::streamTo(SourceStream &s) const
119 {
120   s << '"' << escapeStringForPrettyPrinting(value) << '"';
121 }
122
123 void RegExpNode::streamTo(SourceStream &s) const
124
125     s << "/" <<  pattern << "/" << flags; 
126 }
127
128 void ThisNode::streamTo(SourceStream &s) const { s << "this"; }
129
130 void ResolveNode::streamTo(SourceStream &s) const { s << ident; }
131
132 void GroupNode::streamTo(SourceStream &s) const
133 {
134   s << "(" << group << ")"; 
135 }
136
137 void ElementNode::streamTo(SourceStream &s) const
138 {
139   for (const ElementNode *n = this; n; n = n->next.get()) {
140     for (int i = 0; i < n->elision; i++)
141       s << ",";
142     s << n->node;
143   }
144 }
145
146 void ArrayNode::streamTo(SourceStream &s) const
147 {
148   s << "[" << element;
149   for (int i = 0; i < elision; i++)
150     s << ",";
151   s << "]";
152 }
153
154 void ObjectLiteralNode::streamTo(SourceStream &s) const
155 {
156   if (list)
157     s << "{ " << list << " }";
158   else
159     s << "{ }";
160 }
161
162 void PropertyListNode::streamTo(SourceStream &s) const
163 {
164   s << node;
165   
166   for (const PropertyListNode *n = next.get(); n; n = n->next.get())
167     s << ", " << n->node;
168 }
169
170 void PropertyNode::streamTo(SourceStream &s) const
171 {
172   switch (type) {
173     case Constant:
174       s << name << ": " << assign;
175       break;
176     case Getter:
177     case Setter: {
178       const FuncExprNode *func = static_cast<const FuncExprNode *>(assign.get());
179       if (type == Getter)
180         s << "get "; 
181       else
182         s << "set ";
183       
184       s << name << "(" << func->param << ")" << func->body;
185       break;
186     }
187   }
188 }
189
190 void PropertyNameNode::streamTo(SourceStream &s) const
191 {
192   if (str.isNull())
193     s << UString::from(numeric);
194   else
195     s << str;
196 }
197
198 void BracketAccessorNode::streamTo(SourceStream &s) const
199 {
200   s << expr1 << "[" << expr2 << "]";
201 }
202
203 void DotAccessorNode::streamTo(SourceStream &s) const
204 {
205   s << expr << "." << ident;
206 }
207
208 void ArgumentListNode::streamTo(SourceStream &s) const
209 {
210   s << expr;
211   for (ArgumentListNode *n = next.get(); n; n = n->next.get())
212     s << ", " << n->expr;
213 }
214
215 void ArgumentsNode::streamTo(SourceStream &s) const
216 {
217   s << "(" << list << ")";
218 }
219
220 void NewExprNode::streamTo(SourceStream &s) const
221 {
222   s << "new " << expr << args;
223 }
224
225 void FunctionCallValueNode::streamTo(SourceStream &s) const
226 {
227   s << expr << args;
228 }
229
230 void FunctionCallResolveNode::streamTo(SourceStream &s) const
231 {
232   s << ident << args;
233 }
234
235 void FunctionCallBracketNode::streamTo(SourceStream &s) const
236 {
237   s << base << "[" << subscript << "]" << args;
238 }
239
240 void FunctionCallParenBracketNode::streamTo(SourceStream &s) const
241 {
242   s << "(" << base << "[" << subscript << "])" << args;
243 }
244
245 void FunctionCallDotNode::streamTo(SourceStream &s) const
246 {
247   s << base << "." << ident << args;
248 }
249
250 void FunctionCallParenDotNode::streamTo(SourceStream &s) const
251 {
252   s << "(" << base << "." << ident << ")" << args;
253 }
254
255 void PostfixResolveNode::streamTo(SourceStream &s) const
256 {
257   s << m_ident;
258   if (m_oper == OpPlusPlus)
259     s << "++";
260   else
261     s << "--";
262 }
263
264 void PostfixBracketNode::streamTo(SourceStream &s) const
265 {
266   s << m_base << "[" << m_subscript << "]";
267   if (m_oper == OpPlusPlus)
268     s << "++";
269   else
270     s << "--";
271 }
272
273 void PostfixDotNode::streamTo(SourceStream &s) const
274 {
275   s << m_base << "." << m_ident;
276   if (m_oper == OpPlusPlus)
277     s << "++";
278   else
279     s << "--";
280 }
281
282 void DeleteResolveNode::streamTo(SourceStream &s) const
283 {
284   s << "delete " << m_ident;
285 }
286
287 void DeleteBracketNode::streamTo(SourceStream &s) const
288 {
289   s << "delete " << m_base << "[" << m_subscript << "]";
290 }
291
292 void DeleteDotNode::streamTo(SourceStream &s) const
293 {
294   s << "delete " << m_base << "." << m_ident;
295 }
296
297 void DeleteValueNode::streamTo(SourceStream &s) const
298 {
299   s << "delete " << m_expr;
300 }
301
302 void VoidNode::streamTo(SourceStream &s) const
303 {
304   s << "void " << expr;
305 }
306
307 void TypeOfValueNode::streamTo(SourceStream &s) const
308 {
309   s << "typeof " << m_expr;
310 }
311
312 void TypeOfResolveNode::streamTo(SourceStream &s) const
313 {
314   s << "typeof " << m_ident;
315 }
316
317 void PrefixResolveNode::streamTo(SourceStream &s) const
318 {
319   if (m_oper == OpPlusPlus)
320     s << "++";
321   else
322     s << "--";
323   s << m_ident;
324 }
325
326 void PrefixBracketNode::streamTo(SourceStream &s) const
327 {
328   if (m_oper == OpPlusPlus)
329     s << "++";
330   else
331     s << "--";
332   s << m_base << "[" << m_subscript << "]";
333 }
334
335 void PrefixDotNode::streamTo(SourceStream &s) const
336 {
337   if (m_oper == OpPlusPlus)
338     s << "++";
339   else
340     s << "--";
341   s << m_base << "." << m_ident;
342 }
343
344 void UnaryPlusNode::streamTo(SourceStream &s) const
345 {
346   s << "+" << expr;
347 }
348
349 void NegateNode::streamTo(SourceStream &s) const
350 {
351   s << "-" << expr;
352 }
353
354 void BitwiseNotNode::streamTo(SourceStream &s) const
355 {
356   s << "~" << expr;
357 }
358
359 void LogicalNotNode::streamTo(SourceStream &s) const
360 {
361   s << "!" << expr;
362 }
363
364 void MultNode::streamTo(SourceStream &s) const
365 {
366   s << term1 << oper << term2;
367 }
368
369 void AddNode::streamTo(SourceStream &s) const
370 {
371   s << term1 << oper << term2;
372 }
373
374 void ShiftNode::streamTo(SourceStream &s) const
375 {
376   s << term1;
377   if (oper == OpLShift)
378     s << "<<";
379   else if (oper == OpRShift)
380     s << ">>";
381   else
382     s << ">>>";
383   s << term2;
384 }
385
386 void RelationalNode::streamTo(SourceStream &s) const
387 {
388   s << expr1;
389   switch (oper) {
390   case OpLess:
391     s << " < ";
392     break;
393   case OpGreater:
394     s << " > ";
395     break;
396   case OpLessEq:
397     s << " <= ";
398     break;
399   case OpGreaterEq:
400     s << " >= ";
401     break;
402   case OpInstanceOf:
403     s << " instanceof ";
404     break;
405   case OpIn:
406     s << " in ";
407     break;
408   default:
409     ;
410   }
411   s << expr2;
412 }
413
414 void EqualNode::streamTo(SourceStream &s) const
415 {
416   s << expr1;
417  switch (oper) {
418  case OpEqEq:
419    s << " == ";
420    break;
421  case OpNotEq:
422    s << " != ";
423    break;
424  case OpStrEq:
425    s << " === ";
426    break;
427  case OpStrNEq:
428    s << " !== ";
429    break;
430  default:
431    ;
432  }
433   s << expr2;
434 }
435
436 void BitOperNode::streamTo(SourceStream &s) const
437 {
438   s << expr1;
439   if (oper == OpBitAnd)
440     s << " & ";
441   else if (oper == OpBitXOr)
442     s << " ^ ";
443   else
444     s << " | ";
445   s << expr2;
446 }
447
448 void BinaryLogicalNode::streamTo(SourceStream &s) const
449 {
450   s << expr1 << (oper == OpAnd ? " && " : " || ") << expr2;
451 }
452
453 void ConditionalNode::streamTo(SourceStream &s) const
454 {
455   s << logical << " ? " << expr1 << " : " << expr2;
456 }
457
458 static void streamAssignmentOperatorTo(SourceStream &s, Operator oper)
459 {
460   const char *opStr;
461   switch (oper) {
462   case OpEqual:
463     opStr = " = ";
464     break;
465   case OpMultEq:
466     opStr = " *= ";
467     break;
468   case OpDivEq:
469     opStr = " /= ";
470     break;
471   case OpPlusEq:
472     opStr = " += ";
473     break;
474   case OpMinusEq:
475     opStr = " -= ";
476     break;
477   case OpLShift:
478     opStr = " <<= ";
479     break;
480   case OpRShift:
481     opStr = " >>= ";
482     break;
483   case OpURShift:
484     opStr = " >>>= ";
485     break;
486   case OpAndEq:
487     opStr = " &= ";
488     break;
489   case OpXOrEq:
490     opStr = " ^= ";
491     break;
492   case OpOrEq:
493     opStr = " |= ";
494     break;
495   case OpModEq:
496     opStr = " %= ";
497     break;
498   default:
499     opStr = " ?= ";
500   }
501   s << opStr;
502 }
503
504 void AssignResolveNode::streamTo(SourceStream &s) const
505 {
506   s << m_ident;
507   streamAssignmentOperatorTo(s, m_oper);
508   s << m_right;
509 }
510
511 void AssignBracketNode::streamTo(SourceStream &s) const
512 {
513   s << m_base << "[" << m_subscript << "]";
514   streamAssignmentOperatorTo(s, m_oper);
515   s << m_right;
516 }
517
518 void AssignDotNode::streamTo(SourceStream &s) const
519 {
520   s << m_base << "." << m_ident;
521   streamAssignmentOperatorTo(s, m_oper);
522   s << m_right;
523 }
524
525 void CommaNode::streamTo(SourceStream &s) const
526 {
527   s << expr1 << ", " << expr2;
528 }
529
530 void AssignExprNode::streamTo(SourceStream &s) const
531 {
532   s << " = " << expr;
533 }
534
535 void VarDeclNode::streamTo(SourceStream &s) const
536 {
537   s << ident << init;
538 }
539
540 void VarDeclListNode::streamTo(SourceStream &s) const
541 {
542   s << var;
543   for (VarDeclListNode *n = next.get(); n; n = n->next.get())
544     s << ", " << n->var;
545 }
546
547 void VarStatementNode::streamTo(SourceStream &s) const
548 {
549   s << SourceStream::Endl << "var " << next << ";";
550 }
551
552 void BlockNode::streamTo(SourceStream &s) const
553 {
554   s << SourceStream::Endl << "{" << SourceStream::Indent
555     << source << SourceStream::Unindent << SourceStream::Endl << "}";
556 }
557
558 void EmptyStatementNode::streamTo(SourceStream &s) const
559 {
560   s << SourceStream::Endl << ";";
561 }
562
563 void ExprStatementNode::streamTo(SourceStream &s) const
564 {
565   s << SourceStream::Endl << expr << ";";
566 }
567
568 void IfNode::streamTo(SourceStream &s) const
569 {
570   s << SourceStream::Endl << "if (" << expr << ")" << SourceStream::Indent
571     << statement1 << SourceStream::Unindent;
572   if (statement2)
573     s << SourceStream::Endl << "else" << SourceStream::Indent
574       << statement2 << SourceStream::Unindent;
575 }
576
577 void DoWhileNode::streamTo(SourceStream &s) const
578 {
579   s << SourceStream::Endl << "do " << SourceStream::Indent
580     << statement << SourceStream::Unindent << SourceStream::Endl
581     << "while (" << expr << ");";
582 }
583
584 void WhileNode::streamTo(SourceStream &s) const
585 {
586   s << SourceStream::Endl << "while (" << expr << ")" << SourceStream::Indent
587     << statement << SourceStream::Unindent;
588 }
589
590 void ForNode::streamTo(SourceStream &s) const
591 {
592   s << SourceStream::Endl << "for ("
593     << expr1  // TODO: doesn't properly do "var i = 0"
594     << "; " << expr2
595     << "; " << expr3
596     << ")" << SourceStream::Indent << statement << SourceStream::Unindent;
597 }
598
599 void ForInNode::streamTo(SourceStream &s) const
600 {
601   s << SourceStream::Endl << "for (";
602   if (varDecl)
603     s << "var " << varDecl;
604   else
605     s << lexpr;
606   
607   if (init)
608     s << " = " << init;
609   s << " in " << expr << ")" << SourceStream::Indent
610     << statement << SourceStream::Unindent;
611 }
612
613 void ContinueNode::streamTo(SourceStream &s) const
614 {
615   s << SourceStream::Endl << "continue";
616   if (!ident.isNull())
617     s << " " << ident;
618   s << ";";
619 }
620
621 void BreakNode::streamTo(SourceStream &s) const
622 {
623   s << SourceStream::Endl << "break";
624   if (!ident.isNull())
625     s << " " << ident;
626   s << ";";
627 }
628
629 void ReturnNode::streamTo(SourceStream &s) const
630 {
631   s << SourceStream::Endl << "return";
632   if (value)
633     s << " " << value;
634   s << ";";
635 }
636
637 void WithNode::streamTo(SourceStream &s) const
638 {
639   s << SourceStream::Endl << "with (" << expr << ") "
640     << statement;
641 }
642
643 void CaseClauseNode::streamTo(SourceStream &s) const
644 {
645   s << SourceStream::Endl;
646   if (expr)
647     s << "case " << expr;
648   else
649     s << "default";
650   s << ":" << SourceStream::Indent;
651   if (source)
652     s << source;
653   s << SourceStream::Unindent;
654 }
655
656 void ClauseListNode::streamTo(SourceStream &s) const
657 {
658   for (const ClauseListNode *n = this; n; n = n->getNext())
659     s << n->getClause();
660 }
661
662 void CaseBlockNode::streamTo(SourceStream &s) const
663 {
664   for (const ClauseListNode *n = list1.get(); n; n = n->getNext())
665     s << n->getClause();
666   if (def)
667     s << def;
668   for (const ClauseListNode *n = list2.get(); n; n = n->getNext())
669     s << n->getClause();
670 }
671
672 void SwitchNode::streamTo(SourceStream &s) const
673 {
674   s << SourceStream::Endl << "switch (" << expr << ") {"
675     << SourceStream::Indent << block << SourceStream::Unindent
676     << SourceStream::Endl << "}";
677 }
678
679 void LabelNode::streamTo(SourceStream &s) const
680 {
681   s << SourceStream::Endl << label << ":" << SourceStream::Indent
682     << statement << SourceStream::Unindent;
683 }
684
685 void ThrowNode::streamTo(SourceStream &s) const
686 {
687   s << SourceStream::Endl << "throw " << expr << ";";
688 }
689
690 void TryNode::streamTo(SourceStream &s) const
691 {
692   s << "try " << tryBlock;
693   if (catchBlock)
694     s << SourceStream::Endl << "catch (" << exceptionIdent << ")" << catchBlock;
695   if (finallyBlock)
696     s << SourceStream::Endl << "finally " << finallyBlock;
697 }
698
699 void ParameterNode::streamTo(SourceStream &s) const
700 {
701   s << id;
702   for (ParameterNode *n = next.get(); n; n = n->next.get())
703     s << ", " << n->id;
704 }
705
706 void FuncDeclNode::streamTo(SourceStream &s) const
707 {
708   s << SourceStream::Endl << "function " << ident << "(" << param << ")" << body;
709 }
710
711 void FuncExprNode::streamTo(SourceStream &s) const
712 {
713   s << "function " << ident << "(" << param << ")" << body;
714 }
715
716 void SourceElementsNode::streamTo(SourceStream &s) const
717 {
718   for (const SourceElementsNode *n = this; n; n = n->next.get())
719     s << n->node;
720 }