Back to index

texmacs  1.0.7.15
drd_info.cpp
Go to the documentation of this file.
00001 
00002 /******************************************************************************
00003 * MODULE     : drd_info.cpp
00004 * DESCRIPTION: data relation descriptions
00005 * COPYRIGHT  : (C) 2003  Joris van der Hoeven
00006 *******************************************************************************
00007 * This software falls under the GNU general public license version 3 or later.
00008 * It comes WITHOUT ANY WARRANTY WHATSOEVER. For details, see the file LICENSE
00009 * in the root directory or <http://www.gnu.org/licenses/gpl-3.0.html>.
00010 ******************************************************************************/
00011 
00012 #include "vars.hpp"
00013 #include "drd_info.hpp"
00014 #include "drd_std.hpp"
00015 #include "drd_mode.hpp"
00016 #include "iterator.hpp"
00017 #include "analyze.hpp"
00018 
00019 /******************************************************************************
00020 * Constructors and basic operations
00021 ******************************************************************************/
00022 
00023 drd_info_rep::drd_info_rep (string name2):
00024   name (name2), info (tag_info ()), env (UNINIT) {}
00025 drd_info_rep::drd_info_rep (string name2, drd_info base):
00026   name (name2), info (tag_info (), base->info), env (UNINIT) {}
00027 drd_info::drd_info (string name):
00028   rep (tm_new<drd_info_rep> (name)) {}
00029 drd_info::drd_info (string name, drd_info base):
00030   rep (tm_new<drd_info_rep> (name, base)) {}
00031 
00032 tree
00033 drd_info_rep::get_locals () {
00034   tree t (COLLECTION);
00035   iterator<tree_label> it= iterate (info->item);
00036   while (it->busy()) {
00037     tree_label l= it->next();
00038     tree v= (tree) info->item[l];
00039     t << tree (ASSOCIATE, as_string (l), v);
00040   }
00041   return t;
00042 }
00043 
00044 bool
00045 drd_info_rep::set_locals (tree t) {
00046   if (!is_func (t, COLLECTION))
00047     return false;
00048   int i, n= N(t);
00049   for (i=0; i<n; i++)
00050     if (is_func (t[i], ASSOCIATE, 2) && is_atomic (t[i][0]))
00051       info (make_tree_label (t[i][0]->label))= tag_info (t[i][1]);
00052   return true;
00053 }
00054 
00055 bool
00056 drd_info_rep::contains (string l) {
00057   return existing_tree_label (l) && info->contains (as_tree_label (l));
00058 }
00059 
00060 tm_ostream&
00061 operator << (tm_ostream& out, drd_info drd) {
00062   return out << "drd [" << drd->name << "]";
00063 }
00064 
00065 /******************************************************************************
00066 * Tag types
00067 ******************************************************************************/
00068 
00069 void
00070 drd_info_rep::set_type (tree_label l, int tp) {
00071   if (info[l]->pi.freeze_type) return;
00072   if (!info->contains (l)) info(l)= copy (info[l]);
00073   tag_info& ti= info(l);
00074   ti->pi.type= tp;
00075 }
00076 
00077 int
00078 drd_info_rep::get_type (tree_label l) {
00079   return info[l]->pi.type;
00080 }
00081 
00082 void
00083 drd_info_rep::freeze_type (tree_label l) {
00084   if (!info->contains (l)) info(l)= copy (info[l]);
00085   tag_info& ti= info(l);
00086   ti->pi.freeze_type= true;
00087 }
00088 
00089 int
00090 drd_info_rep::get_type (tree t) {
00091   return info[L(t)]->pi.type;
00092 }
00093 
00094 /******************************************************************************
00095 * Arity related methods
00096 ******************************************************************************/
00097 
00098 void
00099 drd_info_rep::set_arity (tree_label l, int arity, int extra, int am, int cm) {
00100   if (info[l]->pi.freeze_arity) return;
00101   if (!info->contains (l)) info(l)= copy (info[l]);
00102   tag_info& ti= info(l);
00103   ti->pi.arity_mode= am;
00104   ti->pi.child_mode= cm;
00105   if (am != ARITY_VAR_REPEAT) {
00106     ti->pi.arity_base = arity;
00107     ti->pi.arity_extra= extra;
00108   }
00109   else {
00110     ti->pi.arity_base = extra;
00111     ti->pi.arity_extra= arity;
00112   }
00113   int n;
00114   if (arity+extra == 0) n= 0;
00115   else if (cm == CHILD_UNIFORM) n= 1;
00116   else if (cm == CHILD_BIFORM) n= 2;
00117   else n= arity+extra;
00118   if (N(ti->ci) != n) ti->ci= array<child_info> (n);
00119 }
00120 
00121 int
00122 drd_info_rep::get_arity_mode (tree_label l) {
00123   return info[l]->pi.arity_mode;
00124 }
00125 
00126 int
00127 drd_info_rep::get_child_mode (tree_label l) {
00128   return info[l]->pi.child_mode;
00129 }
00130 
00131 int
00132 drd_info_rep::get_arity_base (tree_label l) {
00133   return info[l]->pi.arity_base;
00134 }
00135 
00136 int
00137 drd_info_rep::get_arity_extra (tree_label l) {
00138   return info[l]->pi.arity_extra;
00139 }
00140 
00141 int
00142 drd_info_rep::get_nr_indices (tree_label l) {
00143   return N(info[l]->ci);
00144 }
00145 
00146 void
00147 drd_info_rep::freeze_arity (tree_label l) {
00148   if (!info->contains (l)) info(l)= copy (info[l]);
00149   tag_info& ti= info(l);
00150   ti->pi.freeze_arity= true;
00151 }
00152 
00153 int
00154 drd_info_rep::get_old_arity (tree_label l) {
00155   tag_info ti= info[l];
00156   if (ti->pi.arity_mode != ARITY_NORMAL) return -1;
00157   else return ((int) ti->pi.arity_base) + ((int) ti->pi.arity_extra);
00158 }
00159 
00160 int
00161 drd_info_rep::get_minimal_arity (tree_label l) {
00162   parent_info pi= info[l]->pi;
00163   switch (pi.arity_mode) {
00164   case ARITY_NORMAL:
00165     return ((int) pi.arity_base) + ((int) pi.arity_extra);
00166   case ARITY_OPTIONS:
00167   case ARITY_REPEAT:
00168   case ARITY_VAR_REPEAT:
00169     return ((int) pi.arity_base);
00170   }
00171   return 0; // NOT REACHED
00172 }
00173 
00174 int
00175 drd_info_rep::get_maximal_arity (tree_label l) {
00176   parent_info pi= info[l]->pi;
00177   switch (pi.arity_mode) {
00178   case ARITY_NORMAL:
00179   case ARITY_OPTIONS:
00180     return ((int) pi.arity_base) + ((int) pi.arity_extra);
00181   case ARITY_REPEAT:
00182   case ARITY_VAR_REPEAT:
00183     return 0x7fffffff;
00184   }
00185   return 0; // NOT REACHED
00186 }
00187 
00188 bool
00189 drd_info_rep::correct_arity (tree_label l, int i) {
00190   parent_info pi= info[l]->pi;
00191   switch (pi.arity_mode) {
00192   case ARITY_NORMAL:
00193     return i == ((int) pi.arity_base) + ((int) pi.arity_extra);
00194   case ARITY_OPTIONS:
00195     return (i >= ((int) pi.arity_base)) &&
00196            (i <= ((int) pi.arity_base) + ((int) pi.arity_extra));
00197   case ARITY_REPEAT:
00198   case ARITY_VAR_REPEAT:
00199     return (i >= ((int) pi.arity_base)) &&
00200            (((i-pi.arity_base) % pi.arity_extra) == 0);
00201   }
00202   return false; // NOT REACHED
00203 }
00204 
00205 bool
00206 drd_info_rep::insert_point (tree_label l, int i, int n) {
00207   parent_info pi= info[l]->pi;
00208   switch (pi.arity_mode) {
00209   case ARITY_NORMAL:
00210     return false;
00211   case ARITY_OPTIONS:
00212     return (i >= ((int) pi.arity_base)) && (i <= n) &&
00213            (n < ((int) pi.arity_base) + ((int) pi.arity_extra));
00214   case ARITY_REPEAT:
00215     return (i >= 0) &&
00216            ((i < ((int) pi.arity_base)) ||
00217            ((i - pi.arity_base) % pi.arity_extra) == 0);
00218   case ARITY_VAR_REPEAT:
00219     return (i >= 0) &&
00220            ((i > (n - ((int) pi.arity_base))) ||
00221            (i % pi.arity_extra == 0));
00222   }
00223   return false; // NOT REACHED
00224 }
00225 
00226 bool
00227 drd_info_rep::is_dynamic (tree t, bool hack) {
00228   if (hack && L(t) >= START_EXTENSIONS) return true; // FIXME: temporary fix
00229   if (is_atomic (t)) return false;
00230   if (is_func (t, DOCUMENT) || is_func (t, PARA) || is_func (t, CONCAT) ||
00231       is_func (t, TABLE) || is_func (t, ROW)) return false;
00232   return info[L(t)]->pi.arity_mode != ARITY_NORMAL;
00233 }
00234 
00235 /******************************************************************************
00236 * Border accessability related methods
00237 ******************************************************************************/
00238 
00239 void
00240 drd_info_rep::set_border (tree_label l, int mode) {
00241   if (info[l]->pi.freeze_border) return;
00242   if (!info->contains (l)) info(l)= copy (info[l]);
00243   tag_info& ti= info(l);
00244   ti->pi.border_mode= mode;
00245 }
00246 
00247 int
00248 drd_info_rep::get_border (tree_label l) {
00249   return info[l]->pi.border_mode;
00250 }
00251 
00252 void
00253 drd_info_rep::freeze_border (tree_label l) {
00254   if (!info->contains (l)) info(l)= copy (info[l]);
00255   tag_info& ti= info(l);
00256   ti->pi.freeze_border= true;
00257 }
00258 
00259 bool
00260 drd_info_rep::is_child_enforcing (tree t) {
00261   return ((info[L(t)]->pi.border_mode & BORDER_INNER) != 0) &&
00262          (N(t) != 0);
00263 }
00264 
00265 bool
00266 drd_info_rep::is_parent_enforcing (tree t) {
00267   return ((info[L(t)]->pi.border_mode & BORDER_OUTER) != 0) &&
00268          (N(t) != 0);
00269 }
00270 
00271 bool
00272 drd_info_rep::var_without_border (tree_label l) {
00273   return ((info[l]->pi.border_mode & BORDER_INNER) != 0) &&
00274          (!std_contains (as_string (l)));
00275 }
00276 
00277 /******************************************************************************
00278 * With-like structures correspond to macros which just modify
00279 * the current environment, such as the 'strong' tag
00280 ******************************************************************************/
00281 
00282 void
00283 drd_info_rep::set_with_like (tree_label l, bool is_with_like) {
00284   if (info[l]->pi.freeze_with) return;
00285   if (!info->contains (l)) info(l)= copy (info[l]);
00286   tag_info& ti= info(l);
00287   ti->pi.with_like= is_with_like;
00288 }
00289 
00290 bool
00291 drd_info_rep::get_with_like (tree_label l) {
00292   return info[l]->pi.with_like;
00293 }
00294 
00295 void
00296 drd_info_rep::freeze_with_like (tree_label l) {
00297   if (!info->contains (l)) info(l)= copy (info[l]);
00298   tag_info& ti= info(l);
00299   ti->pi.freeze_with= true;
00300 }
00301 
00302 bool
00303 drd_info_rep::is_with_like (tree t) {
00304   return info[L(t)]->pi.with_like && N(t) > 0;
00305 }
00306 
00307 /******************************************************************************
00308 * Other attributes
00309 ******************************************************************************/
00310 
00311 void
00312 drd_info_rep::set_attribute (tree_label l, string which, tree val) {
00313   if (!info->contains (l)) info(l)= copy (info[l]);
00314   tag_info& ti= info(l);
00315   ti->set_attribute (which, val);
00316 }
00317 
00318 tree
00319 drd_info_rep::get_attribute (tree_label l, string which) {
00320   tree val= info[l]->get_attribute (which);
00321   if ((which == "name") && (val == ""))
00322     return as_string (l);
00323   return val;
00324 }
00325 
00326 void
00327 drd_info_rep::set_name (tree_label l, string val) {
00328   set_attribute (l, "name", val);
00329 }
00330 
00331 void
00332 drd_info_rep::set_long_name (tree_label l, string val) {
00333   set_attribute (l, "long-name", val);
00334 }
00335 
00336 void
00337 drd_info_rep::set_syntax (tree_label l, tree val) {
00338   set_attribute (l, "syntax", val);
00339 }
00340 
00341 string
00342 drd_info_rep::get_name (tree_label l) {
00343   return as_string (get_attribute (l, "name"));
00344 }
00345 
00346 string
00347 drd_info_rep::get_long_name (tree_label l) {
00348   string r= as_string (get_attribute (l, "long-name"));
00349   if (r != "") return r;
00350   return as_string (get_attribute (l, "name"));
00351 }
00352 
00353 tree
00354 drd_info_rep::get_syntax (tree_label l) {
00355   tree r= get_attribute (l, "syntax");
00356   if (r != "") return r;
00357   if (env->contains (as_string (l))) return env[as_string (l)];
00358   return UNINIT;
00359 }
00360 
00361 static tree
00362 replace (tree t, hashmap<tree,tree> h) {
00363   if (h->contains (t)) return h[t];
00364   else if (is_atomic (t)) return t;
00365   else {
00366     int i, n= N(t);
00367     tree r (t, n);
00368     for (i=0; i<n; i++)
00369       r[i]= replace (t[i], h);
00370     return r;
00371   }
00372 }
00373 
00374 tree
00375 drd_info_rep::get_syntax (tree t, path p) {
00376   if (is_atomic (t)) {
00377     string s= t->label;
00378     if (N(s) == 1 || !existing_tree_label (s)) return UNINIT;
00379     return get_syntax (as_tree_label (s));
00380   }
00381   else if (is_func (t, VALUE, 1) && is_atomic (t[0])) {
00382     string s= t[0]->label;
00383     if (!existing_tree_label (s)) return UNINIT;
00384     return get_syntax (as_tree_label (s));
00385   }
00386   else if (L(t) < START_EXTENSIONS)
00387     return UNINIT;
00388   else {
00389     tree fun= the_drd->get_syntax (L(t));
00390     if (fun == UNINIT) return UNINIT;
00391     else if (N(t) == 0 && !is_func (fun, MACRO)) return fun;
00392     else if (!is_func (fun, MACRO)) return UNINIT;
00393     else {
00394       int i, n= N(fun)-1;
00395       hashmap<tree,tree> tab (UNINIT);
00396       for (i=0; i<n; i++) {
00397         tree var= tree (ARG, fun[i]);
00398         tree val= "";
00399         if (i < N(t)) {
00400           if (p == path (-1)) val= t[i];
00401           else val= tree (QUASI, t[i], (tree) (p * i));
00402         }
00403         tab (var)= val;
00404       }
00405       return replace (fun[n], tab);
00406     }
00407   }
00408 }
00409 
00410 /******************************************************************************
00411 * Children's mode
00412 ******************************************************************************/
00413 
00414 void
00415 drd_info_rep::set_type (tree_label l, int nr, int tp) {
00416   if (!info->contains (l)) info(l)= copy (info[l]);
00417   tag_info  & ti= info(l);
00418   if (nr >= N(ti->ci)) return;
00419   child_info& ci= ti->ci[nr];
00420   if (ci.freeze_type) return;
00421   ci.type= tp;
00422 }
00423 
00424 int
00425 drd_info_rep::get_type (tree_label l, int nr) {
00426   if (nr >= N(info[l]->ci)) return TYPE_ADHOC;
00427   return info[l]->ci[nr].type;
00428 }
00429 
00430 void
00431 drd_info_rep::freeze_type (tree_label l, int nr) {
00432   if (!info->contains (l)) info(l)= copy (info[l]);
00433   tag_info  & ti= info(l);
00434   if (nr >= N(ti->ci)) return;
00435   child_info& ci= ti->ci[nr];
00436   ci.freeze_type= true;
00437 }
00438 
00439 int
00440 drd_info_rep::get_type_child (tree t, int i) {
00441   tag_info ti= info[L(t)];
00442   int index= ti->get_index (i, N(t));
00443   if (is_func (t, EXTERN) && N(t)>0 && is_atomic (t[0])) {
00444     ti= info[make_tree_label ("extern:" * t[0]->label)];
00445     index= ti->get_index (i-1, N(t));
00446   }
00447   if ((index<0) || (index>=N(ti->ci))) return TYPE_INVALID;
00448   int r= ti->ci[index].type;
00449   if (r != TYPE_BINDING) return r;
00450   if ((i & 1) == 0) return TYPE_VARIABLE;
00451   return TYPE_REGULAR;
00452 }
00453 
00454 /******************************************************************************
00455 * Children's accessability related methods
00456 ******************************************************************************/
00457 
00458 void
00459 drd_info_rep::set_accessible (tree_label l, int nr, int is_accessible) {
00460   if (!info->contains (l)) info(l)= copy (info[l]);
00461   tag_info  & ti= info(l);
00462   if (nr >= N(ti->ci)) return;
00463   child_info& ci= ti->ci[nr];
00464   if (ci.freeze_accessible) return;
00465   ci.accessible= is_accessible;
00466 }
00467 
00468 int
00469 drd_info_rep::get_accessible (tree_label l, int nr) {
00470   if (nr >= N(info[l]->ci)) return ACCESSIBLE_NEVER;
00471   return info[l]->ci[nr].accessible;
00472 }
00473 
00474 void
00475 drd_info_rep::freeze_accessible (tree_label l, int nr) {
00476   if (!info->contains (l)) info(l)= copy (info[l]);
00477   tag_info  & ti= info(l);
00478   if (nr >= N(ti->ci)) return;
00479   child_info& ci= ti->ci[nr];
00480   ci.freeze_accessible= true;
00481 }
00482 
00483 bool
00484 drd_info_rep::all_accessible (tree_label l) {
00485   int i, n= N(info[l]->ci);
00486   for (i=0; i<n; i++)
00487     if (info[l]->ci[i].accessible != ACCESSIBLE_ALWAYS)
00488       return false;
00489   return n>0;
00490 }
00491 
00492 bool
00493 drd_info_rep::none_accessible (tree_label l) {
00494   int i, n= N(info[l]->ci);
00495   for (i=0; i<n; i++)
00496     if (info[l]->ci[i].accessible != ACCESSIBLE_NEVER)
00497       return false;
00498   return true;
00499 }
00500 
00501 bool
00502 drd_info_rep::is_accessible_child (tree t, int i) {
00503   //cout << "l= " << as_string (L(t)) << "\n";
00504   tag_info ti= info[L(t)];
00505   int index= ti->get_index (i, N(t));
00506   if (is_func (t, EXTERN) && N(t)>0 && is_atomic (t[0])) {
00507     ti= info[make_tree_label ("extern:" * t[0]->label)];
00508     index= ti->get_index (i-1, N(t));
00509   }
00510   if ((index<0) || (index>=N(ti->ci))) {
00511     if (get_access_mode () == DRD_ACCESS_SOURCE)
00512       return !is_atomic (t) && i >= 0 && i < N(t);
00513     else return false;
00514   }
00515   switch (get_access_mode ()) {
00516   case DRD_ACCESS_NORMAL:
00517     return ti->ci[index].accessible == ACCESSIBLE_ALWAYS;
00518   case DRD_ACCESS_HIDDEN:
00519     return ti->ci[index].accessible == ACCESSIBLE_ALWAYS ||
00520            ti->ci[index].accessible == ACCESSIBLE_HIDDEN;
00521   case DRD_ACCESS_SOURCE:
00522     return true;
00523   }
00524   return true; // NOT REACHED
00525 }
00526 
00527 /******************************************************************************
00528 * Children's writability
00529 ******************************************************************************/
00530 
00531 void
00532 drd_info_rep::set_writability (tree_label l, int nr, int writability) {
00533   if (!info->contains (l)) info(l)= copy (info[l]);
00534   tag_info  & ti= info(l);
00535   if (nr >= N(ti->ci)) return;
00536   child_info& ci= ti->ci[nr];
00537   if (ci.freeze_writability) return;
00538   ci.writability= writability;
00539 }
00540 
00541 int
00542 drd_info_rep::get_writability (tree_label l, int nr) {
00543   if (nr >= N(info[l]->ci)) return WRITABILITY_NORMAL;
00544   return info[l]->ci[nr].writability;
00545 }
00546 
00547 void
00548 drd_info_rep::freeze_writability (tree_label l, int nr) {
00549   if (!info->contains (l)) info(l)= copy (info[l]);
00550   tag_info  & ti= info(l);
00551   if (nr >= N(ti->ci)) return;
00552   child_info& ci= ti->ci[nr];
00553   ci.freeze_writability= true;
00554 }
00555 
00556 int
00557 drd_info_rep::get_writability_child (tree t, int i) {
00558   tag_info ti= info[L(t)];
00559   int index= ti->get_index (i, N(t));
00560   if (is_func (t, EXTERN) && N(t)>0 && is_atomic (t[0])) {
00561     ti= info[make_tree_label ("extern:" * t[0]->label)];
00562     index= ti->get_index (i-1, N(t));
00563   }
00564   if ((index<0) || (index>=N(ti->ci))) return WRITABILITY_DISABLE;
00565   return ti->ci[index].writability;
00566 }
00567 
00568 /******************************************************************************
00569 * Child names, based on set/get attribute for parent
00570 ******************************************************************************/
00571 
00572 void
00573 drd_info_rep::set_child_name (tree_label l, int nr, string val) {
00574   set_attribute (l, "name-" * as_string (nr), val);
00575 }
00576 
00577 void
00578 drd_info_rep::set_child_long_name (tree_label l, int nr, string val) {
00579   set_attribute (l, "long-name-" * as_string (nr), val);
00580 }
00581 
00582 string
00583 drd_info_rep::get_child_name (tree_label l, int nr) {
00584   return as_string (get_attribute (l, "name-" * as_string (nr)));
00585 }
00586 
00587 string
00588 drd_info_rep::get_child_long_name (tree_label l, int nr) {
00589   return as_string (get_attribute (l, "long-name-" * as_string (nr)));
00590 }
00591 
00592 string
00593 drd_info_rep::get_child_name (tree t, int i) {
00594   tag_info ti= info[L(t)];
00595   int index= ti->get_index (i, N(t));
00596   if (is_func (t, EXTERN) && N(t)>0 && is_atomic (t[0])) {
00597     ti= info[make_tree_label ("extern:" * t[0]->label)];
00598     index= ti->get_index (i-1, N(t));
00599   }
00600   if ((index<0) || (index>=N(ti->ci))) return "";
00601   return get_child_name (L(t), index);
00602 }
00603 
00604 string
00605 drd_info_rep::get_child_long_name (tree t, int i) {
00606   tag_info ti= info[L(t)];
00607   int index= ti->get_index (i, N(t));
00608   if (is_func (t, EXTERN) && N(t)>0 && is_atomic (t[0])) {
00609     ti= info[make_tree_label ("extern:" * t[0]->label)];
00610     index= ti->get_index (i-1, N(t));
00611   }
00612   if ((index<0) || (index>=N(ti->ci))) return "";
00613   string r= get_child_long_name (L(t), index);
00614   if (r != "") return r;
00615   return get_child_name (L(t), index);
00616 }
00617 
00618 /******************************************************************************
00619 * Environment determination
00620 ******************************************************************************/
00621 
00622 tree
00623 drd_env_write (tree env, string var, tree val) {
00624   for (int i=0; i<=N(env); i+=2)
00625     if (i == N(env))
00626       return env * tree (ATTR, var, val);
00627     else if (var <= env[i]->label) {
00628       if (var == env[i]->label)
00629        return env (0, i) * tree (ATTR, var, val) * env (i+2, N(env));
00630       return env (0, i) * tree (ATTR, var, val) * env (i, N(env));
00631     }
00632   return env;
00633 }
00634 
00635 tree
00636 drd_env_merge (tree env, tree t) {
00637   int i, n= N(t);
00638   for (i=0; (i+1)<n; i+=2)
00639     if (is_atomic (t[i]))
00640       env= drd_env_write (env, t[i]->label, t[i+1]);
00641   return env;
00642 }
00643 
00644 tree
00645 drd_env_read (tree env, string var, tree val) {
00646   int i, n= N(env);
00647   for (i=0; i<n; i+=2)
00648     if (env[i] == var)
00649       return env[i+1];
00650   return val;
00651 }
00652 
00653 void
00654 drd_info_rep::set_env (tree_label l, int nr, tree env) {
00655   //if (as_string (l) == "section")
00656   //cout << as_string (l) << ", " << nr << " -> " << env << "\n";
00657   //if (as_string (l) == "session")
00658   //cout << as_string (l) << ", " << nr << " -> " << env << "\n";
00659   if (!info->contains (l)) info(l)= copy (info[l]);
00660   tag_info  & ti= info(l);
00661   if (nr >= N(ti->ci)) return;
00662   child_info& ci= ti->ci[nr];
00663   if (ci.freeze_env) return;
00664   ci.env= drd_encode (env);
00665 }
00666 
00667 tree
00668 drd_info_rep::get_env (tree_label l, int nr) {
00669   if (nr >= N(info[l]->ci)) return tree (ATTR);
00670   return drd_decode (info[l]->ci[nr].env);
00671 }
00672 
00673 void
00674 drd_info_rep::freeze_env (tree_label l, int nr) {
00675   if (!info->contains (l)) info(l)= copy (info[l]);
00676   tag_info  & ti= info(l);
00677   if (nr >= N(ti->ci)) return;
00678   child_info& ci= ti->ci[nr];
00679   ci.freeze_env= true;
00680 }
00681 
00682 tree
00683 drd_info_rep::get_env_child (tree t, int i, tree env) {
00684   if (L(t) == WITH && i == N(t)-1)
00685     return drd_env_merge (env, t (0, N(t)-1));
00686   else {
00687     /* makes cursor movement (is_accessible_cursor) slow for large preambles
00688     if (L(t) == DOCUMENT && N(t) > 0 &&
00689        (is_compound (t[0], "hide-preamble", 1) ||
00690         is_compound (t[0], "show-preamble", 1)))
00691       {
00692        tree u= t[0][0];
00693        if (!is_func (u, DOCUMENT)) u= tree (DOCUMENT, u);
00694        tree cenv (ATTR);
00695        for (int i=0; i<N(u); i++)
00696          if (is_func (u[i], ASSIGN, 2))
00697            cenv << copy (u[i][0]) << copy (u[i][1]);
00698        env= drd_env_merge (env, cenv);
00699       }
00700     */
00701 
00702     tag_info ti= info[L(t)];
00703     int index= ti->get_index (i, N(t));
00704     if ((index<0) || (index>=N(ti->ci))) return "";
00705     tree cenv= drd_decode (ti->ci[index].env);
00706     for (int i=1; i<N(cenv); i+=2)
00707       if (is_func (cenv[i], ARG, 1) && is_int (cenv[i][0])) {
00708        cenv= copy (cenv);
00709        int j= as_int (cenv[i][0]);
00710        if (j>=0 && j<N(t)) cenv[i]= copy (t[j]);
00711       }
00712     return drd_env_merge (env, cenv);
00713   }
00714 }
00715 
00716 
00717 tree
00718 drd_info_rep::get_env_child (tree t, int i, string var, tree val) {
00719   tree env= get_env_child (t, i, tree (ATTR));
00720   return drd_env_read (env, var, val);
00721 }
00722 
00723 tree
00724 drd_info_rep::get_env_descendant (tree t, path p, tree env) {
00725   if (is_nil (p) || env == "") return env;
00726   int  i= p->item;
00727   path q= p->next;
00728   if (is_compound (t) && i >= 0 && i < N(t))
00729     return get_env_descendant (t[i], q, get_env_child (t, i, env));
00730   return "";
00731 }
00732 
00733 /******************************************************************************
00734 * Heuristic initialization of DRD
00735 ******************************************************************************/
00736 
00737 void
00738 drd_info_rep::set_environment (hashmap<string,tree> env2) {
00739   env= env2;
00740 }
00741 
00742 tree
00743 drd_info_rep::arg_access (tree t, tree arg, tree env, int& type) {
00744   // returns "" if unaccessible and the env if accessible
00745   //cout << "  arg_access " << t << ", " << arg << ", " << env << "\n";
00746   if (is_atomic (t)) return "";
00747   else if (t == arg) return env;
00748   else if (is_func (t, QUOTE_ARG, 1) && N(arg) == 1 && t[0] == arg[0])
00749     return env;
00750   else if (is_func (t, MAP_ARGS) && (t[2] == arg[0])) {
00751     if ((N(t) >= 4) && (N(arg) >= 2) && (as_int (t[3]) > as_int (arg[1])))
00752       return "";
00753     if ((N(t) == 5) && (N(arg) >= 2) && (as_int (t[3]) <= as_int (arg[1])))
00754       return "";
00755     tree_label inner= make_tree_label (as_string (t[0]));
00756     tree_label outer= make_tree_label (as_string (t[1]));
00757     if (get_nr_indices (inner) > 0)
00758       type= get_type_child (tree (inner, arg), 0);
00759     if ((get_nr_indices (inner) > 0) &&
00760        (get_accessible (inner, 0) == ACCESSIBLE_ALWAYS) &&
00761        all_accessible (outer))
00762       return env;
00763     return "";
00764   }
00765   else if (is_func (t, MACRO)) return "";
00766   else if (is_func (t, WITH)) {
00767     int n= N(t)-1;
00768     //cout << "env= " << drd_env_merge (env, t (0, n)) << "\n";
00769     return arg_access (t[n], arg, drd_env_merge (env, t (0, n)), type);
00770   }
00771   else if (is_func (t, TFORMAT)) {
00772     int n= N(t)-1;
00773     tree oldf= drd_env_read (env, CELL_FORMAT, tree (TFORMAT));
00774     tree newf= oldf * tree (TFORMAT, A (t (0, n)));
00775     tree w   = tree (ATTR, CELL_FORMAT, newf);
00776     tree cenv= get_env_child (t, n, drd_env_merge (env, w));
00777     return arg_access (t[n], arg, cenv, type);
00778   }
00779   else if (is_func (t, COMPOUND) && N(t) >= 1 && is_atomic (t[0]))
00780     return arg_access (compound (t[0]->label, A (t (1, N(t)))),
00781                      arg, env, type);
00782   else if ((is_func (t, IF) || is_func (t, VAR_IF)) && N(t) >= 2)
00783     return arg_access (t[1], arg, env, type);
00784   else {
00785     int i, n= N(t);
00786     for (i=0; i<n; i++) {
00787       int  ctype= get_type_child (t, i);
00788       tree cenv = get_env_child (t, i, env);
00789       tree aenv = arg_access (t[i], arg, cenv, ctype);
00790       if (aenv != "") {
00791        if (ctype != TYPE_INVALID) type= ctype;
00792        if (is_accessible_child (t, i)) return aenv;
00793       }
00794       else if (type == TYPE_UNKNOWN &&
00795                ctype != TYPE_INVALID &&
00796                ctype != TYPE_UNKNOWN) {
00797         type= ctype;
00798         //cout << "  found type " << t << ", " << arg << ", " << type << "\n";
00799       }
00800     }
00801     return "";
00802   }
00803 }
00804 
00805 static void
00806 rewrite_symbolic_arguments (tree macro, tree& env) {
00807   if (!is_func (env, ATTR)) return;
00808   for (int i=1; i<N(env); i+=2)
00809     if (is_func (env[i], ARG, 1)) {
00810       for (int j=0; j+1<N(macro); j++)
00811        if (macro[j] == env[i][0])
00812          env[i]= tree (ARG, as_tree (j));
00813     }
00814 }
00815 
00816 bool
00817 drd_info_rep::heuristic_with_like (tree t, tree arg) {
00818   if (arg == "") {
00819     if (!is_func (t, MACRO) || N(t) < 2) return false;
00820     return heuristic_with_like (t[N(t)-1], t[N(t)-2]);
00821   }
00822   else if (t == tree (ARG, arg))
00823     return true;
00824   else if (is_with_like (t))
00825     return heuristic_with_like (t[N(t)-1], arg);
00826   else return false;
00827 }
00828 
00829 bool
00830 drd_info_rep::heuristic_init_macro (string var, tree macro) {
00831   //cout << "init_macro " << var << " -> " << macro << "\n";
00832   tree_label l = make_tree_label (var);
00833   tag_info old_ti= copy (info[l]);
00834   int i, n= N(macro)-1;
00835   set_arity (l, n, 0, ARITY_NORMAL, CHILD_DETAILED);
00836   set_type (l, get_type (macro[n]));
00837   set_with_like (l, heuristic_with_like (macro, ""));
00838   //if (heuristic_with_like (macro, ""))
00839   //cout << "With-like: " << var << LF;
00840   for (i=0; i<n; i++) {
00841     if (is_atomic (macro[i]))
00842       if (l >= START_EXTENSIONS || get_child_name (l, i) == "")
00843         set_child_name (l, i, macro[i]->label);
00844     int  type= TYPE_UNKNOWN;
00845     tree arg (ARG, macro[i]);
00846     tree env= arg_access (macro[n], arg, tree (ATTR), type);
00847     //if (var == "section" || var == "section-title")
00848     //cout << var << " -> " << env << ", " << macro << "\n";
00849     //if (var == "math")
00850     //cout << var << ", " << i << " -> " << type << ", " << env << ", " << macro << "\n";
00851     set_type (l, i, type);
00852     if (env != "") {
00853       //if (var == "eqnarray*")
00854       //cout << var << " -> " << env << "\n";
00855       //if (var == "session")
00856       //cout << var << " = " << macro << ", " << i << " -> " << env << "\n";
00857       rewrite_symbolic_arguments (macro, env);
00858       set_accessible (l, i, ACCESSIBLE_ALWAYS);
00859       set_env (l, i, env);
00860     }
00861   }
00862   //if (old_ti != info[l])
00863   //cout << var << ": " << old_ti << " -> " << info[l] << "\n";
00864   return (old_ti != info[l]);
00865 }
00866 
00867 static int
00868 minimal_arity (tree t, tree var) {
00869   if (is_atomic (t)) return 0;
00870   else if (is_func (t, ARG, 2) && (t[0] == var))
00871     return as_int (t[1]) + 1;
00872   else if (is_func (t, MAP_ARGS) && (N(t)>=4) && (t[2] == var))
00873     return as_int (t[3]);
00874   else {
00875     int i, n= N(t), m= 0;
00876     for (i=0; i<n; i++)
00877       m= max (m, minimal_arity (t[i], var));
00878     return m;
00879   }
00880 }
00881 
00882 bool
00883 drd_info_rep::heuristic_init_xmacro (string var, tree xmacro) {
00884   tree_label l = make_tree_label (var);
00885   tag_info old_ti= copy (info[l]);
00886   int i, m= minimal_arity (xmacro[1], xmacro[0]);
00887   set_arity (l, m, 1, ARITY_REPEAT, CHILD_DETAILED);
00888   set_type (l, get_type (xmacro[1]));
00889   for (i=0; i<=m; i++) {
00890     int type= TYPE_UNKNOWN;
00891     tree arg (ARG, xmacro[0], as_string (i));
00892     tree env= arg_access (xmacro[1], arg, tree (ATTR), type);
00893     //cout << var << ", " << xmacro << ", " << i << " -> " << type << "\n";
00894     set_type (l, i, type);
00895     if (env != "") {
00896       set_accessible (l, i, ACCESSIBLE_ALWAYS);
00897       set_env (l, i, env);
00898     }
00899   }
00900   // if (old_ti != info[l])
00901   //   cout << var << ": " << old_ti << " -> " << info[l] << "\n";
00902   return (old_ti != info[l]);
00903 }
00904 
00905 void
00906 drd_info_rep::heuristic_init (hashmap<string,tree> env2) {
00907   // time_t tt= texmacs_time ();
00908   set_environment (env2);
00909   bool flag= true;
00910   int round= 0;
00911   while (flag) {
00912     // cout << HRULE;
00913     flag= false;
00914     iterator<string> it= iterate (env);
00915     while (it->busy()) {
00916       string var= it->next();
00917       tree   val= env[var];
00918       if (is_func (val, MACRO))
00919        flag= heuristic_init_macro (var, val) | flag;
00920       if (is_func (val, XMACRO))
00921        flag= heuristic_init_xmacro (var, val) | flag;
00922     }
00923     if ((round++) == 10) {
00924       cout << "TeXmacs] Warning: bad heuristic drd convergence\n";
00925       flag= false;
00926     }
00927   }
00928   // cout << "--> " << (texmacs_time ()-tt) << "ms\n";
00929 }