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<<(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<<(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
, Node
* left
, 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()
289 return stream
.toString();
294 void NullNode::streamTo(SourceStream
& s
)
299 void FalseNode::streamTo(SourceStream
& s
)
304 void TrueNode::streamTo(SourceStream
& s
)
309 void PlaceholderTrueNode::streamTo(SourceStream
&)
313 void NumberNode::streamTo(SourceStream
& s
)
318 void StringNode::streamTo(SourceStream
& s
)
320 s
<< '"' << escapeStringForPrettyPrinting(m_value
) << '"';
323 void RegExpNode::streamTo(SourceStream
& s
)
325 s
<< '/' << m_regExp
->pattern() << '/' << m_regExp
->flags();
328 void ThisNode::streamTo(SourceStream
& s
)
333 void ResolveNode::streamTo(SourceStream
& s
)
338 void ElementNode::streamTo(SourceStream
& s
)
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
)
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
)
364 s
<< "{ " << m_list
<< " }";
369 void PropertyListNode::streamTo(SourceStream
& s
)
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
)
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
)
404 bracketNodeStreamTo(s
, m_base
, m_subscript
);
407 void DotAccessorNode::streamTo(SourceStream
& s
)
409 dotNodeStreamTo(s
, m_base
, m_ident
);
412 void ArgumentListNode::streamTo(SourceStream
& s
)
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
)
421 s
<< '(' << m_listNode
<< ')';
424 void NewExprNode::streamTo(SourceStream
& s
)
426 s
<< "new " << PrecMember
<< m_expr
<< m_args
;
429 void FunctionCallValueNode::streamTo(SourceStream
& s
)
431 s
<< PrecCall
<< m_expr
<< m_args
;
434 void FunctionCallResolveNode::streamTo(SourceStream
& s
)
436 s
<< m_ident
<< m_args
;
439 void FunctionCallBracketNode::streamTo(SourceStream
& s
)
441 bracketNodeStreamTo(s
, m_base
, m_subscript
);
445 void FunctionCallDotNode::streamTo(SourceStream
& s
)
447 dotNodeStreamTo(s
, m_base
, m_ident
);
451 void PostIncResolveNode::streamTo(SourceStream
& s
)
453 s
<< m_ident
<< "++";
456 void PostDecResolveNode::streamTo(SourceStream
& s
)
458 s
<< m_ident
<< "--";
461 void PostIncBracketNode::streamTo(SourceStream
& s
)
463 bracketNodeStreamTo(s
, m_base
, m_subscript
);
467 void PostDecBracketNode::streamTo(SourceStream
& s
)
469 bracketNodeStreamTo(s
, m_base
, m_subscript
);
473 void PostIncDotNode::streamTo(SourceStream
& s
)
475 dotNodeStreamTo(s
, m_base
, m_ident
);
479 void PostDecDotNode::streamTo(SourceStream
& s
)
481 dotNodeStreamTo(s
, m_base
, m_ident
);
485 void PostfixErrorNode::streamTo(SourceStream
& s
)
487 s
<< PrecLeftHandSide
<< m_expr
;
488 if (m_operator
== OpPlusPlus
)
494 void DeleteResolveNode::streamTo(SourceStream
& s
)
496 s
<< "delete " << m_ident
;
499 void DeleteBracketNode::streamTo(SourceStream
& s
)
502 bracketNodeStreamTo(s
, m_base
, m_subscript
);
505 void DeleteDotNode::streamTo(SourceStream
& s
)
508 dotNodeStreamTo(s
, m_base
, m_ident
);
511 void DeleteValueNode::streamTo(SourceStream
& s
)
513 s
<< "delete " << PrecUnary
<< m_expr
;
516 void VoidNode::streamTo(SourceStream
& s
)
518 s
<< "void " << PrecUnary
<< m_expr
;
521 void TypeOfValueNode::streamTo(SourceStream
& s
)
523 s
<< "typeof " << PrecUnary
<< m_expr
;
526 void TypeOfResolveNode::streamTo(SourceStream
& s
)
528 s
<< "typeof " << m_ident
;
531 void PreIncResolveNode::streamTo(SourceStream
& s
)
533 s
<< "++" << m_ident
;
536 void PreDecResolveNode::streamTo(SourceStream
& s
)
538 s
<< "--" << m_ident
;
541 void PreIncBracketNode::streamTo(SourceStream
& s
)
544 bracketNodeStreamTo(s
, m_base
, m_subscript
);
547 void PreDecBracketNode::streamTo(SourceStream
& s
)
550 bracketNodeStreamTo(s
, m_base
, m_subscript
);
553 void PreIncDotNode::streamTo(SourceStream
& s
)
556 dotNodeStreamTo(s
, m_base
, m_ident
);
559 void PreDecDotNode::streamTo(SourceStream
& s
)
562 dotNodeStreamTo(s
, m_base
, m_ident
);
565 void PrefixErrorNode::streamTo(SourceStream
& s
)
567 if (m_operator
== OpPlusPlus
)
568 s
<< "++" << PrecUnary
<< m_expr
;
570 s
<< "--" << PrecUnary
<< m_expr
;
573 void UnaryPlusNode::streamTo(SourceStream
& s
)
575 s
<< "+ " << PrecUnary
<< m_expr
;
578 void NegateNode::streamTo(SourceStream
& s
)
580 s
<< "- " << PrecUnary
<< m_expr
;
583 void BitwiseNotNode::streamTo(SourceStream
& s
)
585 s
<< "~" << PrecUnary
<< m_expr
;
588 void LogicalNotNode::streamTo(SourceStream
& s
)
590 s
<< "!" << PrecUnary
<< m_expr
;
593 void MultNode::streamTo(SourceStream
& s
)
595 streamLeftAssociativeBinaryOperator(s
, precedence(), "*", m_term1
, m_term2
);
598 void DivNode::streamTo(SourceStream
& s
)
600 streamLeftAssociativeBinaryOperator(s
, precedence(), "/", m_term1
, m_term2
);
603 void ModNode::streamTo(SourceStream
& s
)
605 streamLeftAssociativeBinaryOperator(s
, precedence(), "%", m_term1
, m_term2
);
608 void AddNode::streamTo(SourceStream
& s
)
610 streamLeftAssociativeBinaryOperator(s
, precedence(), "+", m_term1
, m_term2
);
613 void SubNode::streamTo(SourceStream
& s
)
615 streamLeftAssociativeBinaryOperator(s
, precedence(), "-", m_term1
, m_term2
);
618 void LeftShiftNode::streamTo(SourceStream
& s
)
620 streamLeftAssociativeBinaryOperator(s
, precedence(), "<<", m_term1
, m_term2
);
623 void RightShiftNode::streamTo(SourceStream
& s
)
625 streamLeftAssociativeBinaryOperator(s
, precedence(), ">>", m_term1
, m_term2
);
628 void UnsignedRightShiftNode::streamTo(SourceStream
& s
)
630 streamLeftAssociativeBinaryOperator(s
, precedence(), ">>>", m_term1
, m_term2
);
633 void LessNode::streamTo(SourceStream
& s
)
635 streamLeftAssociativeBinaryOperator(s
, precedence(), "<", m_expr1
, m_expr2
);
638 void GreaterNode::streamTo(SourceStream
& s
)
640 streamLeftAssociativeBinaryOperator(s
, precedence(), ">", m_expr1
, m_expr2
);
643 void LessEqNode::streamTo(SourceStream
& s
)
645 streamLeftAssociativeBinaryOperator(s
, precedence(), "<=", m_expr1
, m_expr2
);
648 void GreaterEqNode::streamTo(SourceStream
& s
)
650 streamLeftAssociativeBinaryOperator(s
, precedence(), ">=", m_expr1
, m_expr2
);
653 void InstanceOfNode::streamTo(SourceStream
& s
)
655 streamLeftAssociativeBinaryOperator(s
, precedence(), "instanceof", m_expr1
, m_expr2
);
658 void InNode::streamTo(SourceStream
& s
)
660 streamLeftAssociativeBinaryOperator(s
, precedence(), "in", m_expr1
, m_expr2
);
663 void EqualNode::streamTo(SourceStream
& s
)
665 streamLeftAssociativeBinaryOperator(s
, precedence(), "==", m_expr1
, m_expr2
);
668 void NotEqualNode::streamTo(SourceStream
& s
)
670 streamLeftAssociativeBinaryOperator(s
, precedence(), "!=", m_expr1
, m_expr2
);
673 void StrictEqualNode::streamTo(SourceStream
& s
)
675 streamLeftAssociativeBinaryOperator(s
, precedence(), "===", m_expr1
, m_expr2
);
678 void NotStrictEqualNode::streamTo(SourceStream
& s
)
680 streamLeftAssociativeBinaryOperator(s
, precedence(), "!==", m_expr1
, m_expr2
);
683 void BitAndNode::streamTo(SourceStream
& s
)
685 streamLeftAssociativeBinaryOperator(s
, precedence(), "&", m_expr1
, m_expr2
);
688 void BitXOrNode::streamTo(SourceStream
& s
)
690 streamLeftAssociativeBinaryOperator(s
, precedence(), "^", m_expr1
, m_expr2
);
693 void BitOrNode::streamTo(SourceStream
& s
)
695 streamLeftAssociativeBinaryOperator(s
, precedence(), "|", m_expr1
, m_expr2
);
698 void LogicalAndNode::streamTo(SourceStream
& s
)
700 streamLeftAssociativeBinaryOperator(s
, precedence(), "&&", m_expr1
, m_expr2
);
703 void LogicalOrNode::streamTo(SourceStream
& s
)
705 streamLeftAssociativeBinaryOperator(s
, precedence(), "||", m_expr1
, m_expr2
);
708 void ConditionalNode::streamTo(SourceStream
& s
)
710 s
<< PrecLogicalOr
<< m_logical
711 << " ? " << PrecAssignment
<< m_expr1
712 << " : " << PrecAssignment
<< m_expr2
;
715 void ReadModifyResolveNode::streamTo(SourceStream
& s
)
717 s
<< m_ident
<< ' ' << operatorString(m_operator
) << ' ' << PrecAssignment
<< m_right
;
720 void AssignResolveNode::streamTo(SourceStream
& s
)
722 s
<< m_ident
<< " = " << PrecAssignment
<< m_right
;
725 void ReadModifyBracketNode::streamTo(SourceStream
& s
)
727 bracketNodeStreamTo(s
, m_base
, m_subscript
);
728 s
<< ' ' << operatorString(m_operator
) << ' ' << PrecAssignment
<< m_right
;
731 void AssignBracketNode::streamTo(SourceStream
& s
)
733 bracketNodeStreamTo(s
, m_base
, m_subscript
);
734 s
<< " = " << PrecAssignment
<< m_right
;
737 void ReadModifyDotNode::streamTo(SourceStream
& s
)
739 dotNodeStreamTo(s
, m_base
, m_ident
);
740 s
<< ' ' << operatorString(m_operator
) << ' ' << PrecAssignment
<< m_right
;
743 void AssignDotNode::streamTo(SourceStream
& s
)
745 dotNodeStreamTo(s
, m_base
, m_ident
);
746 s
<< " = " << PrecAssignment
<< m_right
;
749 void AssignErrorNode::streamTo(SourceStream
& s
)
751 s
<< PrecLeftHandSide
<< m_left
<< ' '
752 << operatorString(m_operator
) << ' ' << PrecAssignment
<< m_right
;
755 void CommaNode::streamTo(SourceStream
& s
)
757 s
<< PrecAssignment
<< m_expr1
<< ", " << PrecAssignment
<< m_expr2
;
760 void ConstDeclNode::streamTo(SourceStream
& s
)
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
)
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
)
785 s
<< Endl
<< "{" << Indent
;
786 statementListStreamTo(m_children
, s
);
787 s
<< Unindent
<< Endl
<< "}";
790 void ScopeNode::streamTo(SourceStream
& s
)
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 FunctionBodyNode::streamTo(SourceStream
& s
)
814 if (m_children
.isEmpty())
815 parser().reparse(this);
816 ScopeNode::streamTo(s
);
819 void EmptyStatementNode::streamTo(SourceStream
& s
)
824 void ExprStatementNode::streamTo(SourceStream
& s
)
826 s
<< Endl
<< m_expr
<< ';';
829 void VarStatementNode::streamTo(SourceStream
& s
)
831 s
<< Endl
<< "var " << m_expr
<< ';';
834 void IfNode::streamTo(SourceStream
& s
)
836 s
<< Endl
<< "if (" << m_condition
<< ')' << Indent
<< m_ifBlock
<< Unindent
;
839 void IfElseNode::streamTo(SourceStream
& s
)
842 s
<< Endl
<< "else" << Indent
<< m_elseBlock
<< Unindent
;
845 void DoWhileNode::streamTo(SourceStream
& s
)
847 s
<< Endl
<< "do " << Indent
<< m_statement
<< Unindent
<< Endl
848 << "while (" << m_expr
<< ");";
851 void WhileNode::streamTo(SourceStream
& s
)
853 s
<< Endl
<< "while (" << m_expr
<< ')' << Indent
<< m_statement
<< Unindent
;
856 void ForNode::streamTo(SourceStream
& s
)
859 << (m_expr1WasVarDecl
? "var " : "")
863 << ')' << Indent
<< m_statement
<< Unindent
;
866 void ForInNode::streamTo(SourceStream
& s
)
868 s
<< Endl
<< "for (";
869 if (m_identIsVarDecl
) {
874 s
<< PrecLeftHandSide
<< m_lexpr
;
876 s
<< PrecLeftHandSide
<< m_lexpr
;
878 s
<< " in " << m_expr
<< ')' << Indent
<< m_statement
<< Unindent
;
881 void ContinueNode::streamTo(SourceStream
& s
)
883 s
<< Endl
<< "continue";
884 if (!m_ident
.isNull())
889 void BreakNode::streamTo(SourceStream
& s
)
891 s
<< Endl
<< "break";
892 if (!m_ident
.isNull())
897 void ReturnNode::streamTo(SourceStream
& s
)
899 s
<< Endl
<< "return";
905 void WithNode::streamTo(SourceStream
& s
)
907 s
<< Endl
<< "with (" << m_expr
<< ") " << m_statement
;
910 void CaseClauseNode::streamTo(SourceStream
& s
)
914 s
<< "case " << m_expr
;
918 statementListStreamTo(m_children
, s
);
922 void ClauseListNode::streamTo(SourceStream
& s
)
924 for (const ClauseListNode
* n
= this; n
; n
= n
->getNext())
928 void CaseBlockNode::streamTo(SourceStream
& s
)
930 for (const ClauseListNode
* n
= m_list1
.get(); n
; n
= n
->getNext())
932 s
<< m_defaultClause
;
933 for (const ClauseListNode
* n
= m_list2
.get(); n
; n
= n
->getNext())
937 void SwitchNode::streamTo(SourceStream
& s
)
939 s
<< Endl
<< "switch (" << m_expr
<< ") {"
940 << Indent
<< m_block
<< Unindent
944 void LabelNode::streamTo(SourceStream
& s
)
946 s
<< Endl
<< m_label
<< ":" << Indent
<< m_statement
<< Unindent
;
949 void ThrowNode::streamTo(SourceStream
& s
)
951 s
<< Endl
<< "throw " << m_expr
<< ';';
954 void TryNode::streamTo(SourceStream
& s
)
956 s
<< Endl
<< "try " << m_tryBlock
;
958 s
<< Endl
<< "catch (" << m_exceptionIdent
<< ')' << m_catchBlock
;
960 s
<< Endl
<< "finally " << m_finallyBlock
;
963 void ParameterNode::streamTo(SourceStream
& s
)
966 for (ParameterNode
* n
= m_next
.get(); n
; n
= n
->m_next
.get())
967 s
<< ", " << n
->m_ident
;
970 void FuncDeclNode::streamTo(SourceStream
& s
)
972 s
<< Endl
<< "function " << m_ident
<< '(' << m_parameter
<< ')' << m_body
;
975 void FuncExprNode::streamTo(SourceStream
& s
)
977 s
<< "function " << m_ident
<< '(' << m_parameter
<< ')' << m_body
;