/*
 * This file is part of tela the Tensor Language.
 * Copyright (c) 1994-2001 Pekka Janhunen
 */

#ifdef __GNUC__
#  pragma interface
#endif
#include "symbol.H"
#include "common.H"

enum TNodeKind {Kconstant,Kvariable,Kbuiltin,Kslot,Kcolon};

enum Tfunc {
	FPLUS,FDIFFERENCE,FMINUS,
	FTIMES,FQUOTIENT,FPOWER,FMOD,
	FEQ,FNE,FGT,FLT,FGE,FLE,
	FAND,F_OR,FNOT,
	FRANGE,
	FREF,FMREF,FCALL,FLIST,
	FSET,FBLOCK,FDEFUN,FPACKAGE,FLOCAL,FGLOBAL,FFORMAL,FFORMAL_ELLIPSIS,FGOTO,FLABEL,
	FDISP,
	FIF,FWHILE,FREPEAT,FFOR,FCONTINUE,FBREAK,FRETURN,
	FARRAY,FEMPTY_ARRAY,FAPP,
	FHARDNOP,FNOP
};

extern const Tchar *FuncData[];

class Tnode {
 public:
	Tnode *next;		// pointer to next node, or 0
	Tnode *list;		// pointer to sublist node, or 0
	TNodeKind kind;		// node kind
 private:
	union {void *ptr; Tfunc func; TPtrInt s;};	// ptr is Tobject* if k==Kconstant, and Tsymbol* if k==Kvariable
	int lineno;			// source code line number when this node was generated by the parser
 public:
	Tnode() : next(0), list(0), kind(Kbuiltin), func(FLIST), lineno(global::lineno) {}
	Tnode(Tnode*down, Tobject* objptr, Tnode*right) : next(right), list(down), kind(Kconstant), ptr(objptr), lineno(global::lineno) {}
	Tnode(Tnode*down, Tsymbol* symptr, Tnode*right) : next(right), list(down), kind(Kvariable), ptr(symptr), lineno(global::lineno) {}
	Tnode(Tnode*down, Tfunc f,         Tnode*right) : next(right), list(down), kind(Kbuiltin), func(f), lineno(global::lineno) {}
	Tnode(Tnode*down, Tslot s1,        Tnode*right) : next(right), list(down), kind(Kslot), s(s1), lineno(global::lineno) {}
	Tnode(Tnode*down, Tallrange a,     Tnode*right) : next(right), list(down), kind(Kcolon), lineno(global::lineno) {}
	Tnode(const Tnode& node) : next(node.next), list(node.list), kind(node.kind), ptr(node.ptr), lineno(node.lineno) {}
	// --- assignments
	Tnode& operator=(const Tnode& node)
		{next=node.next; list=node.list; kind=node.kind; ptr=node.ptr; lineno=node.lineno; return *this;}
	Tnode& operator=(Tobject& obj) {kind=Kconstant; ptr=&obj; lineno=global::lineno; return *this;}
	Tnode& operator=(Tsymbol& sym) {kind=Kvariable; ptr=&sym; lineno=global::lineno; return *this;}
	Tnode& operator=(Tfunc f) {kind=Kbuiltin; func=f; lineno=global::lineno; return *this;}
	Tnode& operator=(Tslot s1) {kind=Kslot; s=s1; lineno=global::lineno; return *this;}
	// --- inquiry functions
	Tobject& ObjectValue() const {return *(Tobject*)ptr;}
	Tsymbol& SymbolValue() const {return *(Tsymbol*)ptr;}
	Tfunc FunctionValue()  const {return func;}
	Tslot SlotValue() const {return s;}
	TPtrInt GeneralValue() const {return s;}
	int LineNumber() const {return lineno;}
	// --- dynamic allocation
	void* operator new(size_t sz);
	void operator delete(void*) {}	// delete does nothing since mark/release approach is used
	~Tnode() {kind=Kbuiltin;}
};

ostream& operator<<(ostream& o, const Tnode& node);

//Tnode* readtree(istream& i);
//inline istream& operator>>(istream& i, Tnode& node) {Tnode*ptr=readtree(i); node=*ptr; return i;}

struct TNodeBlock {
	enum {SIZE=203/*1024*/};
	TNodeBlock *next;
	TNodeBlock *prev;
	int length;
	Tnode pool[SIZE];
	TNodeBlock() : next(0), prev(0), length(0) {}
};

class TNodePoolState {
 private:
	TNodeBlock* ptr;
	int len;

        //-- TNodePoolState(const TNodePoolState&); // FIXME: using default implementation - cls
        TNodePoolState& operator=(const TNodePoolState&); // do not implement
 public:
	TNodePoolState(TNodeBlock* blockptr) : ptr(blockptr), len(blockptr->length) {}
	TNodePoolState(TNodeBlock* blockptr, int length) : ptr(blockptr), len(length) {}
	TNodeBlock* Ptr() {return ptr;}
	int Len() const {return len;}
};

struct TObjectListNode {
	TObjectPtr op;
	TObjectListNode *nextobj;
};

class TNodePool {
 private:
	TNodeBlock *first;
	TNodeBlock *last;
	int nblocks;
	void AddDeletedObjectsInList(TNodeBlock*p, int start, int stop, TObjectListNode *&objlist);

        TNodePool(const TNodePool&); // do not implement
        TNodePool& operator=(const TNodePool&); // do not implement
 public:
	TNodePool() : first(new TNodeBlock), last(first), nblocks(1) {}
	TNodeBlock& First() const {return *first;}
	TNodeBlock& Last() const {return *last;}
	void SetLast(TNodeBlock*p) {last=p;}
	TNodePoolState mark() {return TNodePoolState(last);}
	void release(TNodePoolState& s);
	int NodesInUse();
	friend class Tnode;
	~TNodePool() {TNodePoolState s(first,0); release(s);}
};

extern TNodePool theNodePool;
