#include "config.h"
#include "nodes.h"
#include "function.h"
namespace KJS {
class SourceStream {
public:
enum Format {
Endl, Indent, Unindent, DotExpr
};
SourceStream() : m_groupIfNumber(false) {}
UString toString() const { return str; }
SourceStream& operator<<(const Identifier &);
SourceStream& operator<<(const UString &);
SourceStream& operator<<(const char *);
SourceStream& operator<<(double);
SourceStream& operator<<(char);
SourceStream& operator<<(Format f);
SourceStream& operator<<(const Node *);
template <typename T> SourceStream& operator<<(RefPtr<T> n) { return this->operator<<(n.get()); }
private:
UString str;
UString ind;
bool m_groupIfNumber;
};
}
using namespace KJS;
SourceStream& SourceStream::operator<<(char c)
{
m_groupIfNumber = false;
UChar ch(c);
str += UString(&ch, 1);
return *this;
}
SourceStream& SourceStream::operator<<(const char *s)
{
m_groupIfNumber = false;
str += UString(s);
return *this;
}
SourceStream& SourceStream::operator<<(double value)
{
if (m_groupIfNumber)
str.append("(");
str += UString::from(value);
if (m_groupIfNumber)
str.append(")");
m_groupIfNumber = false;
return *this;
}
SourceStream& SourceStream::operator<<(const UString &s)
{
m_groupIfNumber = false;
str += s;
return *this;
}
SourceStream& SourceStream::operator<<(const Identifier &s)
{
m_groupIfNumber = false;
str += s.ustring();
return *this;
}
SourceStream& SourceStream::operator<<(const Node *n)
{
if (n)
n->streamTo(*this);
m_groupIfNumber = false;
return *this;
}
SourceStream& SourceStream::operator<<(Format f)
{
m_groupIfNumber = false;
switch (f) {
case Endl:
str += "\n" + ind;
break;
case Indent:
ind += " ";
break;
case Unindent:
ind = ind.substr(0, ind.size() - 2);
break;
case DotExpr:
m_groupIfNumber = true;
break;
}
return *this;
}
UString Node::toString() const
{
SourceStream str;
streamTo(str);
return str.toString();
}
void NullNode::streamTo(SourceStream &s) const { s << "null"; }
void BooleanNode::streamTo(SourceStream &s) const
{
s << (value ? "true" : "false");
}
void NumberNode::streamTo(SourceStream &s) const { s << value; }
void StringNode::streamTo(SourceStream &s) const
{
s << '"' << escapeStringForPrettyPrinting(value) << '"';
}
void RegExpNode::streamTo(SourceStream &s) const
{
s << "/" << pattern << "/" << flags;
}
void ThisNode::streamTo(SourceStream &s) const { s << "this"; }
void ResolveNode::streamTo(SourceStream &s) const { s << ident; }
void GroupNode::streamTo(SourceStream &s) const
{
s << "(" << group << ")";
}
void ElementNode::streamTo(SourceStream &s) const
{
for (const ElementNode *n = this; n; n = n->next.get()) {
for (int i = 0; i < n->elision; i++)
s << ",";
s << n->node;
if (n->next)
s << ",";
}
}
void ArrayNode::streamTo(SourceStream &s) const
{
s << "[" << element;
for (int i = 0; i < elision; i++)
s << ",";
if (opt && element)
s << ",";
s << "]";
}
void ObjectLiteralNode::streamTo(SourceStream &s) const
{
if (list)
s << "{ " << list << " }";
else
s << "{ }";
}
void PropertyListNode::streamTo(SourceStream &s) const
{
s << node;
for (const PropertyListNode *n = next.get(); n; n = n->next.get())
s << ", " << n->node;
}
void PropertyNode::streamTo(SourceStream &s) const
{
switch (type) {
case Constant:
s << name << ": " << assign;
break;
case Getter:
case Setter: {
const FuncExprNode *func = static_cast<const FuncExprNode *>(assign.get());
if (type == Getter)
s << "get ";
else
s << "set ";
s << name << "(" << func->param << ")" << func->body;
break;
}
}
}
void PropertyNameNode::streamTo(SourceStream &s) const
{
if (str.isNull())
s << UString::from(numeric);
else
s << '"' << escapeStringForPrettyPrinting(str.ustring()) << '"';
}
void BracketAccessorNode::streamTo(SourceStream &s) const
{
s << expr1 << "[" << expr2 << "]";
}
void DotAccessorNode::streamTo(SourceStream &s) const
{
s << SourceStream::DotExpr << expr << "." << ident;
}
void ArgumentListNode::streamTo(SourceStream &s) const
{
s << expr;
for (ArgumentListNode *n = next.get(); n; n = n->next.get())
s << ", " << n->expr;
}
void ArgumentsNode::streamTo(SourceStream &s) const
{
s << "(" << list << ")";
}
void NewExprNode::streamTo(SourceStream &s) const
{
s << "new " << expr << args;
}
void FunctionCallValueNode::streamTo(SourceStream &s) const
{
s << expr << args;
}
void FunctionCallResolveNode::streamTo(SourceStream &s) const
{
s << ident << args;
}
void FunctionCallBracketNode::streamTo(SourceStream &s) const
{
s << base << "[" << subscript << "]" << args;
}
void FunctionCallParenBracketNode::streamTo(SourceStream &s) const
{
s << "(" << base << "[" << subscript << "])" << args;
}
void FunctionCallDotNode::streamTo(SourceStream &s) const
{
s << SourceStream::DotExpr << base << "." << ident << args;
}
void FunctionCallParenDotNode::streamTo(SourceStream &s) const
{
s << "(" << SourceStream::DotExpr << base << "." << ident << ")" << args;
}
void PostfixResolveNode::streamTo(SourceStream &s) const
{
s << m_ident;
if (m_oper == OpPlusPlus)
s << "++";
else
s << "--";
}
void PostfixBracketNode::streamTo(SourceStream &s) const
{
s << m_base << "[" << m_subscript << "]";
if (m_oper == OpPlusPlus)
s << "++";
else
s << "--";
}
void PostfixDotNode::streamTo(SourceStream &s) const
{
s << SourceStream::DotExpr << m_base << "." << m_ident;
if (m_oper == OpPlusPlus)
s << "++";
else
s << "--";
}
void PostfixErrorNode::streamTo(SourceStream& s) const
{
s << m_expr;
if (m_oper == OpPlusPlus)
s << "++";
else
s << "--";
}
void DeleteResolveNode::streamTo(SourceStream &s) const
{
s << "delete " << m_ident;
}
void DeleteBracketNode::streamTo(SourceStream &s) const
{
s << "delete " << m_base << "[" << m_subscript << "]";
}
void DeleteDotNode::streamTo(SourceStream &s) const
{
s << "delete " << SourceStream::DotExpr << m_base << "." << m_ident;
}
void DeleteValueNode::streamTo(SourceStream &s) const
{
s << "delete " << m_expr;
}
void VoidNode::streamTo(SourceStream &s) const
{
s << "void " << expr;
}
void TypeOfValueNode::streamTo(SourceStream &s) const
{
s << "typeof " << m_expr;
}
void TypeOfResolveNode::streamTo(SourceStream &s) const
{
s << "typeof " << m_ident;
}
void PrefixResolveNode::streamTo(SourceStream &s) const
{
if (m_oper == OpPlusPlus)
s << "++";
else
s << "--";
s << m_ident;
}
void PrefixBracketNode::streamTo(SourceStream &s) const
{
if (m_oper == OpPlusPlus)
s << "++";
else
s << "--";
s << m_base << "[" << m_subscript << "]";
}
void PrefixDotNode::streamTo(SourceStream &s) const
{
if (m_oper == OpPlusPlus)
s << "++";
else
s << "--";
s << SourceStream::DotExpr << m_base << "." << m_ident;
}
void PrefixErrorNode::streamTo(SourceStream& s) const
{
if (m_oper == OpPlusPlus)
s << "++";
else
s << "--";
s << m_expr;
}
void UnaryPlusNode::streamTo(SourceStream &s) const
{
s << "+ " << expr;
}
void NegateNode::streamTo(SourceStream &s) const
{
s << "- " << expr;
}
void BitwiseNotNode::streamTo(SourceStream &s) const
{
s << "~" << expr;
}
void LogicalNotNode::streamTo(SourceStream &s) const
{
s << "!" << expr;
}
void MultNode::streamTo(SourceStream &s) const
{
s << term1 << " " << oper << " " << term2;
}
void AddNode::streamTo(SourceStream &s) const
{
s << term1 << " " << oper << " " << term2;
}
void ShiftNode::streamTo(SourceStream &s) const
{
s << term1;
if (oper == OpLShift)
s << "<<";
else if (oper == OpRShift)
s << ">>";
else
s << ">>>";
s << term2;
}
void RelationalNode::streamTo(SourceStream &s) const
{
s << expr1;
switch (oper) {
case OpLess:
s << " < ";
break;
case OpGreater:
s << " > ";
break;
case OpLessEq:
s << " <= ";
break;
case OpGreaterEq:
s << " >= ";
break;
case OpInstanceOf:
s << " instanceof ";
break;
case OpIn:
s << " in ";
break;
default:
;
}
s << expr2;
}
void EqualNode::streamTo(SourceStream &s) const
{
s << expr1;
switch (oper) {
case OpEqEq:
s << " == ";
break;
case OpNotEq:
s << " != ";
break;
case OpStrEq:
s << " === ";
break;
case OpStrNEq:
s << " !== ";
break;
default:
;
}
s << expr2;
}
void BitOperNode::streamTo(SourceStream &s) const
{
s << expr1;
if (oper == OpBitAnd)
s << " & ";
else if (oper == OpBitXOr)
s << " ^ ";
else
s << " | ";
s << expr2;
}
void BinaryLogicalNode::streamTo(SourceStream &s) const
{
s << expr1 << (oper == OpAnd ? " && " : " || ") << expr2;
}
void ConditionalNode::streamTo(SourceStream &s) const
{
s << logical << " ? " << expr1 << " : " << expr2;
}
static void streamAssignmentOperatorTo(SourceStream &s, Operator oper)
{
const char *opStr;
switch (oper) {
case OpEqual:
opStr = " = ";
break;
case OpMultEq:
opStr = " *= ";
break;
case OpDivEq:
opStr = " /= ";
break;
case OpPlusEq:
opStr = " += ";
break;
case OpMinusEq:
opStr = " -= ";
break;
case OpLShift:
opStr = " <<= ";
break;
case OpRShift:
opStr = " >>= ";
break;
case OpURShift:
opStr = " >>>= ";
break;
case OpAndEq:
opStr = " &= ";
break;
case OpXOrEq:
opStr = " ^= ";
break;
case OpOrEq:
opStr = " |= ";
break;
case OpModEq:
opStr = " %= ";
break;
default:
opStr = " ?= ";
}
s << opStr;
}
void AssignResolveNode::streamTo(SourceStream &s) const
{
s << m_ident;
streamAssignmentOperatorTo(s, m_oper);
s << m_right;
}
void AssignBracketNode::streamTo(SourceStream &s) const
{
s << m_base << "[" << m_subscript << "]";
streamAssignmentOperatorTo(s, m_oper);
s << m_right;
}
void AssignDotNode::streamTo(SourceStream &s) const
{
s << SourceStream::DotExpr << m_base << "." << m_ident;
streamAssignmentOperatorTo(s, m_oper);
s << m_right;
}
void AssignErrorNode::streamTo(SourceStream& s) const
{
s << m_left;
streamAssignmentOperatorTo(s, m_oper);
s << m_right;
}
void CommaNode::streamTo(SourceStream &s) const
{
s << expr1 << ", " << expr2;
}
void AssignExprNode::streamTo(SourceStream &s) const
{
s << " = " << expr;
}
void VarDeclNode::streamTo(SourceStream &s) const
{
s << ident << init;
}
void VarDeclListNode::streamTo(SourceStream &s) const
{
s << "var " << var;
for (VarDeclListNode *n = next.get(); n; n = n->next.get())
s << ", " << n->var;
}
void VarStatementNode::streamTo(SourceStream &s) const
{
s << SourceStream::Endl << next << ";";
}
void BlockNode::streamTo(SourceStream &s) const
{
s << SourceStream::Endl << "{" << SourceStream::Indent
<< source << SourceStream::Unindent << SourceStream::Endl << "}";
}
void EmptyStatementNode::streamTo(SourceStream &s) const
{
s << SourceStream::Endl << ";";
}
void ExprStatementNode::streamTo(SourceStream &s) const
{
s << SourceStream::Endl << expr << ";";
}
void IfNode::streamTo(SourceStream &s) const
{
s << SourceStream::Endl << "if (" << expr << ")" << SourceStream::Indent
<< statement1 << SourceStream::Unindent;
if (statement2)
s << SourceStream::Endl << "else" << SourceStream::Indent
<< statement2 << SourceStream::Unindent;
}
void DoWhileNode::streamTo(SourceStream &s) const
{
s << SourceStream::Endl << "do " << SourceStream::Indent
<< statement << SourceStream::Unindent << SourceStream::Endl
<< "while (" << expr << ");";
}
void WhileNode::streamTo(SourceStream &s) const
{
s << SourceStream::Endl << "while (" << expr << ")" << SourceStream::Indent
<< statement << SourceStream::Unindent;
}
void ForNode::streamTo(SourceStream &s) const
{
s << SourceStream::Endl << "for ("
<< expr1
<< "; " << expr2
<< "; " << expr3
<< ")" << SourceStream::Indent << statement << SourceStream::Unindent;
}
void ForInNode::streamTo(SourceStream &s) const
{
s << SourceStream::Endl << "for (";
if (varDecl)
s << "var " << varDecl;
else
s << lexpr;
s << " in " << expr << ")" << SourceStream::Indent
<< statement << SourceStream::Unindent;
}
void ContinueNode::streamTo(SourceStream &s) const
{
s << SourceStream::Endl << "continue";
if (!ident.isNull())
s << " " << ident;
s << ";";
}
void BreakNode::streamTo(SourceStream &s) const
{
s << SourceStream::Endl << "break";
if (!ident.isNull())
s << " " << ident;
s << ";";
}
void ReturnNode::streamTo(SourceStream &s) const
{
s << SourceStream::Endl << "return";
if (value)
s << " " << value;
s << ";";
}
void WithNode::streamTo(SourceStream &s) const
{
s << SourceStream::Endl << "with (" << expr << ") "
<< statement;
}
void CaseClauseNode::streamTo(SourceStream &s) const
{
s << SourceStream::Endl;
if (expr)
s << "case " << expr;
else
s << "default";
s << ":" << SourceStream::Indent;
if (source)
s << source;
s << SourceStream::Unindent;
}
void ClauseListNode::streamTo(SourceStream &s) const
{
for (const ClauseListNode *n = this; n; n = n->getNext())
s << n->getClause();
}
void CaseBlockNode::streamTo(SourceStream &s) const
{
for (const ClauseListNode *n = list1.get(); n; n = n->getNext())
s << n->getClause();
if (def)
s << def;
for (const ClauseListNode *n = list2.get(); n; n = n->getNext())
s << n->getClause();
}
void SwitchNode::streamTo(SourceStream &s) const
{
s << SourceStream::Endl << "switch (" << expr << ") {"
<< SourceStream::Indent << block << SourceStream::Unindent
<< SourceStream::Endl << "}";
}
void LabelNode::streamTo(SourceStream &s) const
{
s << SourceStream::Endl << label << ":" << SourceStream::Indent
<< statement << SourceStream::Unindent;
}
void ThrowNode::streamTo(SourceStream &s) const
{
s << SourceStream::Endl << "throw " << expr << ";";
}
void TryNode::streamTo(SourceStream &s) const
{
s << SourceStream::Endl << "try " << tryBlock;
if (catchBlock)
s << SourceStream::Endl << "catch (" << exceptionIdent << ")" << catchBlock;
if (finallyBlock)
s << SourceStream::Endl << "finally " << finallyBlock;
}
void ParameterNode::streamTo(SourceStream &s) const
{
s << id;
for (ParameterNode *n = next.get(); n; n = n->next.get())
s << ", " << n->id;
}
void FuncDeclNode::streamTo(SourceStream &s) const
{
s << SourceStream::Endl << "function " << ident << "(" << param << ")" << body;
}
void FuncExprNode::streamTo(SourceStream &s) const
{
s << "function " << ident << "(" << param << ")" << body;
}
void SourceElementsNode::streamTo(SourceStream &s) const
{
for (const SourceElementsNode *n = this; n; n = n->next.get())
s << n->node;
}