You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
629 lines
12 KiB
629 lines
12 KiB
/*
|
|
* 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;
|
|
}
|
|
|