source: webkit/trunk/JavaScriptCore/kjs/nodes2string.cpp@ 21473

Last change on this file since 21473 was 21473, checked in by bdash, 18 years ago

2007-05-14 Kimmo Kinnunen <Kimmo Kinnunen>

Reviewed by Darin.

  • kjs/nodes2string.cpp: (ArrayNode::streamTo): print extra ',' in case there was elision commas (check opt member var) and array elements present in the array expression

2007-05-14 Kimmo Kinnunen <Kimmo Kinnunen>

Reviewed by Darin.

  • fast/js/resources/toString-elision-trailing-comma.js: Added.
  • fast/js/toString-elision-trailing-comma-expected.txt: Added.
  • fast/js/toString-elision-trailing-comma.html: Added.
  • Property svn:eol-style set to native
File size: 15.7 KB
Line 
1/*
2 * This file is part of the KDE libraries
3 * Copyright (C) 2002 Harri Porten ([email protected])
4 * Copyright (C) 2003, 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
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
27namespace 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, DotExpr
35 };
36 SourceStream() : m_groupIfNumber(false) {}
37 UString toString() const { return str; }
38 SourceStream& operator<<(const Identifier &);
39 SourceStream& operator<<(const UString &);
40 SourceStream& operator<<(const char *);
41 SourceStream& operator<<(double);
42 SourceStream& operator<<(char);
43 SourceStream& operator<<(Format f);
44 SourceStream& operator<<(const Node *);
45 template <typename T> SourceStream& operator<<(RefPtr<T> n) { return this->operator<<(n.get()); }
46
47 private:
48 UString str; /* TODO: buffer */
49 UString ind;
50 bool m_groupIfNumber;
51 };
52}
53
54using namespace KJS;
55
56SourceStream& SourceStream::operator<<(char c)
57{
58 m_groupIfNumber = false;
59 UChar ch(c);
60 str += UString(&ch, 1);
61 return *this;
62}
63
64SourceStream& SourceStream::operator<<(const char *s)
65{
66 m_groupIfNumber = false;
67 str += UString(s);
68 return *this;
69}
70
71SourceStream& SourceStream::operator<<(double value)
72{
73 if (m_groupIfNumber)
74 str.append("(");
75
76 str += UString::from(value);
77
78 if (m_groupIfNumber)
79 str.append(")");
80
81 m_groupIfNumber = false;
82 return *this;
83}
84
85SourceStream& SourceStream::operator<<(const UString &s)
86{
87 m_groupIfNumber = false;
88 str += s;
89 return *this;
90}
91
92SourceStream& SourceStream::operator<<(const Identifier &s)
93{
94 m_groupIfNumber = false;
95 str += s.ustring();
96 return *this;
97}
98
99SourceStream& SourceStream::operator<<(const Node *n)
100{
101 if (n)
102 n->streamTo(*this);
103 m_groupIfNumber = false;
104 return *this;
105}
106
107SourceStream& SourceStream::operator<<(Format f)
108{
109 m_groupIfNumber = false;
110 switch (f) {
111 case Endl:
112 str += "\n" + ind;
113 break;
114 case Indent:
115 ind += " ";
116 break;
117 case Unindent:
118 ind = ind.substr(0, ind.size() - 2);
119 break;
120 case DotExpr:
121 m_groupIfNumber = true;
122 break;
123 }
124
125 return *this;
126}
127
128UString Node::toString() const
129{
130 SourceStream str;
131 streamTo(str);
132
133 return str.toString();
134}
135
136void NullNode::streamTo(SourceStream &s) const { s << "null"; }
137
138void BooleanNode::streamTo(SourceStream &s) const
139{
140 s << (value ? "true" : "false");
141}
142
143void NumberNode::streamTo(SourceStream &s) const { s << value; }
144
145void StringNode::streamTo(SourceStream &s) const
146{
147 s << '"' << escapeStringForPrettyPrinting(value) << '"';
148}
149
150void RegExpNode::streamTo(SourceStream &s) const
151{
152 s << "/" << pattern << "/" << flags;
153}
154
155void ThisNode::streamTo(SourceStream &s) const { s << "this"; }
156
157void ResolveNode::streamTo(SourceStream &s) const { s << ident; }
158
159void GroupNode::streamTo(SourceStream &s) const
160{
161 s << "(" << group << ")";
162}
163
164void ElementNode::streamTo(SourceStream &s) const
165{
166 for (const ElementNode *n = this; n; n = n->next.get()) {
167 for (int i = 0; i < n->elision; i++)
168 s << ",";
169 s << n->node;
170 if (n->next)
171 s << ",";
172 }
173}
174
175void ArrayNode::streamTo(SourceStream &s) const
176{
177 s << "[" << element;
178 for (int i = 0; i < elision; i++)
179 s << ",";
180 // Parser consumes one elision comma if there's array elements
181 // present in the expression.
182 if (opt && element)
183 s << ",";
184 s << "]";
185}
186
187void ObjectLiteralNode::streamTo(SourceStream &s) const
188{
189 if (list)
190 s << "{ " << list << " }";
191 else
192 s << "{ }";
193}
194
195void PropertyListNode::streamTo(SourceStream &s) const
196{
197 s << node;
198
199 for (const PropertyListNode *n = next.get(); n; n = n->next.get())
200 s << ", " << n->node;
201}
202
203void PropertyNode::streamTo(SourceStream &s) const
204{
205 switch (type) {
206 case Constant:
207 s << name << ": " << assign;
208 break;
209 case Getter:
210 case Setter: {
211 const FuncExprNode *func = static_cast<const FuncExprNode *>(assign.get());
212 if (type == Getter)
213 s << "get ";
214 else
215 s << "set ";
216
217 s << name << "(" << func->param << ")" << func->body;
218 break;
219 }
220 }
221}
222
223void PropertyNameNode::streamTo(SourceStream &s) const
224{
225 if (str.isNull())
226 s << UString::from(numeric);
227 else
228 s << '"' << escapeStringForPrettyPrinting(str.ustring()) << '"';
229}
230
231void BracketAccessorNode::streamTo(SourceStream &s) const
232{
233 s << expr1 << "[" << expr2 << "]";
234}
235
236void DotAccessorNode::streamTo(SourceStream &s) const
237{
238 s << SourceStream::DotExpr << expr << "." << ident;
239}
240
241void ArgumentListNode::streamTo(SourceStream &s) const
242{
243 s << expr;
244 for (ArgumentListNode *n = next.get(); n; n = n->next.get())
245 s << ", " << n->expr;
246}
247
248void ArgumentsNode::streamTo(SourceStream &s) const
249{
250 s << "(" << list << ")";
251}
252
253void NewExprNode::streamTo(SourceStream &s) const
254{
255 s << "new " << expr << args;
256}
257
258void FunctionCallValueNode::streamTo(SourceStream &s) const
259{
260 s << expr << args;
261}
262
263void FunctionCallResolveNode::streamTo(SourceStream &s) const
264{
265 s << ident << args;
266}
267
268void FunctionCallBracketNode::streamTo(SourceStream &s) const
269{
270 s << base << "[" << subscript << "]" << args;
271}
272
273void FunctionCallParenBracketNode::streamTo(SourceStream &s) const
274{
275 s << "(" << base << "[" << subscript << "])" << args;
276}
277
278void FunctionCallDotNode::streamTo(SourceStream &s) const
279{
280 s << SourceStream::DotExpr << base << "." << ident << args;
281}
282
283void FunctionCallParenDotNode::streamTo(SourceStream &s) const
284{
285 s << "(" << SourceStream::DotExpr << base << "." << ident << ")" << args;
286}
287
288void PostfixResolveNode::streamTo(SourceStream &s) const
289{
290 s << m_ident;
291 if (m_oper == OpPlusPlus)
292 s << "++";
293 else
294 s << "--";
295}
296
297void PostfixBracketNode::streamTo(SourceStream &s) const
298{
299 s << m_base << "[" << m_subscript << "]";
300 if (m_oper == OpPlusPlus)
301 s << "++";
302 else
303 s << "--";
304}
305
306void PostfixDotNode::streamTo(SourceStream &s) const
307{
308 s << SourceStream::DotExpr << m_base << "." << m_ident;
309 if (m_oper == OpPlusPlus)
310 s << "++";
311 else
312 s << "--";
313}
314
315void PostfixErrorNode::streamTo(SourceStream& s) const
316{
317 s << m_expr;
318 if (m_oper == OpPlusPlus)
319 s << "++";
320 else
321 s << "--";
322}
323
324void DeleteResolveNode::streamTo(SourceStream &s) const
325{
326 s << "delete " << m_ident;
327}
328
329void DeleteBracketNode::streamTo(SourceStream &s) const
330{
331 s << "delete " << m_base << "[" << m_subscript << "]";
332}
333
334void DeleteDotNode::streamTo(SourceStream &s) const
335{
336 s << "delete " << SourceStream::DotExpr << m_base << "." << m_ident;
337}
338
339void DeleteValueNode::streamTo(SourceStream &s) const
340{
341 s << "delete " << m_expr;
342}
343
344void VoidNode::streamTo(SourceStream &s) const
345{
346 s << "void " << expr;
347}
348
349void TypeOfValueNode::streamTo(SourceStream &s) const
350{
351 s << "typeof " << m_expr;
352}
353
354void TypeOfResolveNode::streamTo(SourceStream &s) const
355{
356 s << "typeof " << m_ident;
357}
358
359void PrefixResolveNode::streamTo(SourceStream &s) const
360{
361 if (m_oper == OpPlusPlus)
362 s << "++";
363 else
364 s << "--";
365 s << m_ident;
366}
367
368void PrefixBracketNode::streamTo(SourceStream &s) const
369{
370 if (m_oper == OpPlusPlus)
371 s << "++";
372 else
373 s << "--";
374 s << m_base << "[" << m_subscript << "]";
375}
376
377void PrefixDotNode::streamTo(SourceStream &s) const
378{
379 if (m_oper == OpPlusPlus)
380 s << "++";
381 else
382 s << "--";
383 s << SourceStream::DotExpr << m_base << "." << m_ident;
384}
385
386void PrefixErrorNode::streamTo(SourceStream& s) const
387{
388 if (m_oper == OpPlusPlus)
389 s << "++";
390 else
391 s << "--";
392 s << m_expr;
393}
394
395void UnaryPlusNode::streamTo(SourceStream &s) const
396{
397 s << "+" << expr;
398}
399
400void NegateNode::streamTo(SourceStream &s) const
401{
402 s << "-" << expr;
403}
404
405void BitwiseNotNode::streamTo(SourceStream &s) const
406{
407 s << "~" << expr;
408}
409
410void LogicalNotNode::streamTo(SourceStream &s) const
411{
412 s << "!" << expr;
413}
414
415void MultNode::streamTo(SourceStream &s) const
416{
417 s << term1 << oper << term2;
418}
419
420void AddNode::streamTo(SourceStream &s) const
421{
422 s << term1 << oper << term2;
423}
424
425void ShiftNode::streamTo(SourceStream &s) const
426{
427 s << term1;
428 if (oper == OpLShift)
429 s << "<<";
430 else if (oper == OpRShift)
431 s << ">>";
432 else
433 s << ">>>";
434 s << term2;
435}
436
437void RelationalNode::streamTo(SourceStream &s) const
438{
439 s << expr1;
440 switch (oper) {
441 case OpLess:
442 s << " < ";
443 break;
444 case OpGreater:
445 s << " > ";
446 break;
447 case OpLessEq:
448 s << " <= ";
449 break;
450 case OpGreaterEq:
451 s << " >= ";
452 break;
453 case OpInstanceOf:
454 s << " instanceof ";
455 break;
456 case OpIn:
457 s << " in ";
458 break;
459 default:
460 ;
461 }
462 s << expr2;
463}
464
465void EqualNode::streamTo(SourceStream &s) const
466{
467 s << expr1;
468 switch (oper) {
469 case OpEqEq:
470 s << " == ";
471 break;
472 case OpNotEq:
473 s << " != ";
474 break;
475 case OpStrEq:
476 s << " === ";
477 break;
478 case OpStrNEq:
479 s << " !== ";
480 break;
481 default:
482 ;
483 }
484 s << expr2;
485}
486
487void BitOperNode::streamTo(SourceStream &s) const
488{
489 s << expr1;
490 if (oper == OpBitAnd)
491 s << " & ";
492 else if (oper == OpBitXOr)
493 s << " ^ ";
494 else
495 s << " | ";
496 s << expr2;
497}
498
499void BinaryLogicalNode::streamTo(SourceStream &s) const
500{
501 s << expr1 << (oper == OpAnd ? " && " : " || ") << expr2;
502}
503
504void ConditionalNode::streamTo(SourceStream &s) const
505{
506 s << logical << " ? " << expr1 << " : " << expr2;
507}
508
509static void streamAssignmentOperatorTo(SourceStream &s, Operator oper)
510{
511 const char *opStr;
512 switch (oper) {
513 case OpEqual:
514 opStr = " = ";
515 break;
516 case OpMultEq:
517 opStr = " *= ";
518 break;
519 case OpDivEq:
520 opStr = " /= ";
521 break;
522 case OpPlusEq:
523 opStr = " += ";
524 break;
525 case OpMinusEq:
526 opStr = " -= ";
527 break;
528 case OpLShift:
529 opStr = " <<= ";
530 break;
531 case OpRShift:
532 opStr = " >>= ";
533 break;
534 case OpURShift:
535 opStr = " >>>= ";
536 break;
537 case OpAndEq:
538 opStr = " &= ";
539 break;
540 case OpXOrEq:
541 opStr = " ^= ";
542 break;
543 case OpOrEq:
544 opStr = " |= ";
545 break;
546 case OpModEq:
547 opStr = " %= ";
548 break;
549 default:
550 opStr = " ?= ";
551 }
552 s << opStr;
553}
554
555void AssignResolveNode::streamTo(SourceStream &s) const
556{
557 s << m_ident;
558 streamAssignmentOperatorTo(s, m_oper);
559 s << m_right;
560}
561
562void AssignBracketNode::streamTo(SourceStream &s) const
563{
564 s << m_base << "[" << m_subscript << "]";
565 streamAssignmentOperatorTo(s, m_oper);
566 s << m_right;
567}
568
569void AssignDotNode::streamTo(SourceStream &s) const
570{
571 s << SourceStream::DotExpr << m_base << "." << m_ident;
572 streamAssignmentOperatorTo(s, m_oper);
573 s << m_right;
574}
575
576void AssignErrorNode::streamTo(SourceStream& s) const
577{
578 s << m_left;
579 streamAssignmentOperatorTo(s, m_oper);
580 s << m_right;
581}
582
583void CommaNode::streamTo(SourceStream &s) const
584{
585 s << expr1 << ", " << expr2;
586}
587
588void AssignExprNode::streamTo(SourceStream &s) const
589{
590 s << " = " << expr;
591}
592
593void VarDeclNode::streamTo(SourceStream &s) const
594{
595 s << ident << init;
596}
597
598void VarDeclListNode::streamTo(SourceStream &s) const
599{
600 s << "var " << var;
601 for (VarDeclListNode *n = next.get(); n; n = n->next.get())
602 s << ", " << n->var;
603}
604
605void VarStatementNode::streamTo(SourceStream &s) const
606{
607 s << SourceStream::Endl << next << ";";
608}
609
610void BlockNode::streamTo(SourceStream &s) const
611{
612 s << SourceStream::Endl << "{" << SourceStream::Indent
613 << source << SourceStream::Unindent << SourceStream::Endl << "}";
614}
615
616void EmptyStatementNode::streamTo(SourceStream &s) const
617{
618 s << SourceStream::Endl << ";";
619}
620
621void ExprStatementNode::streamTo(SourceStream &s) const
622{
623 s << SourceStream::Endl << expr << ";";
624}
625
626void IfNode::streamTo(SourceStream &s) const
627{
628 s << SourceStream::Endl << "if (" << expr << ")" << SourceStream::Indent
629 << statement1 << SourceStream::Unindent;
630 if (statement2)
631 s << SourceStream::Endl << "else" << SourceStream::Indent
632 << statement2 << SourceStream::Unindent;
633}
634
635void DoWhileNode::streamTo(SourceStream &s) const
636{
637 s << SourceStream::Endl << "do " << SourceStream::Indent
638 << statement << SourceStream::Unindent << SourceStream::Endl
639 << "while (" << expr << ");";
640}
641
642void WhileNode::streamTo(SourceStream &s) const
643{
644 s << SourceStream::Endl << "while (" << expr << ")" << SourceStream::Indent
645 << statement << SourceStream::Unindent;
646}
647
648void ForNode::streamTo(SourceStream &s) const
649{
650 s << SourceStream::Endl << "for ("
651 << expr1
652 << "; " << expr2
653 << "; " << expr3
654 << ")" << SourceStream::Indent << statement << SourceStream::Unindent;
655}
656
657void ForInNode::streamTo(SourceStream &s) const
658{
659 s << SourceStream::Endl << "for (";
660 if (varDecl)
661 s << "var " << varDecl;
662 else
663 s << lexpr;
664
665 s << " in " << expr << ")" << SourceStream::Indent
666 << statement << SourceStream::Unindent;
667}
668
669void ContinueNode::streamTo(SourceStream &s) const
670{
671 s << SourceStream::Endl << "continue";
672 if (!ident.isNull())
673 s << " " << ident;
674 s << ";";
675}
676
677void BreakNode::streamTo(SourceStream &s) const
678{
679 s << SourceStream::Endl << "break";
680 if (!ident.isNull())
681 s << " " << ident;
682 s << ";";
683}
684
685void ReturnNode::streamTo(SourceStream &s) const
686{
687 s << SourceStream::Endl << "return";
688 if (value)
689 s << " " << value;
690 s << ";";
691}
692
693void WithNode::streamTo(SourceStream &s) const
694{
695 s << SourceStream::Endl << "with (" << expr << ") "
696 << statement;
697}
698
699void CaseClauseNode::streamTo(SourceStream &s) const
700{
701 s << SourceStream::Endl;
702 if (expr)
703 s << "case " << expr;
704 else
705 s << "default";
706 s << ":" << SourceStream::Indent;
707 if (source)
708 s << source;
709 s << SourceStream::Unindent;
710}
711
712void ClauseListNode::streamTo(SourceStream &s) const
713{
714 for (const ClauseListNode *n = this; n; n = n->getNext())
715 s << n->getClause();
716}
717
718void CaseBlockNode::streamTo(SourceStream &s) const
719{
720 for (const ClauseListNode *n = list1.get(); n; n = n->getNext())
721 s << n->getClause();
722 if (def)
723 s << def;
724 for (const ClauseListNode *n = list2.get(); n; n = n->getNext())
725 s << n->getClause();
726}
727
728void SwitchNode::streamTo(SourceStream &s) const
729{
730 s << SourceStream::Endl << "switch (" << expr << ") {"
731 << SourceStream::Indent << block << SourceStream::Unindent
732 << SourceStream::Endl << "}";
733}
734
735void LabelNode::streamTo(SourceStream &s) const
736{
737 s << SourceStream::Endl << label << ":" << SourceStream::Indent
738 << statement << SourceStream::Unindent;
739}
740
741void ThrowNode::streamTo(SourceStream &s) const
742{
743 s << SourceStream::Endl << "throw " << expr << ";";
744}
745
746void TryNode::streamTo(SourceStream &s) const
747{
748 s << "try " << tryBlock;
749 if (catchBlock)
750 s << SourceStream::Endl << "catch (" << exceptionIdent << ")" << catchBlock;
751 if (finallyBlock)
752 s << SourceStream::Endl << "finally " << finallyBlock;
753}
754
755void ParameterNode::streamTo(SourceStream &s) const
756{
757 s << id;
758 for (ParameterNode *n = next.get(); n; n = n->next.get())
759 s << ", " << n->id;
760}
761
762void FuncDeclNode::streamTo(SourceStream &s) const
763{
764 s << SourceStream::Endl << "function " << ident << "(" << param << ")" << body;
765}
766
767void FuncExprNode::streamTo(SourceStream &s) const
768{
769 s << "function " << ident << "(" << param << ")" << body;
770}
771
772void SourceElementsNode::streamTo(SourceStream &s) const
773{
774 for (const SourceElementsNode *n = this; n; n = n->next.get())
775 s << n->node;
776}
Note: See TracBrowser for help on using the repository browser.