/* This is -*- C++ -*-.
   Copyright (C) 1992 Per Bothner.

This file is part of Q.

Q is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.

Q 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 General Public License for more details.

You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING.  If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */

#ifndef TYPES_H
/*#pragma once*/
#pragma interface
#define TYPES_H
#include "config.h"
#include "sys-params.h"
#define USE_RX
#ifdef DIGITon16BITS
typedef short fix_int;
typedef unsigned short fix_unsigned;
#else
typedef int fix_int;
typedef unsigned int fix_unsigned;
#endif
#define length_t size_t
typedef long index_t; /* Sequence index. Start at 0.
  Negative indexes count from the end, where -1 is end and -2 is last element.*/

#if (defined(__GNUG__) || defined(__GNUC__)) && !defined(alloca)
#define alloca(x) __builtin_alloca(x)
#endif
#define MAX_SIGNED 0x7FFFFFFF

#define DO_GC
#ifdef __cplusplus
#ifdef DO_GC
extern "C" {
#include "../gc/gc.h"
}
extern void * operator new(size_t, int);
#undef GC_NEW
#define GC_NEW new
#else
#define GC_NEW new
#define GC_malloc_atomic(size) malloc(size)
#define GC_malloc(size) malloc(size)
#define GC_realloc(ptr, size) realloc(ptr, size)
#endif
#endif /* __cplusplus */

typedef void *Object;
typedef int bool;
#ifdef __cplusplus
class ostream;
class Root;
typedef Root *RootPtr;
class Expression;
typedef Expression Expr;
#else
typedef Object RootPtr;
typedef struct CFile CFile;
#endif 
typedef RootPtr (*Func)();

#define INTERN_FIELD_NAMES
#ifdef __cplusplus
class Symbol; class Package;
extern Symbol * EnterSymbol(char *, int = -1);
class Name {
#ifdef INTERN_FIELD_NAMES
  public:
    const Symbol *_name;
    inline Name() { }
    Name(const Symbol *symbol) { _name = symbol; }
    Name(char *string, int len = -1) { _name = EnterSymbol(string, len); }
    inline char *string() const;
    inline const Symbol * symbol() const {return _name;}
    inline long length() const;
    int operator==(Name other) { return _name == other._name; }
    const Symbol * operator->() const { return _name; }
    operator const Symbol *() const { return _name; }
    operator const int() const { return (int)_name; }
#else /* !INTERN_FIELD_NAMES */
    const char *_name;
  public:
    inline Name() { }
    Name(const char *string) { _name = string; }
    inline char *string() const { return _name; }
    inline long& length() { return strlen(_name); }
    int operator==(Name other) { return strcmp(_name, other._name) == 0; }
#endif /* !INTERN_FIELD_NAMES */
};
#else /* !__cplusplus */
typedef struct Symbol Symbol;
#ifdef INTERN_FIELD_NAMES
typedef struct Symbol *Name;
#else /* !INTERN_FIELD_NAMES */
typedef char *Name;
#endif /* !INTERN_FIELD_NAMES */
#endif /* !__cplusplus */

/* special reference counts */
#define RefsOverflow 0
#define RefsInfinity 0

#if 0
/* argument to prefix() methods */
struct ExList {
    struct Expr_Ptr *exList;
    struct DisplayEnv *env;
};
#endif

#ifdef __cplusplus
class Numeric; class LVariable; class Functional; class Assignable;
class CFile; class GenMap; class GenSeq; class StringC;
class Type; class RecordType; class Root; class GenFile;
typedef RecordType Class; class Iterator; class Vector;
#define StringList Vector /* Vector of Strings. */

struct ArgDesc {
    Root ** lArgs;
    Root ** rArgs;
    Root ** nArgs;
    Symbol **names;
    int lCount;
    int rCount;
    int nCount;
    int rLength() { return rCount + 2 * nCount; }
    Root *& keyword(int i) { return rArgs[rCount+i]; }
    inline int empty() { return lCount+rCount+nCount == 0; }
    ArgDesc(Root **lA, Root**rA, Root**nA, Symbol** nm, int lC, int rC, int nC)
	{ lArgs = lA; rArgs = rA; nArgs = nA; names = nm;
	  lCount = lC; rCount = rC; nCount = nC; }
    ArgDesc(const Root **lA, const Root**rA, const Root**nA,
	    Symbol** nm, int lC, int rC, int nC)
	{ lArgs = (Root**)lA; rArgs = (Root**)rA; nArgs = (Root**)nA;
	  names = nm; lCount = lC; rCount = rC; nCount = nC; }
    void copy_to(ArgDesc& copied_args); // make "deep" copy
    ArgDesc() { }
    ArgDesc(ArgDesc& args, int leftUsed, int rightUsed) {
	lArgs = args.lArgs; rArgs = args.rArgs+rightUsed;
	lCount = args.lCount-leftUsed; rCount = args.rCount-rightUsed,
	nArgs = args.nArgs; names = args.names; nCount = args.nCount;
    }
//  ArgDesc(ArgDesc& arg); // make shallow copy
};
class Root {
 public:
    inline static const RecordType * desc();
    //THE isA METHOD MUST BE THE FIRST VIRTUAL (see RecordType::new_subclass)
    virtual const RecordType *isA() const;
    bool isMemberOf(const Class&cl) const { return isA() == &cl; }
    inline bool isKindOf(const Class&cl) const;
    virtual Root *value();
    virtual void update();
    virtual void assign(Root *new_value);
    inline void assign(const Root *new_value) { assign((Root*)new_value); }
// inline const Root *value() const { return (const Root*)((Root*)this)->value(); }
    virtual long magic() const;
    virtual void dumpPtr(CFile *cf) const;
    virtual ~Root() {}
    virtual void printon(ostream&) const;
    friend ostream& operator<<(ostream&, const Root&);
    Root *apply(ArgDesc& args);
    virtual void xapply(void* dst, Type* dstType, ArgDesc&);
    inline Root *apply(Root **lArgs, Root **rArgs, Root **nArgs,
	Symbol **names, int lCount, int rCount, int nCount) const {
	ArgDesc args(lArgs, rArgs, nArgs, names, lCount, rCount, nCount);
	return (Root*)((Root*)this)->apply(args);
    }
    inline const Root *apply(const Root **lArgs, const Root **rArgs,
		       const Root **nArgs, Symbol **names,
		       int lCount, int rCount, int nCount) {
	ArgDesc args(lArgs, rArgs, nArgs, names, lCount, rCount, nCount);
	return (const Root*)((Root*)this)->apply(args);
    }
    virtual struct Type *typedesc() const;
//    virtual struct ClassDesc *classdesc();
    virtual int hash() const; // -1 means unknown or variable
    virtual void unify(Root&);
    virtual int compare(const Root&) const;
    virtual Numeric *numeric();
    inline const Numeric *numeric() const
	{ return (const Numeric*)((Root*)this)->numeric(); }
    virtual Assignable * assignable() const;
    virtual LVariable * lvariable();
    virtual GenMap *mapping();
    virtual GenSeq *sequence() const;
    virtual Functional * functional();
    virtual GenFile *file() { return NULL; }
    virtual const StringC *asString(int format=0) const;
    Root *apply_empty();
    void coerceTo(void * dstAddr, Type *dstType);
#ifdef DO_GC
    void* operator new(size_t s) { return GC_malloc(s); }
#endif
};

#define PTR_CAST(TYPE, val) \
  ((val)->isKindOf(*TYPE::desc()) ? (TYPE*)(val) : (TYPE*)0)
#endif /* __cplusplus */

typedef struct _HandlerDesc_ HandlerDesc;

typedef struct Type * HeapPrefix;
#define __optionField unsigned short options;
#define Options(x) (x).options
#define __Opts_Type(opts, type) (opts), __HeapPrefix(type)

typedef void *ErrVal; /* error or special code */
/*#include "heap.h"*/

#ifndef __cplusplus
struct HashTable;
#else

#endif

/* #define _PCtoSTATLINK ((0x43FA<<16)|(0xFFFF&(-2))) * lea pc@(-2),a1 */

#define WidenCall(filter) NULL, 0, filter

#if 0
ProcType:
    hash - always empty, but points to supertype?

    postfix or prefix: bit
    paramType
    paramName???
#endif

enum TypeKind {
    RecordTypeKind, FunctionTypeKind, ArrayTypeKind, BitsTypeKind,
    ExceptionTypeKind, ReferenceTypeKind, PrimitiveTypeKind, UnionTypeKind,
    TextTypeKind
};

#define BITS_TYPE_SIGNED_OPTION 1
#define BITS_TYPE_MAPPED_OPTION 2
#define BITS_TYPE_OFFSET(t) (t)->prefixLen
#define BITS_TYPE_SIGNED(t) ((t)->options & BITS_TYPE_SIGNED_OPTION)
#define BITS_TYPE_BLENGTH(t) (((t)->inst_size<<3) + (t)->excess_bits)
#define BITS_TYPE_TYPE(t) (t)->surrounding
#define BITS_TYPE_MAPPING(t) ((void**)(t)->prefix)
#define BITS_TYPE_MAPPED(t) ((t)->options & BITS_TYPE_MAPPED_OPTION)
#define BITS_TYPE_ALIGN(t) (t)->alignment

typedef void (*CoerceFunction)(void*dst, const void*src,
 			    const struct Type*dstCl, const struct Type*srcCl);
typedef void (*EmitFunction)(struct Type*, void *addr, CFile *cf);

#if 0
typedef struct Any (*ApplyMethod)();
typedef long (*IntMethod)();
typedef struct Any (*AnyMethod)();

typedef AnyMethod MethodTable;
#define MethodTableSize 12
extern MethodTable DefaultMethodTable[MethodTableSize];
#endif

struct ClassDesc {
    struct Field *fields; /* pointer to array */
    unsigned short *hash; /* hashtab; each element is index in fields */
    short nFields;/* number of named fields */
    short uFields; /* number of unnamed field */
    char nHashLog; /* log2 of length of hashtable */
    char flags;
#if 0
    ApplyMethod dummy_prefix, dummy_postfix; /* no longer used */
    MethodTable *stdMethods;
    ApplyMethod lastfix;
short first; /* index of first field */
#endif
};

/* OBSOLETE? bit for 'options' field of a TypeOb: */
#define SequenceType 1	/* if the type is a TypeSeq */
#define FileType 2	/* if the type is a TypeFil (sequences.h) */
/* #define BitFieldType 3 */
#define TypeIsCompiled 4
#define CFileType 16	/* if a character file */
#define TypeIsScalar 32

#ifdef __cplusplus
extern RecordType Type_classDesc;
struct Type : public Root
{
    unsigned long inst_size; /* length of object in bytes (but see excess_bits) */
    EmitFunction emitFunction;
    inline void emit(void *addr, CFile *cf)
	{ (*emitFunction)(this, addr, cf); }
    Type *surrounding; /* descriptor of surrounding structure */
#else
struct Type
{
    void *__vt__;
    unsigned long inst_size; /* length of object in bytes (but see excess_bits) */
    Func as;	/* obsolete: $self;T$ coerce self to T */
    struct Type *surrounding; /* descriptor of surrounding structure */
#endif
    unsigned short offset; /* offset within surrounding structure */
    short filler; /* was: Func lastfix; */
    enum TypeKind kind : 8;
    unsigned char prefixLen; /* length of prefix (usually sizeof(HeapPrefix))*/
    unsigned alignment : 4; /* log2 of alignment needed (in bits) */
    unsigned excess_bits : 3; /* extra padding in bits that were added to
	round size up to nearest byte (usually 0) */
    unsigned options : 7;
    CoerceFunction _coerceTo;
#ifdef __cplusplus
    inline static const RecordType * desc();
    inline int isFunction() { return kind == FunctionTypeKind; }
    size_t size() const { return inst_size; }
    virtual const RecordType *isA() const;
    virtual void xapply(void* dst, Type* dstType, ArgDesc&);
//    void set_desc(ClassDesc *d, unsigned s) { desc = d; inst_size = s; }
    inline const int expanded() const {return kind == RecordTypeKind;}
    inline void coerceTo(void*dst, const void *src, const Type *dst_clas) const
	{ (*_coerceTo)(dst, src, dst_clas, this); }
    virtual Root *coerceToRoot(void *srcAddr) const;
    virtual void coerceFromRoot(void *dstAddr, Root *value) const;
    //inline isScalar(void *object) { return options & TypeIsScalar; }
    virtual void printon(ostream& file) const;
    inline void print_val(void *addr, ostream& outs) const
	{ coerceToRoot(addr)->printon(outs); }
    virtual void cdecl(Symbol *var, ostream&) const;
    int is_scalar() const;
    void copy_object(void* dst, void *src); // Copy objects of current Type.
#endif
};

struct Any {
    struct Type *type;
    void *addr;
#ifdef __cplusplus
    inline Root *coerceToRoot()
	{ return ((const Type*)type)->coerceToRoot(addr); }
    inline void printon(ostream& outs) const { type->print_val(addr, outs); }
    void coerceTo(void *dst, Type* dstType) { type->coerceTo(dst, addr, dstType); }
#endif
};
#ifdef __cplusplus
inline ostream& operator<<(ostream& outs, struct Any x)
 { x.printon(outs); return outs; }
#endif

extern struct RecordType Root_classDesc, Type_classDesc;
#ifdef __cplusplus
class PrimitiveType : public Type {
  public:
    const Name class_name;
    PrimitiveType(Symbol *, int size, CoerceFunction, int _flags=0);
    virtual void printon(ostream&) const;
};

class PrimIntType : public PrimitiveType {
  public:
    Name c_name;
    int is_signed : 1;
    PrimIntType(char *qname, char *name, int size, int issigned);
    virtual void cdecl(Symbol *var, ostream&) const;
    virtual Root *coerceToRoot(void *srcAddr) const;
    virtual void coerceFromRoot(void *dstAddr, Root *value) const;
    virtual void dumpPtr(CFile *cf) const;
};

// Text is the only type that has meta-type TextType.
// A Text is a special type that is only used for results.
// It means that the destination is an (ostream*),
// and the result should be printed on it (as if by PrintResult()).

class TextType : public Type {
  public:
    TextType();
    virtual void coerceFromRoot(void *dstAddr, Root *value) const;
    virtual void printon(ostream&) const;
    virtual void cdecl(Symbol *var, ostream&) const;
    virtual void dumpPtr(CFile *cf) const;
};
extern TextType Text;

class ReferenceType : public Type {
  public:
    const Type *base_class;
    ReferenceType(const Type *base, CoerceFunction = 0);
    virtual void printon(ostream&) const;
    virtual void cdecl(Symbol *var, ostream&) const;
    virtual Root *coerceToRoot(void *srcAddr) const;
    virtual void coerceFromRoot(void *dstAddr, Root *value) const;
    virtual void dumpPtr(CFile *cf) const;
};

class Record;

class RecordType : public Type {
  public:
    const Symbol *class_name;
    const Class* *const class_bases;  /* pointer to base class list */
    void *instanceVTable; // Virtual Method table to use for Record instances
    struct ClassDesc desc[1];
    RecordType(int size);
    RecordType(Symbol *, Class**bases, int size, CoerceFunction, int _flags=0,
	       void* VTable=0);
    Record *alloc(size_t size = (size_t)(-1));
    const Symbol *symbol() { return class_name; }
    const char* name() const;
    virtual void printon(ostream&) const;
    virtual void dumpPtr(CFile *cf) const;
    virtual void cdecl(Symbol *var, ostream&) const;
    RecordType* new_subclass(Symbol* name) const;
    bool _isKindOf(const Class&) const;
};

class UnionType : public Type {
  public:
    int count;
    Root **members;
    virtual void printon(ostream&) const;
    virtual void xapply(void* dst, Type* dstType, ArgDesc&);
};
inline const RecordType * Root::desc() { return &Root_classDesc; }
inline const RecordType * Type::desc() { return &Type_classDesc; }
#endif

struct ExceptionClass {
    char *exname;
    struct ExceptionClass *super;
    struct Type *parameter;
    short level; /* one more than level of super; 1 if no super */
    short options;
};

#include "obtags.h"
#include <typetabs.h>

#ifdef __cplusplus
class TypeList { // from NIHLIB
        Type** clp;
        friend Type;
public:
        TypeList(Type*class0, ...);
        TypeList(const char*, ...);
        ~TypeList() {}         // that's right -- don't delete clp
};

#define DECLARE_CASTDOWN(clname) \
  static clname* castdown(Root* p)		{ return (clname*)p; } \
  static const clname* castdown(const Root* p){ return (const clname*)p; }

#define DECLARE_MEMBERS_STATIC(classname, TypeClass) \
  public: \
    static TypeClass classDesc; \
    inline static const TypeClass* desc() {return &classname::classDesc;}

#define DECLARE_MEMBERS(classname) \
    DECLARE_MEMBERS_STATIC(classname, RecordType)\
    DECLARE_CASTDOWN(classname) \
    virtual const RecordType* isA() const;

#define DEFINE_COERCIBLE_CLASS(classname, base_classes, vTable) \
  RecordType classname::classDesc(EnterSymbol(#classname), base_classes, sizeof(classname), COERCE_FUNCTION, TypeIsCompiled, vTable);\
  const RecordType* classname::isA() const { return &classname::classDesc; }

extern void DefaultCoerceTo(void *dst, const void *src,
			    const Type * dstClass, const Type *srcClass);

#define DEFINE_CLASS(classname, base_classes) \
	DEFINE_COERCIBLE_CLASS(classname, base_classes, 0)
#if 0
class Class : public Type {
  private:
//    const Symbol * class_name;
//    size_t inst_size;               // sizeof instance variables
  public:
//    short flags;
//    char alignment;
//    ClassDesc *desc;
};
#endif

extern struct RecordType * AllocRecordType();
EXTERN int hash_string(const char*, int);

inline int IntToHash(int i) { return 0x7FFFFFFF & i; }

class MissingValue : public Root {
    int code;
 public:
    MissingValue(int c) { code = c; }
    virtual void printon(ostream&) const;
    virtual void xapply(void* dst, Type* dstType, ArgDesc&);
};

extern MissingValue __Missing__;
#define Missing (&__Missing__)

class Functional : public Root {
    DECLARE_MEMBERS(Functional)
  public:
    virtual long magic() const;
    virtual Functional * functional() { return this; }
    virtual Root *infix(Root *arg1, Root *arg2);
    virtual Root *prefix(Root *arg);
    virtual Root *postfix(Root *arg);
    virtual Functional * inverse() const;
    virtual Functional *reduce() const;
};

#if 0
class QFunction : public Root {
    DECLARE_MEMBERS(QFunction)
  public:
    char *name;
    // function whose arguments are passed unevaluated
    virtual long magic() const;
    virtual void printon(ostream& outs) const;
    virtual Root * doit(Root *left, StringList*argv) const = 0;
//    virtual void doit_print(Root *left, StringList* argv) const;
};
#endif

class PrefixOp : public Functional {
  public:
    virtual void xapply(void* dst, Type* dstType, ArgDesc&);
};

typedef RootPtr OpenFlags;

class GenMap : public PrefixOp {
    DECLARE_MEMBERS(GenMap)
 public:
    virtual int rank() const { return 1; }
    virtual length_t dimension(int axis) { return 0; }
    virtual long magic() const;
    virtual length_t length() = 0;
    virtual Root * prefix(Root *);
    virtual void printon(ostream&) const;
    virtual void printBare(ostream& outs) const;
    virtual GenMap *mapping() { return this; }
    Root *chooseAll() const;
    virtual Functional * inverse();
    virtual GenSeq*  keys();

    virtual int sizeof_file() const;
    virtual void open(GenFile*, OpenFlags flags=0);
    GenFile *open(OpenFlags = 0);
};

class GenArray : public GenMap {
    DECLARE_MEMBERS(GenArray)
  public:
    virtual Root* row_major_index(fix_int index) = 0;
    virtual void set_at(index_t index, Root *new_value);
#if 0
    virtual int dimensions() = 0;
    virtual Type *elType() = 0;
    virtual Range * indices(int dim = 0) = 0;
    virtual size_t length(int dim = 0);
    virtual void *base() = 0;
    virtual int stride(int dim = 0) = 0;
#endif
};

class GenSeq : public GenArray {
    DECLARE_MEMBERS(GenSeq)
 public:
    virtual length_t dimension(int axis) { return length(); }
    virtual length_t _cycle_length(int cycle_part = 0);
    inline length_t finite_length() { return _cycle_length(0); }
    inline length_t cycle_length() { return _cycle_length(1); }
    virtual void xapply(void* dst, Type* dstType, ArgDesc&);
    virtual Root * prefix(Root *);
    virtual int null();
    virtual Root * index(index_t index);
    virtual Root* row_major_index(fix_int ind)
	{ return index((index_t)ind); }
    virtual GenSeq *sequence() const { return (GenSeq*)this; }
    int compare(Root&);
    virtual int compare(const Root& other) const
	{ return ((GenSeq*)this)->compare(*(Root*)&other); }
    virtual void unify(Root&);
    virtual void printBare(ostream& outs) const;
    virtual GenSeq*  keys();
    virtual GenSeq *subseq(index_t start, index_t end);
//    virtual Generator *generator() const;

    virtual int sizeof_file() const;
    virtual void open(GenFile*, OpenFlags flags=0);
//    virtual GenFile* open(Iterator* = 0, OpenFlags flags=0);
};

class CharSeq : public GenSeq {
    DECLARE_MEMBERS(CharSeq)
  public:
//    int char_index(index_t);
#if 0
    virtual GenSeq *subseq(index_t start, index_t end);
#endif
};

#if 0
class String : public GenSeq {
  public:
    length_t len;
    virtual size_t length() { return len; }
    virtual void printon(ostream &) const;
    virtual void printBare(ostream&) const;
    String(char *s, size_t l) { str = s; len = l; }
    String(unsigned char *s, size_t l) { str = (char*)s; len = l; }
    virtual Root *index(index_t i);
    virtual const StringC *asString(int format=0) const;
    virtual int sizeof_file() const;
    virtual void open(GenFile*, OpenFlags flags=0);
//    virtual GenFile * open(long flags=0)const;
    char* chars() const { return str; }
    inline size_t leng() const { return len; }
};
#endif

class StringC : public CharSeq {
    DECLARE_MEMBERS(StringC)
  public:
    char *str;
    /*const*/ length_t len;
#if 1
    StringC(char *s, size_t l) { str = s; len = l; }
    StringC(unsigned char *s, length_t l) { str = (char*)s; len = l; }
    char* chars() const { return str; }
    char* string() const { return str; }
    virtual GenSeq *subseq(index_t start, index_t end);
#else
    StringC(length_t l) : len(l) { }
    char * chars() const { return (char*)(this+1); }
    char * string() const { return (char*)(this+1); }
    // Root * data[len+1];
#endif
    inline length_t leng() const { return len; }
    virtual length_t length() { return len; }
    virtual Root * index(index_t i);
    virtual int sizeof_file() const;
    virtual void open(GenFile*, OpenFlags flags=0);
    virtual const StringC *asString(int format=0) const { return this; }
    virtual void printon(ostream&) const;
    virtual void printBare(ostream&) const;
    virtual void dumpPtr(CFile *cf) const;
    int equal(const StringC& x) const;
};

struct String : public StringC {
    String(char *s, size_t l) :StringC(s, l) { }
};


extern StringC * NewString(length_t size);
extern StringC * NewString(length_t size, const char *vals);

class StringV : public String { // Same as StringC, but updatable
    DECLARE_MEMBERS(StringV)
    StringV(char *s, size_t l) : String(s, l) { }
    StringV(size_t l) : String(NULL, l) { }
//    virtual Root * index(index_t i);
    virtual const StringC *asString(int format=0) const;
//    virtual void set_at(index_t index, Root *new_value);
};

class Assignable : public Root {
  public:
    Root * _property_list;
    MARK(gcpointer(_property_list));
    virtual void printon(ostream&) const;
    virtual long magic() const;
    virtual Assignable * assignable() const { return (Assignable*)this; }
    inline Assignable();
    void NotifyDependents();
    virtual void xapply(void* dst, Type* dstType, ArgDesc&);
};

extern void SignalBadAssignment(Root *var, Root *new_val);

class Symbol : public Assignable {
    DECLARE_MEMBERS(Symbol)
  public:
#define C_SYM 2
#ifdef C_SYM
    char *_pchars;
#else
    const StringC *_pname;
#endif
    Package *_package; // Home package. NULL if not interned in a package.
    // The _value cell is curently shared for both 'value binding'
    // and 'function binding.' This saves space, at some complexity
    // to deal with the case that both bindings are bound.
    // In that case, _value points to a cons cell.
  protected:
    Root *_value;
  public:
#ifdef C_SYM
    int _flags : 8;
    unsigned int _plength : 24;
#else
    int _flags;
#endif

    enum {
	is_constant = 1,
	has_value = 2,
	has_function = 4,
	has_both = 8, /* has_value+has_function, and they're different. */
	is_macro = 16,
	autoload_function = 32, // Use (char*)_value as file name.
	fixed_binding = 64, // Can update value, but not add/remove binding.
    };

    Root* sym_value(); // Get 'value binding'.
    Root* sym_function(); // Get 'function binding'.
    void sym_value(Root *nval) {Symbol::assign(nval);} // Set 'value binding'.
    void sym_function(Root *new_val); // Set 'function binding'.
    // Set both function and value bindings to the same.
    // Used for Q and Scheme but not Common Lisp.
    void set_value(Root *new_val);

    Root * package() const; // Returns Nil if not interned.
    int is_external(Package*p=NULL) const; // True if external in p.
    friend int compare(const Symbol&, const Symbol&);
    virtual int compare(const Root&) const;
    /*char print_name[len+1];*/
    virtual long magic() const;
    virtual void printon(ostream&) const;
    virtual const StringC *asString(int format=0) const; 
#ifdef C_SYM
    inline const StringC *Str() const { return NewString(leng(), chars()); }
    inline long Length() const { return _plength; }
    inline long length() const { return _plength; }
    inline long leng() const { return _plength; } // Preferred name
    inline char *string() const { return _pchars; }
    inline char *chars() const { return _pchars; } // Preferred name
    unsigned char *ustring() const { return (unsigned char*)_pchars; }
    void init(char* pchars, int plength, Package *pack);
    Symbol(char* pchars, int plength, Package *pack)
	{ init(pchars, plength, pack); }
    Symbol(const String *str);
    Symbol(const String *str, Package *pack)
	{ init(str->chars(), str->leng(), pack); }
#else
    inline const StringC *Str() const { return _pname; }
    inline long Length() const { return _pname->leng(); }
    inline long length() const { return _pname->leng(); }
    inline long leng() const { return _pname->leng(); } // Preferred name
    inline char *string() const { return _pname->chars(); }
    inline char *chars() const { return _pname->chars(); } // Preferred name
    unsigned char *ustring() const
	{ return (unsigned char*)_pname->chars(); }
#endif
    inline long Hash() const { return hash_string(string(), length()); }
    Symbol(const StringC *str);
    Symbol(const StringC *str, Package *);
    virtual int hash() const;
    // followed by string
    void coerceTo(Type*, void *);
    virtual void assign(Root *new_value);
    virtual Root *value();
    virtual void xapply(void* dst, Type* dstType, ArgDesc&);
    virtual void dumpPtr(CFile *cf) const;
};

class NilClass : public Symbol {
  public:
    NilClass();
    virtual GenSeq *sequence() const;
    virtual void printon(ostream&) const;
    virtual void xapply(void* dst, Type* dstType, ArgDesc&);
};

extern NilClass NilSymbol;

inline Assignable::Assignable() { _property_list = &NilSymbol; }
inline void Symbol::init(char* pchars, int plength, Package *pack)
  { _pchars = pchars; _plength = plength; _property_list = &NilSymbol;
    _value = NULL; _flags = 0; _package = pack; }

class Character : public Symbol {
    DECLARE_MEMBERS(Character)
      public:
    virtual void printon(ostream&) const;
};

/*struct Char { char c; };*/
/* IsChar(x) assumes x is a Symbol */
#define IsChar(x) (SymbolLength(x) == 1)
extern struct Character CharTable[256];
#define CCharToChar(c) &CharTable[(unsigned char)(c)]

inline char * Name::string() const { return _name ? _name->string() : NULL; }
inline long Name::length() const { return _name->length(); }
inline bool Root::isKindOf(const Class&cl) const
{ return isA()->_isKindOf(cl);}

class Atom : public Root {
 public:
    Symbol * name;
    inline Atom(Symbol * n) { name = n; }
    virtual void printon(ostream&) const;
};

extern ReferenceType RefRoot, RefInteger, RefReal, RefNumeric, RefVector;

inline Root *Root::apply(ArgDesc& args) {
    Root *dst; xapply(&dst, &RefRoot, args); return dst; }

#endif /* __cplusplus */


typedef struct
  {
    RootPtr arg;
    RootPtr val;
  } MapPair;

typedef struct
  {
    Object environ; /* must be consistent with FrStatLink */
    HeapPrefix h;
  } StructHdr; /* same as FramePrefix; should be merged ? */

#define FileUndoSeeks 1
struct BFile{
    struct Any mapping;
/*  void *current;     void *readLimit; short stride; */
    short flags;
    int curIndex;
    HandlerDesc *handlerAtLastSeek;
};

#ifdef __cplusplus
#define UnknownByteLocation 0x400000
struct Location {/* position in file */
    int fileNo : 8;
    int code: 8; /* hack! */
    int byteNo : 24; /* byte within file */
    int lineNo : 16; /* line within file, starting at 1; 0 is unknown */
    void set_unknown() { fileNo = 0; lineNo = 0; byteNo = UnknownByteLocation;}
};
#endif
#endif /* !TYPES_H */
