
/******************************************************************************
* MODULE     : tree.gen.h
* DESCRIPTION: fixed size trees with reference counting
* COPYRIGHT  : (C) 1999  Joris van der Hoeven
*******************************************************************************
* This software falls under the GNU general public license and comes WITHOUT
* ANY WARRANTY WHATSOEVER. See the file $TEXMACS_PATH/LICENSE for more details.
* If you don't have this file, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
******************************************************************************/

#include <basic.gen.h>
#include <string.gen.h>
#include <array.gen.h>
#include <hashmap.gen.h>

#module tree
#import basic
#import string
#define no_debug_trees

/******************************************************************************
* The tree class 'tree'
******************************************************************************/

enum tree_label {
  STRING, UNKNOWN, UNINIT, ERROR, RAW_DATA,
  DOCUMENT, PARAGRAPH, SURROUND, CONCAT, FORMAT,
  HSPACE, VSPACE_BEFORE, VSPACE_AFTER, SPACE,
  HTAB, SPLIT, MOVE, RESIZE, REPEAT, FLOAT,
  DECORATE_ATOMS, DECORATE_LINES, DECORATE_PAGES, DECORATED_BOX, // 25

  GROUP, LEFT, MIDDLE, RIGHT, BIG,
  LEFT_PRIME, RIGHT_PRIME, BELOW, ABOVE,
  LEFT_SUB, LEFT_SUP, RIGHT_SUB, RIGHT_SUP,
  FRAC, SQRT, WIDE, WIDE_UNDER, NEG, TREE,
  OLD_MATRIX, OLD_TABLE, OLD_MOSAIC, OLD_MOSAIC_ITEM, // 23

  TABLE_FORMAT, TABLE_WITH, CELL_WITH, TABLE_MARKER,
  TABLE, ROW, CELL, SUB_TABLE, // 8

  ASSIGN, WITH, SET, RESET,
  VAR_EXPAND, EXPAND, APPLY, BEGIN, END, INCLUDE,
  MACRO, FUNCTION, ENVIRONMENT,
  EVAL, VALUE, ARGUMENT,
  BACKUP, QUOTE, DELAY, HOLD, RELEASE, // 21

  OR, XOR, AND, NOT,
  PLUS, MINUS, TIMES, OVER, DIVIDE, MODULO,
  MERGE, LENGTH, RANGE, NUMBER, DATE, TRANSLATE,
  IS_TUPLE, LOOK_UP,
  EQUAL, UNEQUAL, LESS, LESSEQ, GREATER, GREATEREQ,
  IF, CASE, WHILE, EXTERN, AUTHORIZE, // 29

  INACTIVE, SYMBOL, LATEX, HYBRID,
  TUPLE, COLLECTION, ASSOCIATE,
  LABEL, REFERENCE, PAGEREF, WRITE,
  SPECIFIC, HYPERLINK, ACTION,
  TAG, MEANING, // 16

  GRAPHICS, POINT, LINE, ARC, BEZIER, POSTSCRIPT // 6
};

class tree_rep;
class atomic_rep;
class compound_rep;
class array<tree>;
class tree {
  tree_rep* rep; // can be atomic or compound
public:
  inline tree (const tree& x);
  inline ~tree ();
  inline atomic_rep* operator -> ();
  inline tree& operator = (tree x);

  inline tree ();
  inline tree (string l);
  inline tree (char* l);
  inline tree (tree_label l, int n=0);
  inline tree (tree t, int n);
  tree (tree_label l, tree t1);
  tree (tree_label l, tree t1, tree t2);
  tree (tree_label l, tree t1, tree t2, tree t3);
  tree (tree_label l, tree t1, tree t2, tree t3, tree t4);
  tree (tree_label l, tree t1, tree t2, tree t3, tree t4, tree t5);
  tree (tree_label l, tree t1, tree t2, tree t3, tree t4, tree t5, tree t6);
  inline tree& operator [] (int i);
  tree operator () (int start, int end);

  friend inline int N (tree t);
  friend inline int arity (tree t);
  friend inline tree_label L (tree t);
  friend inline array<tree> A (tree t);
  friend inline bool is_atomic (tree t);
  friend inline bool is_compound (tree t);
  friend inline bool operator == (tree t, string s);
  friend inline bool operator != (tree t, string s);
  friend inline bool operator == (tree t, char* s);
  friend inline bool operator != (tree t, char* s);
  friend inline bool is_func (tree t, tree_label l);
  friend inline bool is_func (tree t, tree_label l, int i);

  friend tree copy (tree t);
  friend bool operator == (tree t, tree u);
  friend bool operator != (tree t, tree u);
  friend tree& operator << (tree& t, tree t2);
  friend tree& operator << (tree& t, array<tree> a);
  friend ostream& operator << (ostream& out, tree t);
};

#import array (tree)
#import hashmap (string, int)

class tree_rep: concrete_struct {
public:
  tree_label op;
  inline tree_rep (tree_label op2): op (op2) {}
  friend class tree;
};

class atomic_rep: public tree_rep {
public:
  string label;
  inline atomic_rep (string l): tree_rep (STRING), label (l) {}
  friend class tree;
};

class compound_rep: public tree_rep {
public:
  array<tree> a;
  inline compound_rep (tree_label l, array<tree> a2): tree_rep (l), a (a2) {}
  friend class tree;
};

/******************************************************************************
* Routines for trees
******************************************************************************/

#ifdef debug_trees
#define CHECK_ATOMIC(t,s) \
  if (((t).rep)->op != STRING) { \
    cerr << "\nThe tree : " << (t) << "\n"; \
    fatal_error ("atomic tree expected", s); \
  }
#define CHECK_COMPOUND(t,s) \
  if (((t).rep)->op == STRING) { \
    cerr << "\nThe tree : " << (t) << "\n"; \
    fatal_error ("compound tree expected", s); \
  }
#else
#define CHECK_ATOMIC(t,s)
#define CHECK_COMPOUND(t,s)
#endif

void destroy_tree_rep (tree_rep* rep);
inline tree::tree (const tree& x): rep (x.rep) { rep->ref_count++; }
inline tree::~tree () {
  if ((--rep->ref_count)==0) destroy_tree_rep (rep); }
inline atomic_rep* tree::operator -> () {
  CHECK_ATOMIC (*this, "tree::operator ->");
  return (atomic_rep*) rep; }
inline tree& tree::operator = (tree x) {
  x.rep->ref_count++;
  if ((--rep->ref_count)==0) destroy_tree_rep (rep);
  rep= x.rep;
  return *this; }

inline tree::tree ():
  rep (new atomic_rep (string ())) {}
inline tree::tree (char *s):
  rep (new atomic_rep (s)) {}
inline tree::tree (string s):
  rep (new atomic_rep (s)) {}
inline tree::tree (tree_label l, int n):
  rep (new compound_rep (l, array<tree> (n))) {}
inline tree::tree (tree t, int n):
  rep (new compound_rep (t.rep->op, array<tree> (n))) {
    CHECK_COMPOUND (t, "tree::tree (tree, int)"); }
inline tree& tree::operator [] (int i) {
  CHECK_COMPOUND (*this, "tree::operator []");
  return ((compound_rep*) rep)->a[i]; }
extern inline int N (tree t) {
  CHECK_COMPOUND (t, "N (tree)");
  return N (((compound_rep*) t.rep)->a); }
inline int arity (tree t) {
  if (t.rep->op == STRING) return 0;
  else return N (((compound_rep*) t.rep)->a); }
inline tree_label L (tree t) {
  return t.rep->op; }
inline array<tree> A (tree t) {
  CHECK_COMPOUND (t, "A (tree)");
  return ((compound_rep*) t.rep)->a; }

inline bool is_atomic (tree t) { return (t.rep->op == STRING); }
inline bool is_compound (tree t) { return (t.rep->op != STRING); }
inline bool operator == (tree t, string s) {
  return (t.rep->op == STRING) && (t->label == s); }
inline bool operator != (tree t, string s) {
  return (t.rep->op != STRING) || (t->label != s); }
inline bool operator == (tree t, char* s) {
  return (t.rep->op == STRING) && (t->label == s); }
inline bool operator != (tree t, char* s) {
  return (t.rep->op != STRING) || (t->label != s); }

inline bool is_func (tree t, tree_label l) {
  return (t.rep->op==l) && (N(t)!=0); }
inline bool is_func (tree t, tree_label l, int i) {
  return (t.rep->op==l) && (N(t)==i); }

inline bool is_bool (tree t) { return is_atomic (t) && is_bool (t->label); }
inline bool is_int (tree t) { return is_atomic (t) && is_int (t->label); }
inline bool is_double (tree t) { return is_atomic (t) && is_double(t->label); }
inline bool is_string (tree t) { return is_atomic (t); }
inline bool as_bool (tree t) {
  if (is_atomic (t)) return as_bool (t->label);
  else return FALSE; }
inline int as_int (tree t) {
  if (is_atomic (t)) return as_int (t->label);
  else return 0; }
inline double as_double (tree t) {
  if (is_atomic (t)) return as_double (t->label);
  else return 0.0; }
inline string as_string (tree t) {
  if (is_atomic (t)) return t->label;
  else return ""; }

tree texmacs_to_tree (string s);
tree texmacs_document_to_tree (string s);
string tree_to_texmacs (tree t);
string tree_to_texmacs_document (tree t);
tree extract (tree doc, string attr);

/******************************************************************************
* Data
******************************************************************************/

#define CONSTRUCTOR_NR 128
extern string CONSTRUCTOR_NAME  [CONSTRUCTOR_NR];
extern int    CONSTRUCTOR_ARITY [CONSTRUCTOR_NR];

inline string get_label (tree t) {
  return is_atomic (t)? t->label: copy (CONSTRUCTOR_NAME [L(t)]); }

tree_label SUB (bool right);
tree_label SUP (bool right);

extern string WITH_LIMITS;
extern string LINE_BREAK;
extern string NEW_LINE;
extern string LINE_SEP;
extern string NEXT_LINE;
extern string NO_BREAK;
extern string YES_FIRST_INDENT;
extern string NO_FIRST_INDENT;
extern string YES_FIRST_INDENT_AFTER;
extern string NO_FIRST_INDENT_AFTER;
extern string PAGE_BREAK;
extern string NEW_PAGE;
extern string NO_PAGE_BREAK_BEFORE;
extern string NO_PAGE_BREAK_AFTER;

bool is_document (tree t);
bool is_concat (tree t);
bool is_format (tree t);
bool is_table (tree t);
bool is_multi_paragraph (tree t);
bool is_script (tree t, bool& right);
bool is_prime (tree t);
bool is_dynamic (tree t);
bool is_expand (tree t);
bool is_expand (tree t, int n);
bool is_expand (tree t, string s, int n);

inline bool
is_applicable (tree t) {
  return is_compound (t) && (N(t) >= 1) &&
    ((L(t) == MACRO) || (L(t) == FUNCTION));
}

bool is_accessible_child (tree t, int child);
bool is_child_enforcing (tree t);
bool is_table_format (tree t);

tree simplify_concat (tree t);
tree simplify_paragraph (tree t);
tree simplify_document (tree t);
tree simplify_with (tree t);
tree simplify_arity (tree t);
tree simplify_correct (tree t);

/******************************************************************************
* Scheme
******************************************************************************/

typedef tree scheme_tree;
typedef array<tree> array<scheme_tree>;

string scheme_tree_to_string (scheme_tree p);
scheme_tree string_to_scheme_tree (string s);
scheme_tree block_to_scheme_tree  (string s);
tree scheme_tree_to_tree (scheme_tree p);
scheme_tree tree_to_scheme_tree (tree t);

tree scheme_to_tree (string s);
tree scheme_document_to_tree (string s);
string tree_to_scheme (tree t);
string tree_to_scheme_document (tree t);

inline tree tuple (tree t1) {
  return tree (TUPLE, t1); }
inline tree tuple (tree t1, tree t2) {
  return tree (TUPLE, t1, t2); }
inline tree tuple (tree t1, tree t2, tree t3) {
  return tree (TUPLE, t1, t2, t3); }
inline tree tuple (tree t1, tree t2, tree t3, tree t4) {
  return tree (TUPLE, t1, t2, t3, t4); }

inline bool is_tuple (tree t) {
  return (L(t) == TUPLE); }
inline bool is_tuple (tree t, string s) {
  return (L(t) == TUPLE) && (N(t) >= 1) && (t[0] == s); }
inline bool is_tuple (tree t, char* s) {
  return (L(t) == TUPLE) && (N(t) >= 1) && (t[0] == s); }
inline bool is_tuple (tree t, char* s, int n) {
  return (L(t) == TUPLE) && (N(t) == (n+1)) && (t[0] == s); }
inline bool is_tuple (tree t, string s, int n) {
  return (L(t) == TUPLE) && (N(t) == (n+1)) && (t[0] == s); }

/******************************************************************************
* Miscellaneous
******************************************************************************/

tree math_correct (tree t);
int  hash (tree t);

#endmodule // tree
