2 * Copyright (C) 2002 Harri Porten (porten@kde.org)
3 * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
4 * Copyright (C) 2007 Eric Seidel <eric@webkit.org>
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.
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.
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.
26 #include <wtf/MathExtras.h>
27 #include <wtf/StringExtras.h>
28 #include <wtf/unicode/Unicode.h>
31 using namespace Unicode
;
35 // A simple text streaming class that helps with code indentation.
37 enum EndlType
{ Endl
};
38 enum IndentType
{ Indent
};
39 enum UnindentType
{ Unindent
};
40 enum DotExprType
{ DotExpr
};
45 : m_numberNeedsParens(false)
46 , m_atStartOfStatement(true)
47 , m_precedence(PrecExpression
)
51 UString
toString() const { return m_string
; }
53 SourceStream
& operator<<(const Identifier
&);
54 SourceStream
& operator<<(const UString
&);
55 SourceStream
& operator<<(const char*);
56 SourceStream
& operator<<(double);
57 SourceStream
& operator<<(char);
58 SourceStream
& operator<<(EndlType
);
59 SourceStream
& operator<<(IndentType
);
60 SourceStream
& operator<<(UnindentType
);
61 SourceStream
& operator<<(DotExprType
);
62 SourceStream
& operator<<(Precedence
);
63 SourceStream
& operator<<(const Node
*);
64 template <typename T
> SourceStream
& operator<<(const RefPtr
<T
>& n
) { return *this << n
.get(); }
68 UString m_spacesForIndentation
;
69 bool m_numberNeedsParens
;
70 bool m_atStartOfStatement
;
71 Precedence m_precedence
;
76 static UString
escapeStringForPrettyPrinting(const UString
& s
)
78 UString escapedString
;
80 for (int i
= 0; i
< s
.size(); i
++) {
81 unsigned short c
= s
.data()[i
].unicode();
84 escapedString
+= "\\\"";
87 escapedString
+= "\\n";
90 escapedString
+= "\\r";
93 escapedString
+= "\\t";
96 escapedString
+= "\\\\";
99 if (c
< 128 && isPrintableChar(c
))
100 escapedString
.append(c
);
103 snprintf(hexValue
, 7, "\\u%04x", c
);
104 escapedString
+= hexValue
;
109 return escapedString
;
112 static const char* operatorString(Operator oper
)
144 ASSERT_NOT_REACHED();
148 static bool isParserRoundTripNumber(const UString
& string
)
150 double number
= string
.toDouble(false, false);
151 if (isnan(number
) || isinf(number
))
153 return string
== UString::from(number
);
158 SourceStream
& SourceStream::operator<<(char c
)
160 m_numberNeedsParens
= false;
161 m_atStartOfStatement
= false;
167 SourceStream
& SourceStream::operator<<(const char* s
)
169 m_numberNeedsParens
= false;
170 m_atStartOfStatement
= false;
175 SourceStream
& SourceStream::operator<<(double value
)
177 bool needParens
= m_numberNeedsParens
;
178 m_numberNeedsParens
= false;
179 m_atStartOfStatement
= false;
182 m_string
.append('(');
183 m_string
+= UString::from(value
);
185 m_string
.append(')');
190 SourceStream
& SourceStream::operator<<(const UString
& s
)
192 m_numberNeedsParens
= false;
193 m_atStartOfStatement
= false;
198 SourceStream
& SourceStream::operator<<(const Identifier
& s
)
200 m_numberNeedsParens
= false;
201 m_atStartOfStatement
= false;
202 m_string
+= s
.ustring();
206 SourceStream
& SourceStream::operator<<(const Node
* n
)
208 bool needParens
= (m_precedence
!= PrecExpression
&& n
->precedence() > m_precedence
) || (m_atStartOfStatement
&& n
->needsParensIfLeftmost());
209 m_precedence
= PrecExpression
;
213 m_numberNeedsParens
= false;
214 m_string
.append('(');
218 m_string
.append(')');
222 SourceStream
& SourceStream::operator<<(EndlType
)
224 m_numberNeedsParens
= false;
225 m_atStartOfStatement
= true;
226 m_string
.append('\n');
227 m_string
.append(m_spacesForIndentation
);
231 SourceStream
& SourceStream::operator<<(IndentType
)
233 m_numberNeedsParens
= false;
234 m_atStartOfStatement
= false;
235 m_spacesForIndentation
+= " ";
239 SourceStream
& SourceStream::operator<<(UnindentType
)
241 m_numberNeedsParens
= false;
242 m_atStartOfStatement
= false;
243 m_spacesForIndentation
= m_spacesForIndentation
.substr(0, m_spacesForIndentation
.size() - 2);
247 inline SourceStream
& SourceStream::operator<<(DotExprType
)
249 m_numberNeedsParens
= true;
253 inline SourceStream
& SourceStream::operator<<(Precedence precedence
)
255 m_precedence
= precedence
;
259 static void streamLeftAssociativeBinaryOperator(SourceStream
& s
, Precedence precedence
,
260 const char* operatorString
, const Node
* left
, const Node
* right
)
262 s
<< precedence
<< left
263 << ' ' << operatorString
<< ' '
264 << static_cast<Precedence
>(precedence
- 1) << right
;
267 template <typename T
> static inline void streamLeftAssociativeBinaryOperator(SourceStream
& s
,
268 Precedence p
, const char* o
, const RefPtr
<T
>& l
, const RefPtr
<T
>& r
)
270 streamLeftAssociativeBinaryOperator(s
, p
, o
, l
.get(), r
.get());
273 static inline void bracketNodeStreamTo(SourceStream
& s
, const RefPtr
<ExpressionNode
>& base
, const RefPtr
<ExpressionNode
>& subscript
)
275 s
<< PrecCall
<< base
.get() << "[" << subscript
.get() << "]";
278 static inline void dotNodeStreamTo(SourceStream
& s
, const RefPtr
<ExpressionNode
>& base
, const Identifier
& ident
)
280 s
<< DotExpr
<< PrecCall
<< base
.get() << "." << ident
;
285 UString
Node::toString() const
289 return stream
.toString();
294 void NullNode::streamTo(SourceStream
& s
) const
299 void FalseNode::streamTo(SourceStream
& s
) const
304 void TrueNode::streamTo(SourceStream
& s
) const
309 void PlaceholderTrueNode::streamTo(SourceStream
&) const
313 void NumberNode::streamTo(SourceStream
& s
) const
318 void StringNode::streamTo(SourceStream
& s
) const
320 s
<< '"' << escapeStringForPrettyPrinting(m_value
) << '"';
323 void RegExpNode::streamTo(SourceStream
& s
) const
325 s
<< '/' << m_regExp
->pattern() << '/' << m_regExp
->flags();
328 void ThisNode::streamTo(SourceStream
& s
) const
333 void ResolveNode::streamTo(SourceStream
& s
) const
338 void ElementNode::streamTo(SourceStream
& s
) const
340 for (const ElementNode
* n
= this; n
; n
= n
->m_next
.get()) {
341 for (int i
= 0; i
< n
->m_elision
; i
++)
343 s
<< PrecAssignment
<< n
->m_node
;
349 void ArrayNode::streamTo(SourceStream
& s
) const
351 s
<< '[' << m_element
;
352 for (int i
= 0; i
< m_elision
; i
++)
354 // Parser consumes one elision comma if there's array elements
355 // present in the expression.
356 if (m_optional
&& m_element
)
361 void ObjectLiteralNode::streamTo(SourceStream
& s
) const
364 s
<< "{ " << m_list
<< " }";
369 void PropertyListNode::streamTo(SourceStream
& s
) const
372 for (const PropertyListNode
* n
= m_next
.get(); n
; n
= n
->m_next
.get())
373 s
<< ", " << n
->m_node
;
376 void PropertyNode::streamTo(SourceStream
& s
) const
380 UString propertyName
= name().ustring();
381 if (isParserRoundTripNumber(propertyName
))
384 s
<< '"' << escapeStringForPrettyPrinting(propertyName
) << '"';
385 s
<< ": " << PrecAssignment
<< m_assign
;
390 const FuncExprNode
* func
= static_cast<const FuncExprNode
*>(m_assign
.get());
391 if (m_type
== Getter
)
395 s
<< escapeStringForPrettyPrinting(name().ustring())
396 << "(" << func
->m_parameter
<< ')' << func
->m_body
;
402 void BracketAccessorNode::streamTo(SourceStream
& s
) const
404 bracketNodeStreamTo(s
, m_base
, m_subscript
);
407 void DotAccessorNode::streamTo(SourceStream
& s
) const
409 dotNodeStreamTo(s
, m_base
, m_ident
);
412 void ArgumentListNode::streamTo(SourceStream
& s
) const
414 s
<< PrecAssignment
<< m_expr
;
415 for (ArgumentListNode
* n
= m_next
.get(); n
; n
= n
->m_next
.get())
416 s
<< ", " << PrecAssignment
<< n
->m_expr
;
419 void ArgumentsNode::streamTo(SourceStream
& s
) const
421 s
<< '(' << m_listNode
<< ')';
424 void NewExprNode::streamTo(SourceStream
& s
) const
426 s
<< "new " << PrecMember
<< m_expr
<< m_args
;
429 void FunctionCallValueNode::streamTo(SourceStream
& s
) const
431 s
<< PrecCall
<< m_expr
<< m_args
;
434 void FunctionCallResolveNode::streamTo(SourceStream
& s
) const
436 s
<< m_ident
<< m_args
;
439 void FunctionCallBracketNode::streamTo(SourceStream
& s
) const
441 bracketNodeStreamTo(s
, m_base
, m_subscript
);
445 void FunctionCallDotNode::streamTo(SourceStream
& s
) const
447 dotNodeStreamTo(s
, m_base
, m_ident
);
451 void PostIncResolveNode::streamTo(SourceStream
& s
) const
453 s
<< m_ident
<< "++";
456 void PostDecResolveNode::streamTo(SourceStream
& s
) const
458 s
<< m_ident
<< "--";
461 void PostIncBracketNode::streamTo(SourceStream
& s
) const
463 bracketNodeStreamTo(s
, m_base
, m_subscript
);
467 void PostDecBracketNode::streamTo(SourceStream
& s
) const
469 bracketNodeStreamTo(s
, m_base
, m_subscript
);
473 void PostIncDotNode::streamTo(SourceStream
& s
) const
475 dotNodeStreamTo(s
, m_base
, m_ident
);
479 void PostDecDotNode::streamTo(SourceStream
& s
) const
481 dotNodeStreamTo(s
, m_base
, m_ident
);
485 void PostfixErrorNode::streamTo(SourceStream
& s
) const
487 s
<< PrecLeftHandSide
<< m_expr
;
488 if (m_operator
== OpPlusPlus
)
494 void DeleteResolveNode::streamTo(SourceStream
& s
) const
496 s
<< "delete " << m_ident
;
499 void DeleteBracketNode::streamTo(SourceStream
& s
) const
502 bracketNodeStreamTo(s
, m_base
, m_subscript
);
505 void DeleteDotNode::streamTo(SourceStream
& s
) const
508 dotNodeStreamTo(s
, m_base
, m_ident
);
511 void DeleteValueNode::streamTo(SourceStream
& s
) const
513 s
<< "delete " << PrecUnary
<< m_expr
;
516 void VoidNode::streamTo(SourceStream
& s
) const
518 s
<< "void " << PrecUnary
<< m_expr
;
521 void TypeOfValueNode::streamTo(SourceStream
& s
) const
523 s
<< "typeof " << PrecUnary
<< m_expr
;
526 void TypeOfResolveNode::streamTo(SourceStream
& s
) const
528 s
<< "typeof " << m_ident
;
531 void PreIncResolveNode::streamTo(SourceStream
& s
) const
533 s
<< "++" << m_ident
;
536 void PreDecResolveNode::streamTo(SourceStream
& s
) const
538 s
<< "--" << m_ident
;
541 void PreIncBracketNode::streamTo(SourceStream
& s
) const
544 bracketNodeStreamTo(s
, m_base
, m_subscript
);
547 void PreDecBracketNode::streamTo(SourceStream
& s
) const
550 bracketNodeStreamTo(s
, m_base
, m_subscript
);
553 void PreIncDotNode::streamTo(SourceStream
& s
) const
556 dotNodeStreamTo(s
, m_base
, m_ident
);
559 void PreDecDotNode::streamTo(SourceStream
& s
) const
562 dotNodeStreamTo(s
, m_base
, m_ident
);
565 void PrefixErrorNode::streamTo(SourceStream
& s
) const
567 if (m_operator
== OpPlusPlus
)
568 s
<< "++" << PrecUnary
<< m_expr
;
570 s
<< "--" << PrecUnary
<< m_expr
;
573 void UnaryPlusNode::streamTo(SourceStream
& s
) const
575 s
<< "+ " << PrecUnary
<< m_expr
;
578 void NegateNode::streamTo(SourceStream
& s
) const
580 s
<< "- " << PrecUnary
<< m_expr
;
583 void BitwiseNotNode::streamTo(SourceStream
& s
) const
585 s
<< "~" << PrecUnary
<< m_expr
;
588 void LogicalNotNode::streamTo(SourceStream
& s
) const
590 s
<< "!" << PrecUnary
<< m_expr
;
593 void MultNode::streamTo(SourceStream
& s
) const
595 streamLeftAssociativeBinaryOperator(s
, precedence(), "*", m_term1
, m_term2
);
598 void DivNode::streamTo(SourceStream
& s
) const
600 streamLeftAssociativeBinaryOperator(s
, precedence(), "/", m_term1
, m_term2
);
603 void ModNode::streamTo(SourceStream
& s
) const
605 streamLeftAssociativeBinaryOperator(s
, precedence(), "%", m_term1
, m_term2
);
608 void AddNode::streamTo(SourceStream
& s
) const
610 streamLeftAssociativeBinaryOperator(s
, precedence(), "+", m_term1
, m_term2
);
613 void SubNode::streamTo(SourceStream
& s
) const
615 streamLeftAssociativeBinaryOperator(s
, precedence(), "-", m_term1
, m_term2
);
618 void LeftShiftNode::streamTo(SourceStream
& s
) const
620 streamLeftAssociativeBinaryOperator(s
, precedence(), "<<", m_term1
, m_term2
);
623 void RightShiftNode::streamTo(SourceStream
& s
) const
625 streamLeftAssociativeBinaryOperator(s
, precedence(), ">>", m_term1
, m_term2
);
628 void UnsignedRightShiftNode::streamTo(SourceStream
& s
) const
630 streamLeftAssociativeBinaryOperator(s
, precedence(), ">>>", m_term1
, m_term2
);
633 void LessNode::streamTo(SourceStream
& s
) const
635 streamLeftAssociativeBinaryOperator(s
, precedence(), "<", m_expr1
, m_expr2
);
638 void GreaterNode::streamTo(SourceStream
& s
) const
640 streamLeftAssociativeBinaryOperator(s
, precedence(), ">", m_expr1
, m_expr2
);
643 void LessEqNode::streamTo(SourceStream
& s
) const
645 streamLeftAssociativeBinaryOperator(s
, precedence(), "<=", m_expr1
, m_expr2
);
648 void GreaterEqNode::streamTo(SourceStream
& s
) const
650 streamLeftAssociativeBinaryOperator(s
, precedence(), ">=", m_expr1
, m_expr2
);
653 void InstanceOfNode::streamTo(SourceStream
& s
) const
655 streamLeftAssociativeBinaryOperator(s
, precedence(), "instanceof", m_expr1
, m_expr2
);
658 void InNode::streamTo(SourceStream
& s
) const
660 streamLeftAssociativeBinaryOperator(s
, precedence(), "in", m_expr1
, m_expr2
);
663 void EqualNode::streamTo(SourceStream
& s
) const
665 streamLeftAssociativeBinaryOperator(s
, precedence(), "==", m_expr1
, m_expr2
);
668 void NotEqualNode::streamTo(SourceStream
& s
) const
670 streamLeftAssociativeBinaryOperator(s
, precedence(), "!=", m_expr1
, m_expr2
);
673 void StrictEqualNode::streamTo(SourceStream
& s
) const
675 streamLeftAssociativeBinaryOperator(s
, precedence(), "===", m_expr1
, m_expr2
);
678 void NotStrictEqualNode::streamTo(SourceStream
& s
) const
680 streamLeftAssociativeBinaryOperator(s
, precedence(), "!==", m_expr1
, m_expr2
);
683 void BitAndNode::streamTo(SourceStream
& s
) const
685 streamLeftAssociativeBinaryOperator(s
, precedence(), "&", m_expr1
, m_expr2
);
688 void BitXOrNode::streamTo(SourceStream
& s
) const
690 streamLeftAssociativeBinaryOperator(s
, precedence(), "^", m_expr1
, m_expr2
);
693 void BitOrNode::streamTo(SourceStream
& s
) const
695 streamLeftAssociativeBinaryOperator(s
, precedence(), "|", m_expr1
, m_expr2
);
698 void LogicalAndNode::streamTo(SourceStream
& s
) const
700 streamLeftAssociativeBinaryOperator(s
, precedence(), "&&", m_expr1
, m_expr2
);
703 void LogicalOrNode::streamTo(SourceStream
& s
) const
705 streamLeftAssociativeBinaryOperator(s
, precedence(), "||", m_expr1
, m_expr2
);
708 void ConditionalNode::streamTo(SourceStream
& s
) const
710 s
<< PrecLogicalOr
<< m_logical
711 << " ? " << PrecAssignment
<< m_expr1
712 << " : " << PrecAssignment
<< m_expr2
;
715 void ReadModifyResolveNode::streamTo(SourceStream
& s
) const
717 s
<< m_ident
<< ' ' << operatorString(m_operator
) << ' ' << PrecAssignment
<< m_right
;
720 void AssignResolveNode::streamTo(SourceStream
& s
) const
722 s
<< m_ident
<< " = " << PrecAssignment
<< m_right
;
725 void ReadModifyBracketNode::streamTo(SourceStream
& s
) const
727 bracketNodeStreamTo(s
, m_base
, m_subscript
);
728 s
<< ' ' << operatorString(m_operator
) << ' ' << PrecAssignment
<< m_right
;
731 void AssignBracketNode::streamTo(SourceStream
& s
) const
733 bracketNodeStreamTo(s
, m_base
, m_subscript
);
734 s
<< " = " << PrecAssignment
<< m_right
;
737 void ReadModifyDotNode::streamTo(SourceStream
& s
) const
739 dotNodeStreamTo(s
, m_base
, m_ident
);
740 s
<< ' ' << operatorString(m_operator
) << ' ' << PrecAssignment
<< m_right
;
743 void AssignDotNode::streamTo(SourceStream
& s
) const
745 dotNodeStreamTo(s
, m_base
, m_ident
);
746 s
<< " = " << PrecAssignment
<< m_right
;
749 void AssignErrorNode::streamTo(SourceStream
& s
) const
751 s
<< PrecLeftHandSide
<< m_left
<< ' '
752 << operatorString(m_operator
) << ' ' << PrecAssignment
<< m_right
;
755 void CommaNode::streamTo(SourceStream
& s
) const
757 s
<< PrecAssignment
<< m_expr1
<< ", " << PrecAssignment
<< m_expr2
;
760 void ConstDeclNode::streamTo(SourceStream
& s
) const
764 s
<< " = " << m_init
;
765 for (ConstDeclNode
* n
= m_next
.get(); n
; n
= n
->m_next
.get()) {
766 s
<< ", " << m_ident
;
768 s
<< " = " << m_init
;
772 void ConstStatementNode::streamTo(SourceStream
& s
) const
774 s
<< Endl
<< "const " << m_next
<< ';';
777 static inline void statementListStreamTo(const Vector
<RefPtr
<StatementNode
> >& nodes
, SourceStream
& s
)
779 for (Vector
<RefPtr
<StatementNode
> >::const_iterator ptr
= nodes
.begin(); ptr
!= nodes
.end(); ptr
++)
783 void BlockNode::streamTo(SourceStream
& s
) const
785 s
<< Endl
<< "{" << Indent
;
786 statementListStreamTo(m_children
, s
);
787 s
<< Unindent
<< Endl
<< "}";
790 void ScopeNode::streamTo(SourceStream
& s
) const
792 s
<< Endl
<< "{" << Indent
;
794 bool printedVar
= false;
795 for (size_t i
= 0; i
< m_varStack
.size(); ++i
) {
796 if (m_varStack
[i
].second
== 0) {
802 s
<< m_varStack
[i
].first
;
808 statementListStreamTo(m_children
, s
);
809 s
<< Unindent
<< Endl
<< "}";
812 void EmptyStatementNode::streamTo(SourceStream
& s
) const
817 void ExprStatementNode::streamTo(SourceStream
& s
) const
819 s
<< Endl
<< m_expr
<< ';';
822 void VarStatementNode::streamTo(SourceStream
& s
) const
824 s
<< Endl
<< "var " << m_expr
<< ';';
827 void IfNode::streamTo(SourceStream
& s
) const
829 s
<< Endl
<< "if (" << m_condition
<< ')' << Indent
<< m_ifBlock
<< Unindent
;
832 void IfElseNode::streamTo(SourceStream
& s
) const
835 s
<< Endl
<< "else" << Indent
<< m_elseBlock
<< Unindent
;
838 void DoWhileNode::streamTo(SourceStream
& s
) const
840 s
<< Endl
<< "do " << Indent
<< m_statement
<< Unindent
<< Endl
841 << "while (" << m_expr
<< ");";
844 void WhileNode::streamTo(SourceStream
& s
) const
846 s
<< Endl
<< "while (" << m_expr
<< ')' << Indent
<< m_statement
<< Unindent
;
849 void ForNode::streamTo(SourceStream
& s
) const
852 << (m_expr1WasVarDecl
? "var " : "")
856 << ')' << Indent
<< m_statement
<< Unindent
;
859 void ForInNode::streamTo(SourceStream
& s
) const
861 s
<< Endl
<< "for (";
862 if (m_identIsVarDecl
) {
867 s
<< PrecLeftHandSide
<< m_lexpr
;
869 s
<< PrecLeftHandSide
<< m_lexpr
;
871 s
<< " in " << m_expr
<< ')' << Indent
<< m_statement
<< Unindent
;
874 void ContinueNode::streamTo(SourceStream
& s
) const
876 s
<< Endl
<< "continue";
877 if (!m_ident
.isNull())
882 void BreakNode::streamTo(SourceStream
& s
) const
884 s
<< Endl
<< "break";
885 if (!m_ident
.isNull())
890 void ReturnNode::streamTo(SourceStream
& s
) const
892 s
<< Endl
<< "return";
898 void WithNode::streamTo(SourceStream
& s
) const
900 s
<< Endl
<< "with (" << m_expr
<< ") " << m_statement
;
903 void CaseClauseNode::streamTo(SourceStream
& s
) const
907 s
<< "case " << m_expr
;
911 statementListStreamTo(m_children
, s
);
915 void ClauseListNode::streamTo(SourceStream
& s
) const
917 for (const ClauseListNode
* n
= this; n
; n
= n
->getNext())
921 void CaseBlockNode::streamTo(SourceStream
& s
) const
923 for (const ClauseListNode
* n
= m_list1
.get(); n
; n
= n
->getNext())
925 s
<< m_defaultClause
;
926 for (const ClauseListNode
* n
= m_list2
.get(); n
; n
= n
->getNext())
930 void SwitchNode::streamTo(SourceStream
& s
) const
932 s
<< Endl
<< "switch (" << m_expr
<< ") {"
933 << Indent
<< m_block
<< Unindent
937 void LabelNode::streamTo(SourceStream
& s
) const
939 s
<< Endl
<< m_label
<< ":" << Indent
<< m_statement
<< Unindent
;
942 void ThrowNode::streamTo(SourceStream
& s
) const
944 s
<< Endl
<< "throw " << m_expr
<< ';';
947 void TryNode::streamTo(SourceStream
& s
) const
949 s
<< Endl
<< "try " << m_tryBlock
;
951 s
<< Endl
<< "catch (" << m_exceptionIdent
<< ')' << m_catchBlock
;
953 s
<< Endl
<< "finally " << m_finallyBlock
;
956 void ParameterNode::streamTo(SourceStream
& s
) const
959 for (ParameterNode
* n
= m_next
.get(); n
; n
= n
->m_next
.get())
960 s
<< ", " << n
->m_ident
;
963 void FuncDeclNode::streamTo(SourceStream
& s
) const
965 s
<< Endl
<< "function " << m_ident
<< '(' << m_parameter
<< ')' << m_body
;
968 void FuncExprNode::streamTo(SourceStream
& s
) const
970 s
<< "function " << m_ident
<< '(' << m_parameter
<< ')' << m_body
;