forked from KolibriOS/kolibrios
235 lines
7.3 KiB
C
235 lines
7.3 KiB
C
|
/** \file lispobject.h
|
||
|
* Implementation of basic LispObject, which is the base class for
|
||
|
* anything that can be put in a linked list.
|
||
|
*
|
||
|
* class LispObject. This class implements one lisp object, which is a
|
||
|
* abstract class containing reference counting and a next pointer.
|
||
|
* derive from this to implement specific types of list elements.
|
||
|
* The local class LispPtr implements automatic garbage collection
|
||
|
* through reference counting.
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
#ifndef __lispobject_h__
|
||
|
#define __lispobject_h__
|
||
|
|
||
|
#include "yacasbase.h"
|
||
|
#include "refcount.h"
|
||
|
#include "lispstring.h"
|
||
|
#include "genericobject.h"
|
||
|
|
||
|
#ifdef YACAS_DEBUG
|
||
|
#define DBG_(xxx) xxx
|
||
|
#else
|
||
|
#define DBG_(xxx) /*xxx*/
|
||
|
#endif
|
||
|
|
||
|
class LispObject;
|
||
|
class BigNumber;
|
||
|
|
||
|
|
||
|
/** class LispPtr. A LispPtr is a smart pointer to a LispObject.
|
||
|
* It does the reference counting, and consequent destruction if needed.
|
||
|
* LispPtr is used in LispObject as a pointer to the next object; and
|
||
|
* LispPtr::GoNext() advances one step in this LispObject::Nixed() chain.
|
||
|
* Diverse built-in functions use LispPtr to hold temporary values.
|
||
|
*/
|
||
|
typedef RefPtr<LispObject> LispPtr;
|
||
|
|
||
|
/** \class LispPtrArray is similar to LispPtr, but implements an array
|
||
|
* of pointers to objects.
|
||
|
*/
|
||
|
typedef CArrayGrower<LispPtr, ArrOpsCustomObj<LispPtr> > LispPtrArray;
|
||
|
|
||
|
|
||
|
#ifdef YACAS_DEBUG
|
||
|
void IncNrObjects();
|
||
|
void DecNrObjects();
|
||
|
#else
|
||
|
#define IncNrObjects()
|
||
|
#define DecNrObjects()
|
||
|
#endif
|
||
|
|
||
|
// Should we DecNrObjects by the delete, or in the destructor?
|
||
|
// Put a DecNrObjects_xxx() macro in both places, and CHOOSE here.
|
||
|
#define DecNrObjects_delete() DECNROBJECTS_CHOOSE(DecNrObjects(),)
|
||
|
#define DecNrObjects_destructor() DECNROBJECTS_CHOOSE(,DecNrObjects())
|
||
|
#define DECNROBJECTS_CHOOSE(bydelete,bydestructor) bydestructor
|
||
|
|
||
|
|
||
|
template <int> struct Undefined;
|
||
|
template <> struct Undefined<1>{};
|
||
|
|
||
|
|
||
|
/** class LispObject is the base object class that can be put in
|
||
|
* linked lists. It either has a pointer to a string, obtained through
|
||
|
* String(), or it is a holder for a sublist, obtainable through SubList(),
|
||
|
* or it is a generic object, in which case Generic() returns non-NULL.
|
||
|
* Only one of these three functions should return a non-NULL value.
|
||
|
* It is a reference-counted object. LispPtr handles the reference counting.
|
||
|
*/
|
||
|
class LispObject : public YacasBase
|
||
|
{
|
||
|
public:
|
||
|
inline LispPtr& Nixed();
|
||
|
|
||
|
public: //Derivables
|
||
|
virtual ~LispObject();
|
||
|
|
||
|
/** Return string representation, or NULL if the object doesn't have one.
|
||
|
* the string representation is only relevant if the object is a
|
||
|
* simple atom. This method returns NULL by default.
|
||
|
*/
|
||
|
virtual LispString * String() { return NULL; }
|
||
|
/** If this object is a list, return a pointer to it.
|
||
|
* Default behaviour is to return NULL.
|
||
|
*/
|
||
|
virtual LispPtr* SubList() { return NULL; }
|
||
|
virtual GenericClass* Generic() { return NULL; }
|
||
|
|
||
|
/** If this is a number, return a BigNumber representation
|
||
|
*/
|
||
|
virtual BigNumber* Number(LispInt aPrecision) { return NULL; }
|
||
|
|
||
|
virtual LispObject* Copy() = 0;
|
||
|
|
||
|
/** Return a pointer to extra info. This allows for annotating
|
||
|
* an object. Returns NULL by default.
|
||
|
* LispObject's implementation of this handles almost all derived classes.
|
||
|
*/
|
||
|
virtual LispObject* ExtraInfo() { return NULL; }
|
||
|
virtual LispObject* SetExtraInfo(LispObject* aData) = 0;
|
||
|
public:
|
||
|
LispInt Equal(LispObject& aOther);
|
||
|
inline LispInt operator==(LispObject& aOther);
|
||
|
inline LispInt operator!=(LispObject& aOther);
|
||
|
DBG_( LispChar * iFileName; )
|
||
|
DBG_( LispInt iLine; )
|
||
|
inline void SetFileAndLine(LispChar * aFileName, LispInt aLine)
|
||
|
{
|
||
|
DBG_( iFileName = aFileName; )
|
||
|
DBG_( iLine = aLine; )
|
||
|
}
|
||
|
protected:
|
||
|
inline LispObject() :
|
||
|
#ifdef YACAS_DEBUG
|
||
|
iFileName(NULL),iLine(0),
|
||
|
#endif // YACAS_DEBUG
|
||
|
iNext(),iReferenceCount()
|
||
|
{
|
||
|
IncNrObjects();
|
||
|
DBG_( iFileName = NULL; )
|
||
|
DBG_( iLine = 0; )
|
||
|
}
|
||
|
inline LispObject(const LispObject& other) :
|
||
|
#ifdef YACAS_DEBUG
|
||
|
iFileName(other.iFileName),iLine(other.iLine),
|
||
|
#endif // YACAS_DEBUG
|
||
|
iNext(),iReferenceCount()
|
||
|
{
|
||
|
IncNrObjects();
|
||
|
}
|
||
|
|
||
|
inline LispObject& operator=(const LispObject& other)
|
||
|
{
|
||
|
#ifdef YACAS_DEBUG
|
||
|
iFileName = other.iFileName;
|
||
|
iLine = other.iLine;
|
||
|
#endif // YACAS_DEBUG
|
||
|
IncNrObjects();
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
|
||
|
private:
|
||
|
LispPtr iNext;
|
||
|
public:
|
||
|
ReferenceCount iReferenceCount;
|
||
|
};
|
||
|
|
||
|
|
||
|
template <class T>
|
||
|
class WithExtraInfo : public T
|
||
|
{
|
||
|
public:
|
||
|
WithExtraInfo(T& aT, LispObject* aData = 0) : T(aT), iExtraInfo(aData) {}
|
||
|
WithExtraInfo(const WithExtraInfo& other) : T(other), iExtraInfo(other.iExtraInfo) {}
|
||
|
virtual LispObject* ExtraInfo() { return iExtraInfo; }
|
||
|
virtual LispObject* SetExtraInfo(LispObject* aData) { iExtraInfo = aData; return this; }
|
||
|
virtual LispObject* Copy()
|
||
|
{
|
||
|
if (!iExtraInfo.ptr()) return T::Copy();
|
||
|
return NEW WithExtraInfo(*this, iExtraInfo->Copy());
|
||
|
}
|
||
|
private:
|
||
|
LispPtr iExtraInfo;
|
||
|
};
|
||
|
|
||
|
|
||
|
template <class T, class U = LispObject>
|
||
|
class ObjectHelper : public U
|
||
|
{
|
||
|
protected:
|
||
|
typedef ObjectHelper ASuper; // for use by the derived class
|
||
|
ObjectHelper() {}
|
||
|
ObjectHelper(const ObjectHelper& other) : U(other) {}
|
||
|
virtual ~ObjectHelper() = 0; // so we're abstract
|
||
|
virtual LispObject* SetExtraInfo(LispObject* aData)
|
||
|
{
|
||
|
if (!aData) return this;
|
||
|
//T * pT = dynamic_cast<T*>(this); LISPASSERT(pT);
|
||
|
LispObject * pObject = NEW WithExtraInfo<T>(*static_cast<T*>(this), aData);
|
||
|
return pObject;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
template <typename T, class U>
|
||
|
inline ObjectHelper<T,U>::~ObjectHelper() {}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* class LispIterator works almost like LispPtr, but doesn't enforce
|
||
|
* reference counting, so it should be faster. Use LispIterator
|
||
|
* (instead of LispPtr) to traverse a lisp expression non-destructively.
|
||
|
*/
|
||
|
class LispIterator : public YacasBase
|
||
|
{
|
||
|
public:
|
||
|
// ala TEMPLATE CLASS iterator
|
||
|
//typedef forward_iterator_tag iterator_category;
|
||
|
typedef LispPtr value_type;
|
||
|
typedef int /*ptrdiff_t*/ difference_type;
|
||
|
typedef LispPtr* pointer;
|
||
|
typedef LispPtr& reference;
|
||
|
public:
|
||
|
LispIterator() : _Ptr(0) {} // construct with null node pointer
|
||
|
LispIterator(pointer ptr) : _Ptr(ptr) {} // construct with node pointer
|
||
|
/*non-standard*/ LispIterator(reference ref) : _Ptr(&ref) {} // construct with node reference
|
||
|
reference operator*() const { return (*(_Ptr)); } // return designated value
|
||
|
pointer operator->() const { return (_Ptr); } // return pointer to class object
|
||
|
inline LispIterator& operator++() // preincrement
|
||
|
{
|
||
|
//precondition: _Ptr != NULL
|
||
|
LISPASSERT(_Ptr != NULL);
|
||
|
//expand: _Ptr = _Nextnode(_Ptr);
|
||
|
LispObject * pObj = _Ptr->operator->();
|
||
|
_Ptr = pObj ? &(pObj->Nixed()) : NULL;
|
||
|
return (*this);
|
||
|
}
|
||
|
LispIterator operator++(int) { LispIterator _Tmp = *this; ++*this; return (_Tmp); } // postincrement
|
||
|
bool operator==(const LispIterator& other) const { return (_Ptr == other._Ptr); } // test for iterator equality
|
||
|
bool operator!=(const LispIterator& other) const { return (!(*this == other)); } // test for iterator inequality
|
||
|
// The following operators are not used yet, and would need to be tested before used.
|
||
|
//LispIterator& operator--() { _Ptr = _Prevnode(_Ptr); return (*this); } // predecrement
|
||
|
//LispIterator operator--(int) { LispIterator _Tmp = *this; --*this; return (_Tmp); } // postdecrement
|
||
|
protected:
|
||
|
pointer _Ptr; // pointer to node
|
||
|
public:
|
||
|
inline LispObject* getObj() const { return (*_Ptr).operator->(); }
|
||
|
};
|
||
|
|
||
|
#include "lispobject.inl"
|
||
|
|
||
|
|
||
|
#endif
|