diff --git a/Kernel/Abstractions/observer.cpp b/Kernel/Abstractions/observer.cpp new file mode 100644 index 000000000..24aaafa3f --- /dev/null +++ b/Kernel/Abstractions/observer.cpp @@ -0,0 +1,287 @@ + +/****************************************************************************** + * MODULE : observer.cpp + * DESCRIPTION: Observers of trees + * COPYRIGHT : (C) 1999 Joris van der Hoeven + ******************************************************************************* + * This software falls under the GNU general public license version 3 or later. + * It comes WITHOUT ANY WARRANTY WHATSOEVER. For details, see the file LICENSE + * in the root directory or . + ******************************************************************************/ + +#include "blackbox.hpp" +#include "hashmap.hpp" +#include "modification.hpp" + +observer nil_observer; + +tm_ostream& +operator<< (tm_ostream& out, observer o) { + out << "print (out); + out << ">"; + return out; +} + +void +touch (tree& ref) { + // cout << "Touch " << ref << "\n"; + if (!is_nil (ref->obs)) ref->obs->touched (ref, path ()); +} + +/****************************************************************************** + * Default virtual routines + ******************************************************************************/ + +void +observer_rep::announce (tree& ref, modification mod) { + // cout << "Modify: " << mod << "\n"; + switch (mod->k) { + case MOD_ASSIGN: + announce_assign (ref, mod->p, mod->t); + break; + case MOD_INSERT: + announce_insert (ref, mod->p, mod->t); + break; + case MOD_REMOVE: + announce_remove (ref, path_up (mod->p), last_item (mod->p)); + break; + case MOD_SPLIT: + announce_split (ref, mod->p); + break; + case MOD_JOIN: + announce_join (ref, mod->p); + break; + case MOD_ASSIGN_NODE: + announce_assign_node (ref, mod->p, mod->t->op); + break; + case MOD_INSERT_NODE: + announce_insert_node (ref, mod->p, mod->t); + break; + case MOD_REMOVE_NODE: + announce_remove_node (ref, mod->p); + break; + case MOD_SET_CURSOR: + announce_set_cursor (ref, mod->p, mod->t); + break; + } +} + +void +observer_rep::done (tree& ref, modification mod) { + (void) ref; + (void) mod; +} + +void +observer_rep::touched (tree& ref, path p) { + (void) ref; + (void) p; +} + +void +observer_rep::announce_assign (tree& ref, path p, tree t) { + (void) ref; + (void) p; + (void) t; +} + +void +observer_rep::announce_insert (tree& ref, path p, tree ins) { + (void) ref; + (void) p; + (void) ins; +} + +void +observer_rep::announce_remove (tree& ref, path p, int nr) { + (void) ref; + (void) p; + (void) nr; +} + +void +observer_rep::announce_split (tree& ref, path p) { + (void) ref; + (void) p; +} + +void +observer_rep::announce_join (tree& ref, path p) { + (void) ref; + (void) p; +} + +void +observer_rep::announce_assign_node (tree& ref, path p, int op) { + (void) ref; + (void) p; + (void) op; +} + +void +observer_rep::announce_insert_node (tree& ref, path p, tree ins) { + (void) ref; + (void) p; + (void) ins; +} + +void +observer_rep::announce_remove_node (tree& ref, path p) { + (void) ref; + (void) p; +} + +void +observer_rep::announce_set_cursor (tree& ref, path p, tree data) { + (void) ref; + (void) p; + (void) data; +} + +void +observer_rep::notify_assign (tree& ref, tree t) { + (void) ref; + (void) t; +} + +void +observer_rep::notify_insert (tree& ref, int pos, int nr) { + (void) ref; + (void) pos; + (void) nr; +} + +void +observer_rep::notify_remove (tree& ref, int pos, int nr) { + (void) ref; + (void) pos; + (void) nr; +} + +void +observer_rep::notify_split (tree& ref, int pos, tree prev) { + (void) ref; + (void) pos; + (void) prev; +} + +void +observer_rep::notify_var_split (tree& ref, tree t1, tree t2) { + (void) ref; + (void) t1; + (void) t2; +} + +void +observer_rep::notify_join (tree& ref, int pos, tree next) { + (void) ref; + (void) pos; + (void) next; +} + +void +observer_rep::notify_var_join (tree& ref, tree t, int offset) { + (void) ref; + (void) t; + (void) offset; +} + +void +observer_rep::notify_assign_node (tree& ref, int op) { + (void) ref; + (void) op; +} + +void +observer_rep::notify_insert_node (tree& ref, int pos) { + (void) ref; + (void) pos; +} + +void +observer_rep::notify_remove_node (tree& ref, int pos) { + (void) ref; + (void) pos; +} + +void +observer_rep::notify_set_cursor (tree& ref, int pos, tree data) { + (void) ref; + (void) pos; + (void) data; +} + +void +observer_rep::notify_detach (tree& ref, tree closest, bool right) { + (void) ref; + (void) closest; + (void) right; +} + +bool +observer_rep::get_ip (path& ip) { + (void) ip; + return false; +} + +bool +observer_rep::set_ip (path ip) { + (void) ip; + return false; +} + +bool +observer_rep::get_position (tree& t, int& index) { + (void) t; + (void) index; + return false; +} + +bool +observer_rep::set_position (tree t, int index) { + (void) t; + (void) index; + return false; +} + +observer& +observer_rep::get_child (int which) { + (void) which; + return nil_observer; +} + +list +observer_rep::get_tree_pointers () { + return list (); +} + +bool +observer_rep::get_tree (tree& t) { + (void) t; + return false; +} + +bool +observer_rep::get_contents (int kind, blackbox& bb) { + (void) kind; + (void) bb; + return false; +} + +bool +observer_rep::set_highlight (int lan, int col, int start, int end) { + (void) col; + (void) start; + (void) end; + (void) lan; + return false; +} + +bool +observer_rep::get_highlight (int lan, array& cols) { + (void) lan; + (void) cols; + return false; +} diff --git a/Kernel/Abstractions/observer.hpp b/Kernel/Abstractions/observer.hpp new file mode 100644 index 000000000..f320907e4 --- /dev/null +++ b/Kernel/Abstractions/observer.hpp @@ -0,0 +1,114 @@ + +/****************************************************************************** + * MODULE : observer.hpp + * DESCRIPTION: Observers of trees + * COPYRIGHT : (C) 2004 Joris van der Hoeven + ******************************************************************************* + * This software falls under the GNU general public license version 3 or later. + * It comes WITHOUT ANY WARRANTY WHATSOEVER. For details, see the file LICENSE + * in the root directory or . + ******************************************************************************/ + +#ifndef OBSERVER_H +#define OBSERVER_H + +#include "string.hpp" + +class tree; +class observer; +class modification; +class blackbox; +template class list; +template class array; +typedef list path; + +#define OBSERVER_UNKNOWN 0 +#define OBSERVER_LIST 1 +#define OBSERVER_IP 2 +#define OBSERVER_POINTER 3 +#define OBSERVER_POSITION 4 +#define OBSERVER_ADDENDUM 5 +#define OBSERVER_EDIT 6 +#define OBSERVER_UNDO 7 +#define OBSERVER_HIGHLIGHT 8 +#define OBSERVER_WIDGET 9 + +#define ADDENDUM_PLAYER 1 + +/****************************************************************************** + * The observer class + ******************************************************************************/ + +extern int observer_count; +class observer_rep : public abstract_struct { +public: + inline observer_rep () { TM_DEBUG (observer_count++); } + inline virtual ~observer_rep () { TM_DEBUG (observer_count--); } + inline virtual int get_type () { return OBSERVER_UNKNOWN; } + inline virtual tm_ostream& print (tm_ostream& out) { return out; } + + // Announcing modifications in subtrees + virtual void announce (tree& ref, modification mod); + virtual void announce_assign (tree& ref, path p, tree t); + virtual void announce_insert (tree& ref, path p, tree ins); + virtual void announce_remove (tree& ref, path p, int nr); + virtual void announce_split (tree& ref, path p); + virtual void announce_join (tree& ref, path p); + virtual void announce_assign_node (tree& ref, path p, int op); + virtual void announce_insert_node (tree& ref, path p, tree ins); + virtual void announce_remove_node (tree& ref, path p); + virtual void announce_set_cursor (tree& ref, path p, tree data); + virtual void done (tree& ref, modification mod); + virtual void touched (tree& ref, path p); + + // Call back routines for tree modifications + virtual void notify_assign (tree& ref, tree t); + virtual void notify_insert (tree& ref, int pos, int nr); + virtual void notify_remove (tree& ref, int pos, int nr); + virtual void notify_split (tree& ref, int pos, tree prev); + virtual void notify_var_split (tree& ref, tree t1, tree t2); + virtual void notify_join (tree& ref, int pos, tree next); + virtual void notify_var_join (tree& ref, tree t, int offset); + virtual void notify_assign_node (tree& ref, int op); + virtual void notify_insert_node (tree& ref, int pos); + virtual void notify_remove_node (tree& ref, int pos); + virtual void notify_set_cursor (tree& ref, int pos, tree data); + virtual void notify_detach (tree& ref, tree closest, bool right); + + // Extra routines for particular types of observers + virtual bool get_ip (path& ip); + virtual bool set_ip (path ip); + virtual bool get_position (tree& t, int& index); + virtual bool set_position (tree t, int index); + virtual observer& get_child (int which); + virtual list get_tree_pointers (); + virtual bool get_tree (tree& t); + virtual bool get_contents (int kind, blackbox& bb); + virtual bool set_highlight (int lan, int col, int start, int end); + virtual bool get_highlight (int lan, array& cols); +}; + +class observer { +public: + ABSTRACT_NULL (observer); + inline friend bool operator== (observer o1, observer o2) { + return o1.rep == o2.rep; + } + inline friend bool operator!= (observer o1, observer o2) { + return o1.rep != o2.rep; + } + inline friend int hash (observer o1) { return hash ((pointer) o1.rep); } +}; +ABSTRACT_NULL_CODE (observer); + +tm_ostream& operator<< (tm_ostream& out, observer o); + +extern observer nil_observer; + +/****************************************************************************** + * Modification routines for trees and other observer-related facilities + ******************************************************************************/ + +void touch (tree& ref); + +#endif // defined OBSERVER_H diff --git a/Kernel/Types/generic_tree.hpp b/Kernel/Types/generic_tree.hpp new file mode 100644 index 000000000..147fb748e --- /dev/null +++ b/Kernel/Types/generic_tree.hpp @@ -0,0 +1,51 @@ + +/****************************************************************************** + * MODULE : generic_tree.hpp + * DESCRIPTION: generic objects as trees + * COPYRIGHT : (C) 2009 Joris van der Hoeven + ******************************************************************************* + * This software falls under the GNU general public license version 3 or later. + * It comes WITHOUT ANY WARRANTY WHATSOEVER. For details, see the file LICENSE + * in the root directory or . + ******************************************************************************/ + +#ifndef GENERIC_TREE_H +#define GENERIC_TREE_H + +#include "blackbox.hpp" + +class generic_rep : public tree_rep { +public: + blackbox data; + template + inline generic_rep (const T& x) + : tree_rep (type_helper::id), data (close_box (x)) {} + friend class tree; +}; + +inline blackbox +as_blackbox (const tree& t) { + return ((generic_rep*) t.rep)->data; +} + +template struct convert_helper { + static inline T op (const F& x) { return (T) x; } +}; + +template struct convert_helper { + static inline tree op (const F& data) { + return tree ((tree_rep*) tm_new (data)); + } +}; + +template struct convert_helper { + static inline T op (const tree& t) { return open_box (as_blackbox (t)); } +}; + +template +inline T +as (const F& t) { + return convert_helper::op (t); +} + +#endif // defined GENERIC_TREE_H diff --git a/Kernel/Types/modification.cpp b/Kernel/Types/modification.cpp new file mode 100644 index 000000000..cdd7ee496 --- /dev/null +++ b/Kernel/Types/modification.cpp @@ -0,0 +1,541 @@ + +/****************************************************************************** + * MODULE : modification.hpp + * DESCRIPTION: elementary tree modifications + * COPYRIGHT : (C) 2008 Joris van der Hoeven + ******************************************************************************* + * This software falls under the GNU general public license version 3 or later. + * It comes WITHOUT ANY WARRANTY WHATSOEVER. For details, see the file LICENSE + * in the root directory or . + ******************************************************************************/ + +#include "modification.hpp" + +static inline int +L (tree t) { + return (t->op); +} + +static int +L (modification mod) { + ASSERT (mod->k == MOD_ASSIGN_NODE, "assign_node modification expected"); + return L (mod->t); +} + +/****************************************************************************** + * Equality and Output + ******************************************************************************/ + +bool +operator== (modification m1, modification m2) { + return m1->k == m2->k && m1->p == m2->p && m1->t == m2->t; +} + +bool +operator!= (modification m1, modification m2) { + return m1->k != m2->k || m1->p != m2->p || m1->t != m2->t; +} + +tm_ostream& +operator<< (tm_ostream& out, modification mod) { + switch (mod->k) { + case MOD_ASSIGN: + return out << "assign (" << root (mod) << ", " << mod->t << ")"; + case MOD_INSERT: + return out << "insert (" << root (mod) << ", " << index (mod) << ", " + << mod->t << ")"; + case MOD_REMOVE: + return out << "remove (" << root (mod) << ", " << index (mod) << ", " + << argument (mod) << ")"; + case MOD_SPLIT: + return out << "split (" << root (mod) << ", " << index (mod) << ", " + << argument (mod) << ")"; + case MOD_JOIN: + return out << "join (" << root (mod) << ", " << index (mod) << ")"; + case MOD_ASSIGN_NODE: + return out << "assign_node (" << root (mod) << ", " << mod->t << ")"; + case MOD_INSERT_NODE: + return out << "insert_node (" << root (mod) << ", " << argument (mod) + << ", " << mod->t << ")"; + case MOD_REMOVE_NODE: + return out << "remove_node (" << root (mod) << ", " << index (mod) << ")"; + case MOD_SET_CURSOR: + return out << "set_cursor (" << root (mod) << ", " << index (mod) << ", " + << mod->t << ")"; + default: + TM_FAILED ("invalid modification type"); + return out; + } +} + +/****************************************************************************** + * Accessors + ******************************************************************************/ + +path +root (modification mod) { + switch (mod->k) { + case MOD_ASSIGN: + return mod->p; + case MOD_INSERT: + return path_up (mod->p); + case MOD_REMOVE: + return path_up (path_up (mod->p)); + case MOD_SPLIT: + return path_up (path_up (mod->p)); + case MOD_JOIN: + return path_up (mod->p); + case MOD_ASSIGN_NODE: + return mod->p; + case MOD_INSERT_NODE: + return path_up (mod->p); + case MOD_REMOVE_NODE: + return path_up (mod->p); + case MOD_SET_CURSOR: + return path_up (mod->p); + default: + TM_FAILED ("invalid modification type"); + } + return path (); +} + +int +index (modification mod) { + switch (mod->k) { + case MOD_INSERT: + return last_item (mod->p); + case MOD_REMOVE: + return last_item (path_up (mod->p)); + case MOD_SPLIT: + return last_item (path_up (mod->p)); + case MOD_JOIN: + return last_item (mod->p); + case MOD_REMOVE_NODE: + return last_item (mod->p); + case MOD_SET_CURSOR: + return last_item (mod->p); + default: + TM_FAILED ("invalid modification type"); + } + return 0; +} + +int +argument (modification mod) { + switch (mod->k) { + case MOD_REMOVE: + return last_item (mod->p); + case MOD_SPLIT: + return last_item (mod->p); + case MOD_INSERT_NODE: + return last_item (mod->p); + default: + TM_FAILED ("invalid modification type"); + } + return 0; +} + +/****************************************************************************** + * Constructor and accessors for scheme interface + ******************************************************************************/ + +modification +make_modification (string s, path p, tree t) { + modification_type k= MOD_ASSIGN; + if (s == "assign") k= MOD_ASSIGN; + else if (s == "insert") k= MOD_INSERT; + else if (s == "remove") k= MOD_REMOVE; + else if (s == "split") k= MOD_SPLIT; + else if (s == "join") k= MOD_JOIN; + else if (s == "assign-node") k= MOD_ASSIGN_NODE; + else if (s == "insert-node") k= MOD_INSERT_NODE; + else if (s == "remove-node") k= MOD_REMOVE_NODE; + else if (s == "set-cursor") k= MOD_SET_CURSOR; + return modification (k, p, t); +} + +string +get_type (modification mod) { + switch (mod->k) { + case MOD_ASSIGN: + return "assign"; + case MOD_INSERT: + return "insert"; + case MOD_REMOVE: + return "remove"; + case MOD_SPLIT: + return "split"; + case MOD_JOIN: + return "join"; + case MOD_ASSIGN_NODE: + return "assign-node"; + case MOD_INSERT_NODE: + return "insert-node"; + case MOD_REMOVE_NODE: + return "remove-node"; + case MOD_SET_CURSOR: + return "set-cursor"; + default: + TM_FAILED ("invalid modification type"); + } + return "none"; +} + +path +get_path (modification mod) { + return mod->p; +} + +tree +get_tree (modification mod) { + return mod->t; +} + +/****************************************************************************** + * Test applicability of modifications + ******************************************************************************/ + +bool +can_assign (tree t, path p, tree u) { + (void) u; + return has_subtree (t, p); +} + +bool +can_insert (tree t, path p, int pos, tree u) { + if (!has_subtree (t, p)) return false; + tree st= subtree (t, p); + if (is_atomic (st)) return pos >= 0 && pos <= N (st->label) && is_atomic (u); + else return pos >= 0 && pos <= N (st) && is_compound (u); +} + +bool +can_remove (tree t, path p, int pos, int nr) { + if (!has_subtree (t, p)) return false; + tree st= subtree (t, p); + if (is_atomic (st)) return pos >= 0 && pos + nr <= N (st->label); + else return pos >= 0 && pos + nr <= N (st); +} + +bool +can_split (tree t, path p, int pos, int at) { + if (!has_subtree (t, p * pos)) return false; + tree st= subtree (t, p * pos); + if (is_atomic (st)) return at >= 0 && at <= N (st->label); + else return at >= 0 && at <= N (st); +} + +bool +can_join (tree t, path p, int pos) { + if (!has_subtree (t, p)) return false; + tree st= subtree (t, p); + if (pos < 0 || pos + 1 >= N (st)) return false; + if (is_atomic (st[pos]) && is_atomic (st[pos + 1])) return true; + if (is_compound (st[pos]) && is_compound (st[pos + 1])) return true; + return false; +} + +bool +can_assign_node (tree t, path p, int op) { + (void) op; + return has_subtree (t, p) && is_compound (subtree (t, p)); +} + +bool +can_insert_node (tree t, path p, int pos, tree u) { + return has_subtree (t, p) && is_compound (u) && pos >= 0 && pos <= N (u); +} + +bool +can_remove_node (tree t, path p, int pos) { + return has_subtree (t, p * pos); +} + +bool +can_set_cursor (tree t, path p, int pos, tree data) { + (void) data; + if (!has_subtree (t, p)) return false; + return pos >= 0 && pos <= right_index (subtree (t, p)); +} + +bool +is_applicable (tree t, modification mod) { + switch (mod->k) { + case MOD_ASSIGN: + return can_assign (t, root (mod), mod->t); + case MOD_INSERT: + return can_insert (t, root (mod), index (mod), mod->t); + case MOD_REMOVE: + return can_remove (t, root (mod), index (mod), argument (mod)); + case MOD_SPLIT: + return can_split (t, root (mod), index (mod), argument (mod)); + case MOD_JOIN: + return can_join (t, root (mod), index (mod)); + case MOD_ASSIGN_NODE: + return can_assign_node (t, root (mod), L (mod)); + case MOD_INSERT_NODE: + return can_insert_node (t, root (mod), argument (mod), mod->t); + case MOD_REMOVE_NODE: + return can_remove_node (t, root (mod), index (mod)); + case MOD_SET_CURSOR: + return can_set_cursor (t, root (mod), index (mod), mod->t); + default: + return false; + } +} + +/****************************************************************************** + * Functional application of modifications + ******************************************************************************/ + +tree +clean_assign (tree t, path p, tree u) { + if (is_nil (p)) return copy (u); + else { + int i, j= p->item, n= N (t); + if (j >= n) + TM_FAILED ("clean_remove(): Invalid path."); // return copy(u); // FIXME? + // check whether this is the + // right return value. + tree r (t, n); + for (i= 0; i < j; i++) + r[i]= t[i]; + r[j]= clean_assign (t[j], p->next, u); + for (i++; i < n; i++) + r[i]= t[i]; + return r; + } +} + +tree +clean_insert (tree t, path p, tree u) { + if (is_nil (p->next) && is_atomic (t)) { + string s= t->label; + return s (0, p->item) * u->label * s (p->item, N (s)); + } + else if (is_nil (p->next)) { + int i, j= p->item, n= N (t), nr= N (u); + tree r (t, n + nr); + for (i= 0; i < j; i++) + r[i]= t[i]; + for (; i < n; i++) + r[i + nr]= t[i]; + for (i= 0; i < nr; i++) + r[j + i]= copy (u[i]); + return r; + } + else { + int i, j= p->item, n= N (t); + tree r (t, n); + for (i= 0; i < j; i++) + r[i]= t[i]; + r[j]= clean_insert (t[j], p->next, u); + for (i++; i < n; i++) + r[i]= t[i]; + return r; + } +} + +tree +clean_remove (tree t, path p, int nr) { + if (is_nil (p->next) && is_atomic (t)) { + string s= t->label; + if (N (s) < p->item + nr) + TM_FAILED ("clean_remove: Invalid remove from atomic tree"); + return s (0, p->item) * s (p->item + nr, N (s)); + } + else if (is_nil (p->next)) { + int i, j= p->item, n= N (t); + tree r (t, n - nr); + for (i= 0; i < j; i++) + r[i]= t[i]; + for (i+= nr; i < n; i++) + r[i - nr]= t[i]; + return r; + } + else { + int i, j= p->item, n= N (t); + if (j >= n) + TM_FAILED ( + "clean_remove: Invalid path"); // return t; // FIXME? check whether + // this is the right return value. + tree r (t, n); + for (i= 0; i < j; i++) + r[i]= t[i]; + r[j]= clean_remove (t[j], p->next, nr); + for (i++; i < n; i++) + r[i]= t[i]; + return r; + } +} + +tree +clean_split (tree t, path p) { + if (is_nil (p->next->next)) { + tree u= t[p->item]; + int i, n1= p->next->item, n2= N (u) - n1; + tree s1, s2; + if (is_atomic (u)) { + s1= u->label (0, n1); + s2= u->label (n1, N (u->label)); + } + else { + s1= tree (u, n1); + s2= tree (u, n2); + for (i= 0; i < n1; i++) + s1[i]= u[i]; + for (i= 0; i < n2; i++) + s2[i]= u[n1 + i]; + } + + int j= p->item, n= N (t); + tree r (t, n + 1); + for (i= 0; i < j; i++) + r[i]= t[i]; + r[j] = s1; + r[j + 1]= s2; + for (i++; i < n; i++) + r[i + 1]= t[i]; + return r; + } + else { + int i, j= p->item, n= N (t); + tree r (t, n); + for (i= 0; i < j; i++) + r[i]= t[i]; + r[j]= clean_split (t[j], p->next); + for (i++; i < n; i++) + r[i]= t[i]; + return r; + } +} + +tree +clean_join (tree t, path p) { + if (is_nil (p->next)) { + int i, j= p->item; + tree s1= t[j], s2= t[j + 1], u; + if (is_atomic (s1)) u= tree (s1->label * s2->label); + else { + int n1= N (s1), n2= N (s2); + u= tree (s1, n1 + n2); + for (i= 0; i < n1; i++) + u[i]= s1[i]; + for (i= 0; i < n2; i++) + u[n1 + i]= s2[i]; + } + + int n= N (t); + tree r (t, n - 1); + for (i= 0; i < j; i++) + r[i]= t[i]; + r[j]= u; + for (i+= 2; i < n; i++) + r[i - 1]= t[i]; + return r; + } + else { + int i, j= p->item, n= N (t); + tree r (t, n); + for (i= 0; i < j; i++) + r[i]= t[i]; + r[j]= clean_join (t[j], p->next); + for (i++; i < n; i++) + r[i]= t[i]; + return r; + } +} + +tree +clean_assign_node (tree t, path p, int op) { + if (is_nil (p)) { + int i, n= N (t); + tree r (op, n); + for (i= 0; i < n; i++) + r[i]= t[i]; + return r; + } + else { + int i, j= p->item, n= N (t); + tree r (t, n); + for (i= 0; i < j; i++) + r[i]= t[i]; + r[j]= clean_assign_node (t[j], p->next, op); + for (i++; i < n; i++) + r[i]= t[i]; + return r; + } +} + +tree +clean_insert_node (tree t, path p, tree u) { + if (is_nil (p->next)) { + int i, j= p->item, n= N (u); + tree r (u, n + 1); + for (i= 0; i < j; i++) + r[i]= u[i]; + r[j]= t; + for (; i < n; i++) + r[i + 1]= u[i]; + return r; + } + else { + int i, j= p->item, n= N (t); + tree r (t, n); + for (i= 0; i < j; i++) + r[i]= t[i]; + r[j]= clean_insert_node (t[j], p->next, u); + for (i++; i < n; i++) + r[i]= t[i]; + return r; + } +} + +tree +clean_remove_node (tree t, path p) { + if (is_nil (p->next)) return t[p->item]; + else { + int i, j= p->item, n= N (t); + tree r (t, n); + for (i= 0; i < j; i++) + r[i]= t[i]; + r[j]= clean_remove_node (t[j], p->next); + for (i++; i < n; i++) + r[i]= t[i]; + return r; + } +} + +tree +clean_set_cursor (tree t, path p, tree data) { + (void) p; + (void) data; + return t; +} + +tree +clean_apply (tree t, modification mod) { + switch (mod->k) { + case MOD_ASSIGN: + return clean_assign (t, mod->p, mod->t); + case MOD_INSERT: + return clean_insert (t, mod->p, mod->t); + case MOD_REMOVE: + return clean_remove (t, path_up (mod->p), last_item (mod->p)); + case MOD_SPLIT: + return clean_split (t, mod->p); + case MOD_JOIN: + return clean_join (t, mod->p); + case MOD_ASSIGN_NODE: + return clean_assign_node (t, mod->p, L (mod)); + case MOD_INSERT_NODE: + return clean_insert_node (t, mod->p, mod->t); + case MOD_REMOVE_NODE: + return clean_remove_node (t, mod->p); + case MOD_SET_CURSOR: + return clean_set_cursor (t, mod->p, mod->t); + default: + TM_FAILED ("invalid modification type"); + return ""; + } +} diff --git a/Kernel/Types/modification.hpp b/Kernel/Types/modification.hpp new file mode 100644 index 000000000..9f7284e1e --- /dev/null +++ b/Kernel/Types/modification.hpp @@ -0,0 +1,147 @@ + +/****************************************************************************** + * MODULE : modification.hpp + * DESCRIPTION: elementary tree modifications + * COPYRIGHT : (C) 2008 Joris van der Hoeven + ******************************************************************************* + * This software falls under the GNU general public license version 3 or later. + * It comes WITHOUT ANY WARRANTY WHATSOEVER. For details, see the file LICENSE + * in the root directory or . + ******************************************************************************/ + +#ifndef MODIFICATION_H +#define MODIFICATION_H + +#include "path.hpp" + +/****************************************************************************** + * Elementary tree modifications + ******************************************************************************/ + +#define MOD_ASSIGN 1 +#define MOD_INSERT 2 +#define MOD_REMOVE 3 +#define MOD_SPLIT 4 +#define MOD_JOIN 5 +#define MOD_ASSIGN_NODE 6 +#define MOD_INSERT_NODE 7 +#define MOD_REMOVE_NODE 8 +#define MOD_SET_CURSOR 9 + +/****************************************************************************** + * The modification class + ******************************************************************************/ + +typedef int modification_type; +class modification; + +class modification_rep : concrete_struct { +public: + modification_type k; + path p; + tree t; + +public: + inline modification_rep (modification_type k2, path p2) : k (k2), p (p2) {} + inline modification_rep (modification_type k2, path p2, tree t2) + : k (k2), p (p2), t (t2) {} + inline ~modification_rep () {} + friend class modification; +}; + +class modification { + CONCRETE (modification); + inline modification (modification_type k, path p) + : rep (tm_new (k, p)) {} + inline modification (modification_type k, path p, tree t) + : rep (tm_new (k, p, t)) {} +}; +CONCRETE_CODE (modification); + +bool operator== (modification m1, modification m2); +bool operator!= (modification m1, modification m2); +tm_ostream& operator<< (tm_ostream& out, modification mod); + +/****************************************************************************** + * Constructors and accessors + ******************************************************************************/ + +inline modification +mod_assign (path p, tree t) { + return modification (MOD_ASSIGN, p, t); +} +inline modification +mod_insert (path p, int pos, tree t) { + return modification (MOD_INSERT, p * pos, t); +} +inline modification +mod_remove (path p, int pos, int nr) { + return modification (MOD_REMOVE, p * path (pos, nr)); +} +inline modification +mod_split (path p, int pos, int at) { + return modification (MOD_SPLIT, p * path (pos, at)); +} +inline modification +mod_join (path p, int pos) { + return modification (MOD_JOIN, p * pos); +} +inline modification +mod_assign_node (path p, int lab) { + return modification (MOD_ASSIGN_NODE, p, tree (lab)); +} +inline modification +mod_insert_node (path p, int pos, tree t) { + return modification (MOD_INSERT_NODE, p * pos, t); +} +inline modification +mod_remove_node (path p, int pos) { + return modification (MOD_REMOVE_NODE, p * pos); +} +inline modification +mod_set_cursor (path p, int pos, tree data) { + return modification (MOD_SET_CURSOR, p * pos, data); +} +inline modification +operator* (int i, modification mod) { + return modification (mod->k, path (i, mod->p), mod->t); +} +inline modification +operator* (path p, modification mod) { + return modification (mod->k, p * mod->p, mod->t); +} +inline modification +operator* (modification mod, int i) { + return modification (mod->k, mod->p * i, mod->t); +} +inline modification +operator/ (modification mod, path p) { + return modification (mod->k, mod->p / p, mod->t); +} +inline modification +copy (modification mod) { + return modification (mod->k, copy (mod->p), copy (mod->t)); +} + +path root (modification mod); +int index (modification mod); +int argument (modification mod); + +modification make_modification (string k, path p, tree t); +string get_type (modification mod); +path get_path (modification mod); +tree get_tree (modification mod); + +/****************************************************************************** + * Further routines on modifications + ******************************************************************************/ + +bool is_applicable (tree t, modification mod); +tree clean_apply (tree t, modification mod); +void raw_apply (tree& t, modification mod); // in observer.cpp + +/****************************************************************************** + * Hooks + ******************************************************************************/ + +#endif // defined MODIFICATION_H diff --git a/Kernel/Types/path.cpp b/Kernel/Types/path.cpp new file mode 100644 index 000000000..d68cb461e --- /dev/null +++ b/Kernel/Types/path.cpp @@ -0,0 +1,173 @@ + +/****************************************************************************** + * MODULE : path.cpp + * DESCRIPTION: paths are integer lists, + * which are for instance useful to select subtrees in trees + * COPYRIGHT : (C) 1999 Joris van der Hoeven + ******************************************************************************* + * This software falls under the GNU general public license version 3 or later. + * It comes WITHOUT ANY WARRANTY WHATSOEVER. For details, see the file LICENSE + * in the root directory or . + ******************************************************************************/ + +#include "path.hpp" +#include "analyze.hpp" +#include "tree.hpp" + +/****************************************************************************** + * General routines on paths + ******************************************************************************/ + +bool +zero_path (path p) { + if (is_nil (p)) return true; + return (p->item == 0) && zero_path (p->next); +} + +int +hash (path p) { + if (is_nil (p)) return 0; + else { + int h= hash (p->next); + return p->item ^ ((h << 7) + (h >> 25)); + } +} + +string +as_string (path p) { + if (is_nil (p)) return ""; + if (is_atom (p)) return as_string (p->item); + return as_string (p->item) * "." * as_string (p->next); +} + +path +as_path (string s) { + int i, j, n= N (s); + for (i= 0; i < n; i++) + if (is_digit (s[i])) break; + if (i == n) return path (); + for (j= i; j < n; j++) + if (!is_digit (s[j])) break; + return path (as_int (s (i, j)), as_path (s (j, n))); +} + +bool +version_inf_eq (string v1, string v2) { + if (starts (v2, v1)) return true; + return path_inf_eq (as_path (v1), as_path (v2)); +} + +bool +version_inf (string v1, string v2) { + if (v1 == v2) return false; + return version_inf_eq (v1, v2); +} + +/****************************************************************************** + * Operations on paths + ******************************************************************************/ + +path +path_add (path p, int plus) { + if (is_atom (p)) return path (p->item + plus); + return path (p->item, path_add (p->next, plus)); +} + +path +path_add (path p, int plus, int pos) { + p= copy (p); + p[pos]+= plus; + return p; +} + +path +path_up (path p) { + ASSERT (!is_nil (p), "path is too short"); + if (is_nil (p->next)) return path (); + return path (p->item, path_up (p->next)); +} + +path +path_up (path p, int times) { + return head (p, N (p) - times); +} + +bool +path_inf (path p1, path p2) { + if (is_nil (p1) || is_nil (p2)) return false; + if (p1->item < p2->item) return true; + if (p1->item > p2->item) return false; + return path_inf (p1->next, p2->next); +} + +bool +path_inf_eq (path p1, path p2) { + if (is_nil (p1) || is_nil (p2)) return (p1 == p2); + if (p1->item < p2->item) return true; + if (p1->item > p2->item) return false; + return path_inf_eq (p1->next, p2->next); +} + +bool +path_less (path p1, path p2) { + return path_less_eq (p1, p2) && (p1 != p2); +} + +bool +path_less_eq (path p1, path p2) { + if (is_nil (p1) || is_nil (p2)) return p1 == p2; + if (is_atom (p1) || is_atom (p2)) { + if (is_atom (p1) && is_atom (p2)) return p1->item <= p2->item; + if ((p1->item == 0) && is_nil (p1->next)) return true; + if ((p2->item == 1) && is_nil (p2->next)) return true; + return false; + } + if (p1->item < p2->item) return true; + if (p1->item > p2->item) return false; + return path_less_eq (p1->next, p2->next); +} + +path +operator/ (path p, path q) { + if (is_nil (q)) return p; + else if (is_nil (p) || (p->item != q->item)) { + TM_FAILED ("path did not start with required path"); + } + else return p->next / q->next; + return path (); // NOT REACHED +} + +path +common (path start, path end) { + if (is_nil (start) || is_nil (end)) return path (); + if (start->item != end->item) return path (); + return path (start->item, common (start->next, end->next)); +} + +/****************************************************************************** + * Main modification routines + ******************************************************************************/ + +bool +has_subtree (tree t, path p) { + if (is_nil (p)) return true; + int i= p->item; + return is_compound (t) && i >= 0 && i < N (t) && has_subtree (t[i], p->next); +} + +tree& +subtree (tree& t, path p) { + if (is_nil (p)) return t; + else if (N (t) > p->item) return subtree (t[p->item], p->next); + else { + cout << "The required path does not exist\n"; + return t; + } +} + +tree& +parent_subtree (tree& t, path p) { + ASSERT (!is_nil (p), "path too short"); + if (is_nil (p->next)) return t; + else return parent_subtree (t[p->item], p->next); +} diff --git a/Kernel/Types/path.hpp b/Kernel/Types/path.hpp new file mode 100644 index 000000000..77f0d7746 --- /dev/null +++ b/Kernel/Types/path.hpp @@ -0,0 +1,60 @@ + +/****************************************************************************** + * MODULE : path.hpp + * DESCRIPTION: paths are integer lists, + * which are for instance useful to select subtrees in trees + * COPYRIGHT : (C) 1999 Joris van der Hoeven + ******************************************************************************* + * This software falls under the GNU general public license version 3 or later. + * It comes WITHOUT ANY WARRANTY WHATSOEVER. For details, see the file LICENSE + * in the root directory or . + ******************************************************************************/ + +#ifndef PATH_H +#define PATH_H + +#include "list.hpp" +#include "tree.hpp" +typedef list path; + +/****************************************************************************** + * General routines + ******************************************************************************/ + +bool zero_path (path p); +int hash (path p); +string as_string (path p); +path as_path (string s); +bool version_inf_eq (string v1, string v2); +bool version_inf (string v1, string v2); + +/****************************************************************************** + * Operations on paths + ******************************************************************************/ + +path path_up (path p); +path path_up (path p, int times); +bool path_inf (path p1, path p2); +bool path_inf_eq (path p1, path p2); +bool path_less (path p1, path p2); +bool path_less_eq (path p1, path p2); +path path_add (path p, int plus); +path path_add (path p, int plus, int pos); +#define path_inc(p) path_add (p, 1) +#define path_dec(p) path_add (p, -1) +path operator/ (path p, path q); +path common (path start, path end); +inline path +strip (path p, path q) { + return p / q; +} + +/****************************************************************************** + * Getting subtrees from paths + ******************************************************************************/ + +bool has_subtree (tree t, path p); +tree& subtree (tree& t, path p); +tree& parent_subtree (tree& t, path p); + +#endif // defined PATH_H diff --git a/Kernel/Types/tree.cpp b/Kernel/Types/tree.cpp new file mode 100644 index 000000000..96ac9bfe3 --- /dev/null +++ b/Kernel/Types/tree.cpp @@ -0,0 +1,205 @@ + +/****************************************************************************** + * MODULE : tree.cpp + * DESCRIPTION: fixed size trees with reference counting + * COPYRIGHT : (C) 1999 Joris van der Hoeven + ******************************************************************************* + * This software falls under the GNU general public license version 3 or later. + * It comes WITHOUT ANY WARRANTY WHATSOEVER. For details, see the file LICENSE + * in the root directory or . + ******************************************************************************/ + +#include "tree.hpp" +#include "generic_tree.hpp" +#include "hashset.hpp" +#include "iterator.hpp" + +/****************************************************************************** + * Main routines for trees + ******************************************************************************/ + +int type_helper::id= new_type_identifier (); + +void +destroy_tree_rep (tree_rep* rep) { + if (((int) rep->op) == 0) tm_delete (static_cast (rep)); + else if (((int) rep->op) > 0) tm_delete (static_cast (rep)); + else tm_delete (static_cast (rep)); +} + +tree::tree (int l, tree t1) : rep (tm_new (l, array (1))) { + (static_cast (rep))->a[0]= t1; +} + +tree::tree (int l, tree t1, tree t2) + : rep (tm_new (l, array (2))) { + (static_cast (rep))->a[0]= t1; + (static_cast (rep))->a[1]= t2; +} + +tree::tree (int l, tree t1, tree t2, tree t3) + : rep (tm_new (l, array (3))) { + (static_cast (rep))->a[0]= t1; + (static_cast (rep))->a[1]= t2; + (static_cast (rep))->a[2]= t3; +} + +tree::tree (int l, tree t1, tree t2, tree t3, tree t4) + : rep (tm_new (l, array (4))) { + (static_cast (rep))->a[0]= t1; + (static_cast (rep))->a[1]= t2; + (static_cast (rep))->a[2]= t3; + (static_cast (rep))->a[3]= t4; +} + +tree::tree (int l, tree t1, tree t2, tree t3, tree t4, tree t5) + : rep (tm_new (l, array (5))) { + (static_cast (rep))->a[0]= t1; + (static_cast (rep))->a[1]= t2; + (static_cast (rep))->a[2]= t3; + (static_cast (rep))->a[3]= t4; + (static_cast (rep))->a[4]= t5; +} + +tree::tree (int l, tree t1, tree t2, tree t3, tree t4, tree t5, tree t6) + : rep (tm_new (l, array (6))) { + (static_cast (rep))->a[0]= t1; + (static_cast (rep))->a[1]= t2; + (static_cast (rep))->a[2]= t3; + (static_cast (rep))->a[3]= t4; + (static_cast (rep))->a[4]= t5; + (static_cast (rep))->a[5]= t6; +} + +tree::tree (int l, tree t1, tree t2, tree t3, tree t4, tree t5, tree t6, + tree t7) + : rep (tm_new (l, array (7))) { + (static_cast (rep))->a[0]= t1; + (static_cast (rep))->a[1]= t2; + (static_cast (rep))->a[2]= t3; + (static_cast (rep))->a[3]= t4; + (static_cast (rep))->a[4]= t5; + (static_cast (rep))->a[5]= t6; + (static_cast (rep))->a[6]= t7; +} + +tree::tree (int l, tree t1, tree t2, tree t3, tree t4, tree t5, tree t6, + tree t7, tree t8) + : rep (tm_new (l, array (8))) { + (static_cast (rep))->a[0]= t1; + (static_cast (rep))->a[1]= t2; + (static_cast (rep))->a[2]= t3; + (static_cast (rep))->a[3]= t4; + (static_cast (rep))->a[4]= t5; + (static_cast (rep))->a[5]= t6; + (static_cast (rep))->a[6]= t7; + (static_cast (rep))->a[7]= t8; +} + +tree +tree::operator() (int begin, int end) { + int i; + tree r (rep->op, end - begin); + for (i= begin; i < end; i++) + r[i - begin]= (static_cast (rep))->a[i]; + return r; +} + +bool +operator== (tree t, tree u) { + if (strong_equal (t, u)) return true; + return (t->op == u->op) && + (is_atomic (t) ? (t->label == u->label) : (A (t) == A (u))); +} + +bool +operator!= (tree t, tree u) { + if (strong_equal (t, u)) return false; + return (t->op != u->op) || + (is_atomic (t) ? (t->label != u->label) : (A (t) != A (u))); +} + +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 t1, tree t2) { + int i; + if (is_atomic (t1)) t1= tree (t2->op, t1); + if (is_atomic (t2)) t2= tree (t1->op, t2); + tree r (t1, N (t1) + N (t2)); + for (i= 0; i < N (t1); i++) + r[i]= t1[i]; + for (i= 0; i < N (t2); i++) + r[i + N (t1)]= t2[i]; + return r; +} + +tree& +operator<< (tree& t, tree t2) { + CHECK_COMPOUND (t); + (static_cast (t.rep))->a << t2; + return t; +} + +tree& +operator<< (tree& t, array a) { + CHECK_COMPOUND (t); + (static_cast (t.rep))->a << a; + return t; +} + +tm_ostream& +operator<< (tm_ostream& out, tree t) { + if (is_atomic (t)) return out << t->label; + else if (is_compound (t)) { + int i, n= N (t); + out << as_string (t->op); + if (n == 0) return out << "()"; + out << " ("; + for (i= 0; i < n - 1; i++) + out << t[i] << ", "; + out << t[i] << ")"; + return out; + } + else out << as_blackbox (t); + return out; +} + +int +hash (array a) { + 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 t->op ^ hash (A (t)); +} + +tree +replace (tree t, tree w, tree b) { + if (t == w) return b; + else if (is_atomic (t)) return t; + else { + int i, n= N (t); + tree r (t, n); + for (i= 0; i < n; i++) + r[i]= replace (t[i], w, b); + return r; + } +} diff --git a/Kernel/Types/tree.hpp b/Kernel/Types/tree.hpp new file mode 100644 index 000000000..591afa48b --- /dev/null +++ b/Kernel/Types/tree.hpp @@ -0,0 +1,338 @@ + +/****************************************************************************** + * MODULE : tree.hpp + * DESCRIPTION: fixed size trees with reference counting + * COPYRIGHT : (C) 1999 Joris van der Hoeven + ******************************************************************************* + * This software falls under the GNU general public license version 3 or later. + * It comes WITHOUT ANY WARRANTY WHATSOEVER. For details, see the file LICENSE + * in the root directory or . + ******************************************************************************/ + +#ifndef TREE_H +#define TREE_H + +#include "array.hpp" +#include "iterator.hpp" +#include "merge_sort.hpp" +#include "observer.hpp" +#include "string.hpp" + +/****************************************************************************** + * The tree class 'tree' + ******************************************************************************/ + +class tree; +class tree_rep; +class atomic_rep; +class compound_rep; +class generic_rep; +class blackbox; +template class iterator; +template class hashset; +template class hashmap; +template class hashentry; + +tree copy (tree t); + +class tree { + tree_rep* rep; // can be atomic or compound or generic + +public: + inline tree (tree_rep* rep2); + inline tree (const tree& x); + inline ~tree (); + inline atomic_rep* operator->(); + inline tree& operator= (tree x); + + inline tree (); + inline tree (string l); + inline tree (const char* l); + inline tree (int l, int n= 0); + inline tree (int l, array a); + inline tree (tree t, int n); + tree (int l, tree t1); + tree (int l, tree t1, tree t2); + tree (int l, tree t1, tree t2, tree t3); + tree (int l, tree t1, tree t2, tree t3, tree t4); + tree (int l, tree t1, tree t2, tree t3, tree t4, tree t5); + tree (int l, tree t1, tree t2, tree t3, tree t4, tree t5, tree t6); + tree (int l, tree t1, tree t2, tree t3, tree t4, tree t5, tree t6, tree t7); + tree (int l, tree t1, tree t2, tree t3, tree t4, tree t5, tree t6, tree t7, + tree t8); + 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 array A (tree t); + friend inline array& AR (tree t); + friend inline bool is_atomic (tree t); + friend inline bool is_compound (tree t); + friend inline bool is_generic (tree t); + friend inline bool operator== (tree t, int lab); + friend inline bool operator!= (tree t, int lab); + friend inline bool operator== (tree t, string s); + friend inline bool operator!= (tree t, string s); + friend inline bool operator== (tree t, const char* s); + friend inline bool operator!= (tree t, const char* s); + friend inline tree_rep* inside (tree t); + friend inline bool strong_equal (tree t, tree u); + friend inline bool is_func (tree t, int l); + friend inline bool is_func (tree t, int 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 a); + friend tm_ostream& operator<< (tm_ostream& out, tree t); + friend tree operator* (tree t1, tree t2); + friend list as_trees (list l); + friend blackbox as_blackbox (const tree& t); +}; + +class tree_rep : concrete_struct { +public: + int op; + observer obs; + inline tree_rep (int op2) : op (op2) {} + friend class tree; +}; + +class atomic_rep : public tree_rep { +public: + string label; + inline atomic_rep (string l) : tree_rep (/*STRING*/ 0), label (l) {} + friend class tree; +}; + +class compound_rep : public tree_rep { +public: + array a; + inline compound_rep (int l, array a2) : tree_rep (l), a (a2) {} + friend class tree; +}; + +// generic_rep in generic_tree.hpp + +typedef tree scheme_tree; + +/****************************************************************************** + * Routines for trees + ******************************************************************************/ + +#ifdef debug_trees +#define CHECK_ATOMIC(t) \ + if (((t).rep)->op != /*STRING*/ 0) { \ + failed_error << "The tree : " << (t) << "\n"; \ + TM_FAILED ("atomic tree expected"); \ + } +#define CHECK_COMPOUND(t) \ + if (((t).rep)->op == /*STRING*/) { \ + failed_error << "The tree : " << (t) << "\n"; \ + TM_FAILED ("compound tree expected"); \ + } +#else +#define CHECK_ATOMIC(t) +#define CHECK_COMPOUND(t) +#endif + +void destroy_tree_rep (tree_rep* rep); +inline tree::tree (tree_rep* rep2) : rep (rep2) { rep->ref_count++; } +inline tree::tree (const tree& x) : rep (x.rep) { rep->ref_count++; } +inline tree::~tree () { + if ((--rep->ref_count) == 0) { + destroy_tree_rep (rep); + rep= NULL; + } +} +inline atomic_rep* +tree::operator->() { + CHECK_ATOMIC (*this); + return static_cast (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 (tm_new (string ())) {} +inline tree::tree (const char* s) : rep (tm_new (s)) {} +inline tree::tree (string s) : rep (tm_new (s)) {} +inline tree::tree (int l, int n) + : rep (tm_new (l, array (n))) {} +inline tree::tree (int l, array a) : rep (tm_new (l, a)) {} +inline tree::tree (tree t, int n) + : rep (tm_new (t.rep->op, array (n))) { + CHECK_COMPOUND (t); +} + +inline tree& +tree::operator[] (int i) { + CHECK_COMPOUND (*this); + return (static_cast (rep))->a[i]; +} +inline int +N (tree t) { + CHECK_COMPOUND (t); + return N ((static_cast (t.rep))->a); +} +inline int +arity (tree t) { + if (t.rep->op == /*STRING*/ 0) return 0; + else return N ((static_cast (t.rep))->a); +} +inline int +right_index (tree t) { + return is_atomic (t) ? N (t->label) : 1; +} +inline array +A (tree t) { + CHECK_COMPOUND (t); + return (static_cast (t.rep))->a; +} +inline array& +AR (tree t) { + CHECK_COMPOUND (t); + return (static_cast (t.rep))->a; +} + +inline bool +is_atomic (tree t) { + return (((int) t.rep->op) == 0); +} +inline bool +is_compound (tree t) { + return (((int) t.rep->op) > /*STRING*/ 0); +} +inline bool +is_generic (tree t) { + return ((int) t.rep->op) < 0; +} +inline bool +operator== (tree t, int lab) { + return (t.rep->op == lab) && (N (t) == 0); +} +inline bool +operator!= (tree t, int lab) { + return (t.rep->op != lab) || (N (t) != 0); +} +inline bool +operator== (tree t, string s) { + return (t.rep->op == /*STRING*/ 0) && (t->label == s); +} +inline bool +operator!= (tree t, string s) { + return (t.rep->op != /*STRING*/ 0) || (t->label != s); +} +inline bool +operator== (tree t, const char* s) { + return (t.rep->op == /*STRING*/ 0) && (t->label == s); +} +inline bool +operator!= (tree t, const char* s) { + return (t.rep->op != /*STRING*/ 0) || (t->label != s); +} +inline tree_rep* +inside (tree t) { + return t.rep; +} +inline bool +strong_equal (tree t, tree u) { + return t.rep == u.rep; +} + +inline bool +is_func (tree t, int l) { + return (t.rep->op == l) && (N (t) != 0); +} +inline bool +is_func (tree t, int 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 long int +as_long_int (tree t) { + if (is_atomic (t)) return as_long_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 replace (tree t, tree w, tree b); + +/****************************************************************************** + * Miscellaneous + ******************************************************************************/ + +tree correct (tree t); +int hash (tree t); + +class formatted { +public: + tree rep; + inline formatted (tree t) : rep (t) {} + inline formatted (const formatted& f) : rep (f.rep) {} +}; + +struct less_eq_associate { + static inline bool leq (tree& a, tree& b) { + return as_string (a[0]) <= as_string (b[0]); + } +}; + +template +static tree +make_collection (hashmap h) { + tree t= as_tree (h); + array a= A (t); + merge_sort_leq (a); + int i, n= N (a); + for (i= 0; i < n; i++) + t[i]= a[i]; + return t; +} + +template <> struct type_helper { + static int id; + static inline tree init_val () { return tree (); } +}; + +#endif // defined TREE_H diff --git a/bin/format b/bin/format index bf83c12f3..3412fcea6 100755 --- a/bin/format +++ b/bin/format @@ -9,6 +9,9 @@ if (eq $platform:os windows) { ~/scoop/apps/llvm/current/bin ] } elif (eq $platform:os linux) { + set paths = [ + /usr/lib/llvm-16/bin + ] } else { }