/* * This file is part of the KDE libraries * Copyright (C) 2002 Harri Porten (porten@kde.org) * Copyright (C) 2003 Apple Computer, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. * */ #include "nodes.h" namespace KJS { /** * A simple text streaming class that helps with code indentation. */ class SourceStream { public: enum Format { Endl, Indent, Unindent }; UString toString() const { return str; } SourceStream& operator<<(const Identifier &); SourceStream& operator<<(const KJS::UString &); SourceStream& operator<<(const char *); SourceStream& operator<<(char); SourceStream& operator<<(Format f); SourceStream& operator<<(const Node *); private: UString str; /* TODO: buffer */ UString ind; }; } using namespace KJS; SourceStream& SourceStream::operator<<(char c) { str += UString(c); return *this; } SourceStream& SourceStream::operator<<(const char *s) { str += UString(s); return *this; } SourceStream& SourceStream::operator<<(const UString &s) { str += s; return *this; } SourceStream& SourceStream::operator<<(const Identifier &s) { str += s.ustring(); return *this; } SourceStream& SourceStream::operator<<(const Node *n) { if (n) n->streamTo(*this); return *this; } SourceStream& SourceStream::operator<<(Format f) { switch (f) { case Endl: str += "\n" + ind; break; case Indent: ind += " "; break; case Unindent: ind = ind.substr(0, ind.size() - 2); break; } return *this; } UString unescapeStr(UString str) { UString unescaped = ""; int i = 0; int copied = 0; for (i = 0; i <= str.size(); i++) { if (str[i] == '"') { if (copied < i) unescaped += str.substr(copied,i-copied); copied = i+1; unescaped += "\\\""; } } if (copied < i) unescaped += str.substr(copied,i-copied); return unescaped; } UString Node::toCode() const { SourceStream str; streamTo(str); return str.toString(); } void NullNode::streamTo(SourceStream &s) const { s << "null"; } void BooleanNode::streamTo(SourceStream &s) const { s << (val ? "true" : "false"); } void NumberNode::streamTo(SourceStream &s) const { s << UString::from(val); } void StringNode::streamTo(SourceStream &s) const { s << '"' << unescapeStr(val) << '"'; } 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->list) { for (int i = 0; i < n->elision; i++) s << ","; s << n->node; if ( n->list ) s << ","; } } void ArrayNode::streamTo(SourceStream &s) const { s << "[" << element; for (int i = 0; i < elision; i++) s << ","; s << "]"; } void ObjectLiteralNode::streamTo(SourceStream &s) const { if (list) s << "{ " << list << " }"; else s << "{ }"; } void PropertyValueNode::streamTo(SourceStream &s) const { for (const PropertyValueNode *n = this; n; n = n->list) s << n->name << ": " << n->assign; } void PropertyNode::streamTo(SourceStream &s) const { if (str.isNull()) s << UString::from(numeric); else s << str; } void AccessorNode1::streamTo(SourceStream &s) const { s << expr1 << "[" << expr2 << "]"; } void AccessorNode2::streamTo(SourceStream &s) const { s << expr << "." << ident; } void ArgumentListNode::streamTo(SourceStream &s) const { s << expr; for (ArgumentListNode *n = list; n; n = n->list) s << ", " << n->expr; } void ArgumentsNode::streamTo(SourceStream &s) const { s << "(" << list << ")"; } void NewExprNode::streamTo(SourceStream &s) const { s << "new " << expr << args; } void FunctionCallNode::streamTo(SourceStream &s) const { s << expr << args; } void PostfixNode::streamTo(SourceStream &s) const { s << expr; if (oper == OpPlusPlus) s << "++"; else s << "--"; } void DeleteNode::streamTo(SourceStream &s) const { s << "delete " << expr; } void VoidNode::streamTo(SourceStream &s) const { s << "void " << expr; } void TypeOfNode::streamTo(SourceStream &s) const { s << "typeof " << expr; } void PrefixNode::streamTo(SourceStream &s) const { s << (oper == OpPlusPlus ? "++" : "--") << 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 AppendStringNode::streamTo(SourceStream &s) const { s << term << "+" << '"' << unescapeStr(str) << '"'; } 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; } void AssignNode::streamTo(SourceStream &s) const { s << left; 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 << expr; } void CommaNode::streamTo(SourceStream &s) const { s << expr1 << ", " << expr2; } void StatListNode::streamTo(SourceStream &s) const { for (const StatListNode *n = this; n; n = n->list) s << n->statement; } 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; for (VarDeclListNode *n = list; n; n = n->list) s << ", " << n->var; } void VarStatementNode::streamTo(SourceStream &s) const { s << SourceStream::Endl << "var " << list << ";"; } 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 // TODO: doesn't properly do "var i = 0" << "; " << expr2 << "; " << expr3 << ")" << SourceStream::Indent << statement << SourceStream::Unindent; } void ForInNode::streamTo(SourceStream &s) const { s << SourceStream::Endl << "for ("; if (varDecl) s << "var " << varDecl; if (init) s << " = " << init; 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 (list) s << list; s << SourceStream::Unindent; } void ClauseListNode::streamTo(SourceStream &s) const { for (const ClauseListNode *n = this; n; n = n->next()) s << n->clause(); } void CaseBlockNode::streamTo(SourceStream &s) const { for (const ClauseListNode *n = list1; n; n = n->next()) s << n->clause(); if (def) s << def; for (const ClauseListNode *n = list2; n; n = n->next()) s << n->clause(); } 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 CatchNode::streamTo(SourceStream &s) const { s << SourceStream::Endl << "catch (" << ident << ")" << block; } void FinallyNode::streamTo(SourceStream &s) const { s << SourceStream::Endl << "finally " << block; } void TryNode::streamTo(SourceStream &s) const { s << SourceStream::Endl << "try " << block << _catch << _final; } void ParameterNode::streamTo(SourceStream &s) const { s << id; for (ParameterNode *n = next; n; n = n->next) s << ", " << n->id; } void FuncDeclNode::streamTo(SourceStream &s) const { s << SourceStream::Endl << "function " << ident << "("; if (param) s << param; s << ")" << body; } void FuncExprNode::streamTo(SourceStream &s) const { s << "function " << "(" << param << ")" << body; } void SourceElementsNode::streamTo(SourceStream &s) const { for (const SourceElementsNode *n = this; n; n = n->elements) s << n->element; }