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

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

2007-01-14 Mark Rowe <[email protected]>

Reviewed by Mitz.

Minor fixes to JavaScript pretty-printing.

  • JavaScriptCore.exp:
  • kjs/Parser.cpp: (KJS::Parser::prettyPrint): Return line number and error message if parsing fails.
  • kjs/Parser.h:
  • kjs/nodes2string.cpp: (ElementNode::streamTo): Include comma delimiters in array literals. (PropertyNameNode::streamTo): Quote property names in object literals to handle the case when the property name is not a valid identifier.
  • kjs/testkjs.cpp: (doIt): Print any errors encountered while pretty-printing.

2007-01-14 Mark Rowe <[email protected]>

Reviewed by Mitz.

Layout tests for fixes to JavaScript pretty-printing.

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