blob: 5383932b50bd5dc770bc31fd0fbac761c32ceaf2 [file] [log] [blame]
/*
* This file is part of the KDE libraries
* Copyright (C) 2003, 2008 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.
*
*/
#ifndef ScopeChain_h
#define ScopeChain_h
#include <wtf/Assertions.h>
namespace KJS {
class JSGlobalObject;
class JSObject;
class ScopeChainIterator;
class ScopeChainNode {
public:
ScopeChainNode(ScopeChainNode* n, JSObject* o)
: next(n)
, object(o)
, refCount(1)
{
}
ScopeChainNode* next;
JSObject* object;
int refCount;
void deref() { if (--refCount == 0) release(); }
void ref() { ++refCount; }
void release();
// Before calling "push" on a bare ScopeChainNode, a client should
// logically "copy" the node. Later, the client can "deref" the head
// of its chain of ScopeChainNodes to reclaim all the nodes it added
// after the logical copy, leaving nodes added before the logical copy
// (nodes shared with other clients) untouched.
ScopeChainNode* copy()
{
ref();
return this;
}
JSObject* bottom() const;
ScopeChainNode* push(JSObject*);
ScopeChainNode* pop();
ScopeChainIterator begin() const;
ScopeChainIterator end() const;
JSGlobalObject* globalObject() const; // defined in JSGlobalObject.h
#ifndef NDEBUG
void print() const;
#endif
};
inline ScopeChainNode* ScopeChainNode::push(JSObject* o)
{
ASSERT(o);
return new ScopeChainNode(this, o);
}
inline ScopeChainNode* ScopeChainNode::pop()
{
ASSERT(next);
ScopeChainNode* result = next;
if (--refCount != 0)
++result->refCount;
else
delete this;
return result;
}
inline JSObject* ScopeChainNode::bottom() const
{
const ScopeChainNode* n = this;
while (n->next)
n = n->next;
return n->object;
}
inline void ScopeChainNode::release()
{
// This function is only called by deref(),
// Deref ensures these conditions are true.
ASSERT(refCount == 0);
ScopeChainNode* n = this;
do {
ScopeChainNode* next = n->next;
delete n;
n = next;
} while (n && --n->refCount == 0);
}
class ScopeChainIterator {
public:
ScopeChainIterator(const ScopeChainNode* node) : m_node(node) {}
JSObject* const & operator*() const { return m_node->object; }
JSObject* const * operator->() const { return &(operator*()); }
ScopeChainIterator& operator++() { m_node = m_node->next; return *this; }
// postfix ++ intentionally omitted
bool operator==(const ScopeChainIterator& other) const { return m_node == other.m_node; }
bool operator!=(const ScopeChainIterator& other) const { return m_node != other.m_node; }
private:
const ScopeChainNode* m_node;
};
inline ScopeChainIterator ScopeChainNode::begin() const
{
return ScopeChainIterator(this);
}
inline ScopeChainIterator ScopeChainNode::end() const
{
return ScopeChainIterator(0);
}
class ScopeChain {
public:
ScopeChain(JSObject* o)
: _node(new ScopeChainNode(0, o))
{
}
ScopeChain(const ScopeChain& c)
: _node(c._node->copy())
{
}
ScopeChain& operator=(const ScopeChain& c);
explicit ScopeChain(ScopeChainNode* node)
: _node(node->copy())
{
}
~ScopeChain() { _node->deref(); }
void swap(ScopeChain&);
ScopeChainNode* node() const { return _node; }
JSObject* top() const { return _node->object; }
JSObject* bottom() const { return _node->bottom(); }
ScopeChainIterator begin() const { return _node->begin(); }
ScopeChainIterator end() const { return _node->end(); }
void push(JSObject* o) { _node = _node->push(o); }
void pop() { _node = _node->pop(); }
void clear() { _node->deref(); _node = 0; }
JSGlobalObject* globalObject() const { return _node->globalObject(); }
void mark() const;
#ifndef NDEBUG
void print() const { _node->print(); }
#endif
private:
ScopeChainNode* _node;
};
inline void ScopeChain::swap(ScopeChain& o)
{
ScopeChainNode* tmp = _node;
_node = o._node;
o._node = tmp;
}
inline ScopeChain& ScopeChain::operator=(const ScopeChain& c)
{
ScopeChain tmp(c);
swap(tmp);
return *this;
}
} // namespace KJS
#endif // ScopeChain_h