
/******************************************************************************
* MODULE     : tree.gen.cc
* 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 <tree.gen.h>
#include <array.gen.cc>

#module code_tree
#import tree
#import code_array (tree)

/******************************************************************************
* Main routines for trees
******************************************************************************/

void
destroy_tree_rep (tree_rep* rep) {
  if (rep->op == STRING) delete ((atomic_rep*) ((void*) rep));
  else delete ((compound_rep*) ((void*) rep));
}

tree::tree (tree_label l, tree t1):
  rep (new compound_rep (l, array<tree> (1))) {
  ((compound_rep*) rep)->a[0]=t1;
}

tree::tree (tree_label l, tree t1, tree t2):
  rep (new compound_rep (l, array<tree> (2))) {
  ((compound_rep*) rep)->a[0]=t1;
  ((compound_rep*) rep)->a[1]=t2;
}

tree::tree (tree_label l, tree t1, tree t2, tree t3):
  rep (new compound_rep (l, array<tree> (3))) {
  ((compound_rep*) rep)->a[0]=t1;
  ((compound_rep*) rep)->a[1]=t2;
  ((compound_rep*) rep)->a[2]=t3;
}

tree::tree (tree_label l, tree t1, tree t2, tree t3, tree t4):
  rep (new compound_rep (l, array<tree> (4))) {
  ((compound_rep*) rep)->a[0]=t1;
  ((compound_rep*) rep)->a[1]=t2;
  ((compound_rep*) rep)->a[2]=t3;
  ((compound_rep*) rep)->a[3]=t4;
}

tree::tree (tree_label l, tree t1, tree t2, tree t3, tree t4, tree t5):
  rep (new compound_rep (l, array<tree> (5))) {
  ((compound_rep*) rep)->a[0]=t1;
  ((compound_rep*) rep)->a[1]=t2;
  ((compound_rep*) rep)->a[2]=t3;
  ((compound_rep*) rep)->a[3]=t4;
  ((compound_rep*) rep)->a[4]=t5;
}

tree::tree (tree_label l,
	    tree t1, tree t2, tree t3, tree t4, tree t5, tree t6):
  rep (new compound_rep (l, array<tree> (6)))
{
  ((compound_rep*) rep)->a[0]=t1;
  ((compound_rep*) rep)->a[1]=t2;
  ((compound_rep*) rep)->a[2]=t3;
  ((compound_rep*) rep)->a[3]=t4;
  ((compound_rep*) rep)->a[4]=t5;
  ((compound_rep*) rep)->a[5]=t6;
}

tree
tree::operator () (int begin, int end) {
  int i;
  tree r (rep->op, end-begin);
  for (i=begin; i<end; i++) r[i-begin]= ((compound_rep*) rep)->a[i];
  return r;
}

bool
operator == (tree t, tree u) {
  return (L(t)==L(u)) &&
    (L(t)==STRING? (t->label==u->label): (A(t)==A(u)));
}

bool
operator != (tree t, tree u) {
  return (L(t)!=L(u)) ||
    (L(t)==STRING? (t->label!=u->label): (A(t)!=A(u)));
}

int
right_index (tree t) {
  return is_atomic (t)? N(t->label): 1;
}

tree
copy (tree t) {
  if (is_atomic (t)) return tree (copy (t->label));
  else {
    int i, n= N(t);
    tree t2 (t, n);
    for (i=0; i<n; i++) t2[i]= copy (t[i]);
    return t2;
  }
}

tree&
operator << (tree& t, tree t2) {
  CHECK_COMPOUND (t, "operator << (tree&, tree)");
  ((compound_rep*) t.rep)->a << t2;
  return t;
}

tree&
operator << (tree& t, array<tree> a) {
  CHECK_COMPOUND (t, "operator << (tree&, array<tree>)");
  ((compound_rep*) t.rep)->a << a;
  return t;
}

ostream&
operator << (ostream& out, tree t) {
  if (is_atomic (t)) return out << t->label;
  else {
    int i, n= N(t);
    out << CONSTRUCTOR_NAME [(int) L(t)];
    if (n==0) return out;
    out << " (";
    for (i=0; i< n-1; i++)
      out << t[i] << ", ";
    out << t[i] << ")";
    return out;
  }
}

int
hash (array<tree> a) {
  register int i, h=0, n=N(a);
  for (i=0; i<n; i++) {
    h=(h<<7) + (h>>25);
    h=h + hash(a[i]);
  }
  return h;
}

int
hash (tree t) {
  if (is_atomic (t)) return hash (t->label);
  else return ((int) L(t)) ^ hash (A(t));
}

/******************************************************************************
* initialization
******************************************************************************/

hashmap<string,int> CONSTRUCTOR_CODE (UNKNOWN);

string CONSTRUCTOR_NAME       [CONSTRUCTOR_NR];
int    CONSTRUCTOR_ARITY      [CONSTRUCTOR_NR];
int    CONSTRUCTOR_PROPERTIES [CONSTRUCTOR_NR];

#define ACCESSIBLE_MASK            7
#define NOT_ACCESSIBLE             0
#define ACCESSIBLE                 1
#define FIRST_ACCESSIBLE           2
#define LAST_ACCESSIBLE            3
#define TAIL_ACCESSIBLE            4
#define TABLE_ACCESSIBLE           5
#define BORDER_ACCESSIBLE_MASK     8
#define BORDER_NOT_ACCESSIBLE      8
#define DYNAMIC_MASK              16
#define DYNAMIC                   16

#define ACCESSIBLE_EXCEPT_BORDER (ACCESSIBLE+BORDER_NOT_ACCESSIBLE)
#define ONLY_LAST_ACCESSIBLE (LAST_ACCESSIBLE+BORDER_NOT_ACCESSIBLE)

string WITH_LIMITS ("with limits");
string LINE_BREAK ("line break");
string NEW_LINE ("new line");
string LINE_SEP ("line separator");
string NEXT_LINE ("next line");
string NO_BREAK ("no line break");
string NO_FIRST_INDENT ("no first indentation");
string YES_FIRST_INDENT ("enable first indentation");
string NO_FIRST_INDENT_AFTER ("no indentation after");
string YES_FIRST_INDENT_AFTER ("enable indentation after");
string PAGE_BREAK ("page break");
string NEW_PAGE ("new page");
string NO_PAGE_BREAK_BEFORE ("no page break before");
string NO_PAGE_BREAK_AFTER ("no page break after");

tree_label SUB (bool right) { return right? RIGHT_SUB: LEFT_SUB; }
tree_label SUP (bool right) { return right? RIGHT_SUP: LEFT_SUP; }

static void
constructor (tree_label l, string name, int arity, int properties= 0) {
  CONSTRUCTOR_CODE       (name)    = (int) l;
  CONSTRUCTOR_NAME       [(int) l] = name;
  CONSTRUCTOR_ARITY      [(int) l] = arity;
  CONSTRUCTOR_PROPERTIES [(int) l] = properties;
}

static bool edit_data_initialized=FALSE;

void
initialize_data () {
  if (edit_data_initialized) return;
  edit_data_initialized=TRUE;

  constructor (UNKNOWN, "unknown", 0);
  constructor (UNINIT, "uninit", 0);
  constructor (ERROR, "error", 1);
  constructor (RAW_DATA, "raw_data", 1);

  constructor (DOCUMENT, "document", -1, ACCESSIBLE_EXCEPT_BORDER);
  constructor (PARAGRAPH, "paragraph", -1, ACCESSIBLE_EXCEPT_BORDER);
  constructor (SURROUND, "surround", 3, ACCESSIBLE + DYNAMIC);
  constructor (CONCAT, "concat", -1, ACCESSIBLE_EXCEPT_BORDER);
  constructor (FORMAT, "format", -1);
  constructor (HSPACE, "hspace", -1);
  constructor (VSPACE_BEFORE, "vspace*", -1);
  constructor (VSPACE_AFTER, "vspace", -1);
  constructor (SPACE, "space", -1);
  constructor (HTAB, "htab", -1);
  constructor (SPLIT, "split", -1, DYNAMIC);
  constructor (MOVE, "move", 3, FIRST_ACCESSIBLE);
  constructor (RESIZE, "resize", 5, FIRST_ACCESSIBLE);
  constructor (FLOAT, "float", 3, LAST_ACCESSIBLE + DYNAMIC);
  constructor (REPEAT, "repeat", 2, FIRST_ACCESSIBLE + DYNAMIC);
  constructor (DECORATE_ATOMS, "datoms", -1, LAST_ACCESSIBLE + DYNAMIC);
  constructor (DECORATE_LINES, "dlines", -1, LAST_ACCESSIBLE + DYNAMIC);
  constructor (DECORATE_PAGES, "dpages", -1, LAST_ACCESSIBLE + DYNAMIC);
  constructor (DECORATED_BOX, "dbox", 0);

  constructor (GROUP, "group", 1, ACCESSIBLE);
  constructor (LEFT, "left", 1);
  constructor (MIDDLE, "mid", 1);
  constructor (RIGHT, "right", 1);
  constructor (BIG, "big", 1);
  constructor (LEFT_PRIME, "lprime", 1);
  constructor (RIGHT_PRIME, "rprime", 1);
  constructor (BELOW, "below", 2, ACCESSIBLE);
  constructor (ABOVE, "above", 2, ACCESSIBLE);
  constructor (LEFT_SUB, "lsub", 1, ACCESSIBLE);
  constructor (LEFT_SUP, "lsup", 1, ACCESSIBLE);
  constructor (RIGHT_SUB, "rsub", 1, ACCESSIBLE);
  constructor (RIGHT_SUP, "rsup", 1, ACCESSIBLE);
  constructor (FRAC, "frac", 2, ACCESSIBLE);
  constructor (SQRT, "sqrt", -1, ACCESSIBLE);
  constructor (WIDE, "wide", 1, ACCESSIBLE);
  constructor (WIDE_UNDER, "wide*", 1, ACCESSIBLE);
  constructor (NEG, "neg", 1, ACCESSIBLE);
  constructor (TREE, "tree", -1, ACCESSIBLE);
  constructor (OLD_MATRIX, "old_matrix", -1, TABLE_ACCESSIBLE);
  constructor (OLD_TABLE, "old_table", -1, TABLE_ACCESSIBLE);
  constructor (OLD_MOSAIC, "old_mosaic", -1, TABLE_ACCESSIBLE);
  constructor (OLD_MOSAIC_ITEM, "old_mosaic_item", -1, ACCESSIBLE);

  constructor (TABLE_FORMAT, "tformat", -1, ONLY_LAST_ACCESSIBLE + DYNAMIC);
  constructor (TABLE_WITH, "twith", 2, ACCESSIBLE);
  constructor (CELL_WITH, "cwith", 6, ACCESSIBLE);
  constructor (TABLE_MARKER, "tmarker", 0);
  constructor (TABLE, "table", -1, ACCESSIBLE_EXCEPT_BORDER);
  constructor (ROW, "row", -1, ACCESSIBLE_EXCEPT_BORDER);
  constructor (CELL, "cell", 1, ACCESSIBLE_EXCEPT_BORDER);
  constructor (SUB_TABLE, "sub_table", 1, ACCESSIBLE_EXCEPT_BORDER);

  constructor (ASSIGN, "assign", 2, DYNAMIC);
  constructor (WITH, "with", -1, LAST_ACCESSIBLE + DYNAMIC);
  constructor (SET, "set", 2, DYNAMIC);
  constructor (RESET, "reset", 1, DYNAMIC);
  constructor (VAR_EXPAND, "var_expand", -1,
	       TAIL_ACCESSIBLE + DYNAMIC + BORDER_NOT_ACCESSIBLE);
  constructor (EXPAND, "expand", -1, TAIL_ACCESSIBLE + DYNAMIC);
  constructor (APPLY, "apply", -1, DYNAMIC);
  constructor (BEGIN, "begin", -1, DYNAMIC);
  constructor (END, "end", 1, DYNAMIC);
  constructor (INCLUDE, "include", 1, DYNAMIC);
  constructor (MACRO, "macro", -1, DYNAMIC);
  constructor (FUNCTION, "func", -1, DYNAMIC);
  constructor (ENVIRONMENT, "env", -1, DYNAMIC);
  constructor (EVAL, "eval", 1, DYNAMIC);
  constructor (VALUE, "value", 1, DYNAMIC);
  constructor (ARGUMENT, "arg", 1, DYNAMIC);
  constructor (BACKUP, "backup", 1);
  constructor (QUOTE, "quote", 1, DYNAMIC);
  constructor (DELAY, "delay", 1, DYNAMIC);
  constructor (HOLD, "hold", 1, DYNAMIC);
  constructor (RELEASE, "release", 1, DYNAMIC);

  constructor (OR, "or", -1, DYNAMIC);
  constructor (XOR, "xor", 2);
  constructor (AND, "and", -1, DYNAMIC);
  constructor (NOT, "not", 1);
  constructor (PLUS, "plus", 2);
  constructor (MINUS, "minus", 2);
  constructor (TIMES, "times", 2);
  constructor (OVER, "over", 2);
  constructor (DIVIDE, "div", 2);
  constructor (MODULO, "mod", 2);
  constructor (MERGE, "merge", 2);
  constructor (LENGTH, "length", 1);
  constructor (RANGE, "range", 3);
  constructor (NUMBER, "number", 2);
  constructor (DATE, "date", -1);
  constructor (TRANSLATE, "translate", 3);
  constructor (IS_TUPLE, "is_tuple", 1);
  constructor (LOOK_UP, "look_up", 2);
  constructor (EQUAL, "equal", 2);
  constructor (UNEQUAL, "unequal", 2);
  constructor (LESS, "less", 2);
  constructor (LESSEQ, "lesseq", 2);
  constructor (GREATER, "greater", 2);
  constructor (GREATEREQ, "greatereq", 2);
  constructor (IF, "if", -1, DYNAMIC);
  constructor (CASE, "case", -1, DYNAMIC);
  constructor (WHILE, "while", 2);
  constructor (EXTERN, "extern", -1, DYNAMIC);
  constructor (AUTHORIZE, "authorize", 2);

  constructor (INACTIVE, "inactive", 1, ACCESSIBLE);
  constructor (SYMBOL, "symbol", 1);
  constructor (LATEX, "latex", 1, DYNAMIC);
  constructor (HYBRID, "hybrid", 1, DYNAMIC);
  constructor (TUPLE, "tuple", -1, DYNAMIC);
  constructor (COLLECTION, "collection", -1);
  constructor (ASSOCIATE, "associate", 2);
  constructor (LABEL, "label", -1, DYNAMIC);
  constructor (REFERENCE, "reference", -1, DYNAMIC);
  constructor (PAGEREF, "pageref", -1, DYNAMIC);
  constructor (WRITE, "write", -1, DYNAMIC);
  constructor (SPECIFIC, "specific", 2, DYNAMIC);
  constructor (HYPERLINK, "hlink", 2, FIRST_ACCESSIBLE + DYNAMIC);
  constructor (ACTION, "action", -1, FIRST_ACCESSIBLE + DYNAMIC);
  constructor (TAG, "tag", 2, FIRST_ACCESSIBLE + DYNAMIC);
  constructor (MEANING, "meaning", 2, FIRST_ACCESSIBLE + DYNAMIC);

  constructor (GRAPHICS, "graphics", -1);
  constructor (POINT, "point", -1);
  constructor (LINE, "line", -1);
  constructor (ARC, "arc", -1);
  constructor (BEZIER, "bezier", -1);
  constructor (POSTSCRIPT, "postscript", -1, DYNAMIC);
}

/******************************************************************************
* Tree predicates
******************************************************************************/

bool
is_document (tree t) {
  return is_func (t, DOCUMENT);
}

bool
is_concat (tree t) {
  return is_func (t, CONCAT);
}

bool
is_format (tree t) {
  return is_document (t) || is_concat (t);
}

bool
is_table (tree t) {
  return
    is_func (t, TABLE) || is_func (t, SUB_TABLE) ||
    is_func (t, ROW) || is_func (t, CELL);
}

bool
is_table_format (tree t) {
  return is_func (t, TABLE_FORMAT);
}

bool
is_multi_paragraph (tree t) {
  switch (L(t)) {
  case DOCUMENT:
    return TRUE;
  case SURROUND:
    return is_multi_paragraph (t[2]);
  case DECORATE_ATOMS:
  case DECORATE_LINES:
  case DECORATE_PAGES:
  case WITH:
    return is_multi_paragraph (t[N(t)-1]);
  case INCLUDE:
    return TRUE;
  case VAR_EXPAND:
  case EXPAND:
    {
      int i, n= N(t);
      if (t[0] == "footnote") return FALSE;
      for (i=1; i<n; i++)
	if (is_multi_paragraph (t[i]))
	  return TRUE;
      return FALSE;
    }
  default:
    return FALSE;
  }
}

bool
is_script (tree t, bool& right) {
  if (is_func (t, LEFT_SUB) ||
      is_func (t, LEFT_SUP)) { right=FALSE; return TRUE; }
  if (is_func (t, RIGHT_SUB) ||
      is_func (t, RIGHT_SUP)) { right=TRUE; return TRUE; }
  return FALSE;
}

bool
is_prime (tree t) {
  return ((L(t) == LEFT_PRIME) || (L(t) == RIGHT_PRIME)) && (N(t) == 1);
}

bool
is_dynamic (tree t) {
  if (is_atomic (t)) return FALSE;
  tree_label l= L (t);
  return (CONSTRUCTOR_PROPERTIES [(int) l] & DYNAMIC_MASK) == DYNAMIC;
}

bool
is_expand (tree t) {
  return ((L(t) == VAR_EXPAND) || (L(t) == EXPAND));
}

bool
is_expand (tree t, int n) {
  return (((L(t) == VAR_EXPAND) || (L(t) == EXPAND))) && (N(t) == n+1);
}

bool
is_expand (tree t, string s, int n) {
  return
    (((L(t) == VAR_EXPAND) || (L(t) == EXPAND))) &&
    (N(t) == n+1) &&
    (t[0] == s);
}

/******************************************************************************
* Testing accessibility
******************************************************************************/

bool
is_accessible_child (tree t, int i) {
  switch (CONSTRUCTOR_PROPERTIES [(int) L(t)] & ACCESSIBLE_MASK) {
  case NOT_ACCESSIBLE:
    return FALSE;
  case ACCESSIBLE:
    return TRUE;
  case FIRST_ACCESSIBLE:
    return i==0;
  case LAST_ACCESSIBLE:
    return i==(N(t)-1);
  case TAIL_ACCESSIBLE:
    return i!=0;
  case TABLE_ACCESSIBLE:
    return i<(N(t)-2);
  default:
    return FALSE;
  }
}

bool
is_child_enforcing (tree t) {
  return
    (N(t) != 0) &&
    ((CONSTRUCTOR_PROPERTIES [(int) L(t)] & BORDER_ACCESSIBLE_MASK) ==
     BORDER_NOT_ACCESSIBLE);
}

/******************************************************************************
* Routines for simplification and correction
******************************************************************************/

static void
simplify_concat (tree& r, tree t) {
  int i, n= N(t);
  for (i=0; i<n; i++)
    if (is_concat (t[i])) simplify_concat (r, t[i]);
    else if (t[i] == "");
    else if (is_atomic (t[i]) && (N(r)>0) && is_atomic (r[N(r)-1]))
      r[N(r)-1]= tree (r[N(r)-1]->label * t[i]->label);
    else r << t[i];
}

tree
simplify_concat (tree t) {
  tree r (CONCAT);
  simplify_concat (r, t);
  if (N(r) == 0) return "";
  if (N(r) == 1) return r[0];
  return r;
}

tree
simplify_correct (tree t) {
  if (is_atomic (t)) return t;
  int i, n= N(t);
  tree r (t, n);
  for (i=0; i<n; i++)
    r[i]= simplify_correct (t[i]);
  if (is_concat (r)) r= simplify_concat (r);
  return r;
}

#endmodule // code_tree
