1
2 /******************************************************************************
3 * MODULE : drd_info.cpp
4 * DESCRIPTION: data relation descriptions
5 * COPYRIGHT : (C) 2003 Joris van der Hoeven
6 *******************************************************************************
7 * This software falls under the GNU general public license version 3 or later.
8 * It comes WITHOUT ANY WARRANTY WHATSOEVER. For details, see the file LICENSE
9 * in the root directory or <http://www.gnu.org/licenses/gpl-3.0.html>.
10 ******************************************************************************/
11
12 #include "vars.hpp"
13 #include "drd_info.hpp"
14 #include "drd_std.hpp"
15 #include "drd_mode.hpp"
16 #include "iterator.hpp"
17 #include "analyze.hpp"
18
19 /******************************************************************************
20 * Constructors and basic operations
21 ******************************************************************************/
22
drd_info_rep(string name2)23 drd_info_rep::drd_info_rep (string name2):
24 name (name2), info (tag_info ()), env (UNINIT) {}
drd_info_rep(string name2,drd_info base)25 drd_info_rep::drd_info_rep (string name2, drd_info base):
26 name (name2), info (tag_info (), base->info), env (UNINIT) {}
drd_info(string name)27 drd_info::drd_info (string name):
28 rep (tm_new<drd_info_rep> (name)) {}
drd_info(string name,drd_info base)29 drd_info::drd_info (string name, drd_info base):
30 rep (tm_new<drd_info_rep> (name, base)) {}
31
32 tree
get_locals()33 drd_info_rep::get_locals () {
34 tree t (COLLECTION);
35 iterator<tree_label> it= iterate (info->item);
36 while (it->busy()) {
37 tree_label l= it->next();
38 tree v= (tree) info->item[l];
39 t << tree (ASSOCIATE, as_string (l), v);
40 }
41 return t;
42 }
43
44 bool
set_locals(tree t)45 drd_info_rep::set_locals (tree t) {
46 if (!is_func (t, COLLECTION))
47 return false;
48 int i, n= N(t);
49 for (i=0; i<n; i++)
50 if (is_func (t[i], ASSOCIATE, 2) && is_atomic (t[i][0]))
51 info (make_tree_label (t[i][0]->label))= tag_info (t[i][1]);
52 return true;
53 }
54
55 bool
contains(string l)56 drd_info_rep::contains (string l) {
57 return existing_tree_label (l) && info->contains (as_tree_label (l));
58 }
59
60 tm_ostream&
operator <<(tm_ostream & out,drd_info drd)61 operator << (tm_ostream& out, drd_info drd) {
62 return out << "drd [" << drd->name << "]";
63 }
64
65 /******************************************************************************
66 * Tag types
67 ******************************************************************************/
68
69 void
set_type(tree_label l,int tp)70 drd_info_rep::set_type (tree_label l, int tp) {
71 if (info[l]->pi.freeze_type) return;
72 if (!info->contains (l)) info(l)= copy (info[l]);
73 tag_info& ti= info(l);
74 ti->pi.type= tp;
75 }
76
77 int
get_type(tree_label l)78 drd_info_rep::get_type (tree_label l) {
79 return info[l]->pi.type;
80 }
81
82 void
freeze_type(tree_label l)83 drd_info_rep::freeze_type (tree_label l) {
84 if (!info->contains (l)) info(l)= copy (info[l]);
85 tag_info& ti= info(l);
86 ti->pi.freeze_type= true;
87 }
88
89 int
get_type(tree t)90 drd_info_rep::get_type (tree t) {
91 return info[L(t)]->pi.type;
92 }
93
94 /******************************************************************************
95 * Arity related methods
96 ******************************************************************************/
97
98 void
set_arity(tree_label l,int arity,int extra,int am,int cm)99 drd_info_rep::set_arity (tree_label l, int arity, int extra, int am, int cm) {
100 if (info[l]->pi.freeze_arity) return;
101 if (!info->contains (l)) info(l)= copy (info[l]);
102 tag_info& ti= info(l);
103 ti->pi.arity_mode= am;
104 ti->pi.child_mode= cm;
105 if (am != ARITY_VAR_REPEAT) {
106 ti->pi.arity_base = arity;
107 ti->pi.arity_extra= extra;
108 }
109 else {
110 ti->pi.arity_base = extra;
111 ti->pi.arity_extra= arity;
112 }
113 int n;
114 if (arity+extra == 0) n= 0;
115 else if (cm == CHILD_UNIFORM) n= 1;
116 else if (cm == CHILD_BIFORM) n= 2;
117 else n= arity+extra;
118 if (N(ti->ci) != n) ti->ci= array<child_info> (n);
119 }
120
121 int
get_arity_mode(tree_label l)122 drd_info_rep::get_arity_mode (tree_label l) {
123 return info[l]->pi.arity_mode;
124 }
125
126 int
get_child_mode(tree_label l)127 drd_info_rep::get_child_mode (tree_label l) {
128 return info[l]->pi.child_mode;
129 }
130
131 int
get_arity_base(tree_label l)132 drd_info_rep::get_arity_base (tree_label l) {
133 return info[l]->pi.arity_base;
134 }
135
136 int
get_arity_extra(tree_label l)137 drd_info_rep::get_arity_extra (tree_label l) {
138 return info[l]->pi.arity_extra;
139 }
140
141 int
get_nr_indices(tree_label l)142 drd_info_rep::get_nr_indices (tree_label l) {
143 return N(info[l]->ci);
144 }
145
146 void
freeze_arity(tree_label l)147 drd_info_rep::freeze_arity (tree_label l) {
148 if (!info->contains (l)) info(l)= copy (info[l]);
149 tag_info& ti= info(l);
150 ti->pi.freeze_arity= true;
151 }
152
153 int
get_old_arity(tree_label l)154 drd_info_rep::get_old_arity (tree_label l) {
155 tag_info ti= info[l];
156 if (ti->pi.arity_mode != ARITY_NORMAL) return -1;
157 else return ((int) ti->pi.arity_base) + ((int) ti->pi.arity_extra);
158 }
159
160 int
get_minimal_arity(tree_label l)161 drd_info_rep::get_minimal_arity (tree_label l) {
162 parent_info pi= info[l]->pi;
163 switch (pi.arity_mode) {
164 case ARITY_NORMAL:
165 return ((int) pi.arity_base) + ((int) pi.arity_extra);
166 case ARITY_OPTIONS:
167 case ARITY_REPEAT:
168 case ARITY_VAR_REPEAT:
169 return ((int) pi.arity_base);
170 }
171 return 0; // NOT REACHED
172 }
173
174 int
get_maximal_arity(tree_label l)175 drd_info_rep::get_maximal_arity (tree_label l) {
176 parent_info pi= info[l]->pi;
177 switch (pi.arity_mode) {
178 case ARITY_NORMAL:
179 case ARITY_OPTIONS:
180 return ((int) pi.arity_base) + ((int) pi.arity_extra);
181 case ARITY_REPEAT:
182 case ARITY_VAR_REPEAT:
183 return 0x7fffffff;
184 }
185 return 0; // NOT REACHED
186 }
187
188 bool
correct_arity(tree_label l,int i)189 drd_info_rep::correct_arity (tree_label l, int i) {
190 parent_info pi= info[l]->pi;
191 switch (pi.arity_mode) {
192 case ARITY_NORMAL:
193 return i == ((int) pi.arity_base) + ((int) pi.arity_extra);
194 case ARITY_OPTIONS:
195 return (i >= ((int) pi.arity_base)) &&
196 (i <= ((int) pi.arity_base) + ((int) pi.arity_extra));
197 case ARITY_REPEAT:
198 case ARITY_VAR_REPEAT:
199 return (i >= ((int) pi.arity_base)) &&
200 (((i-pi.arity_base) % pi.arity_extra) == 0);
201 }
202 return false; // NOT REACHED
203 }
204
205 bool
insert_point(tree_label l,int i,int n)206 drd_info_rep::insert_point (tree_label l, int i, int n) {
207 parent_info pi= info[l]->pi;
208 switch (pi.arity_mode) {
209 case ARITY_NORMAL:
210 return false;
211 case ARITY_OPTIONS:
212 return (i >= ((int) pi.arity_base)) && (i <= n) &&
213 (n < ((int) pi.arity_base) + ((int) pi.arity_extra));
214 case ARITY_REPEAT:
215 return (i >= 0) &&
216 ((i < ((int) pi.arity_base)) ||
217 ((i - pi.arity_base) % pi.arity_extra) == 0);
218 case ARITY_VAR_REPEAT:
219 return (i >= 0) &&
220 ((i > (n - ((int) pi.arity_base))) ||
221 (i % pi.arity_extra == 0));
222 }
223 return false; // NOT REACHED
224 }
225
226 bool
is_dynamic(tree t,bool hack)227 drd_info_rep::is_dynamic (tree t, bool hack) {
228 if (hack && L(t) >= START_EXTENSIONS) return true; // FIXME: temporary fix
229 if (is_atomic (t)) return false;
230 if (is_func (t, DOCUMENT) || is_func (t, PARA) || is_func (t, CONCAT) ||
231 is_func (t, TABLE) || is_func (t, ROW)) return false;
232 return info[L(t)]->pi.arity_mode != ARITY_NORMAL;
233 }
234
235 /******************************************************************************
236 * Border accessability related methods
237 ******************************************************************************/
238
239 void
set_border(tree_label l,int mode)240 drd_info_rep::set_border (tree_label l, int mode) {
241 if (info[l]->pi.freeze_border) return;
242 if (!info->contains (l)) info(l)= copy (info[l]);
243 tag_info& ti= info(l);
244 ti->pi.border_mode= mode;
245 }
246
247 int
get_border(tree_label l)248 drd_info_rep::get_border (tree_label l) {
249 return info[l]->pi.border_mode;
250 }
251
252 void
freeze_border(tree_label l)253 drd_info_rep::freeze_border (tree_label l) {
254 if (!info->contains (l)) info(l)= copy (info[l]);
255 tag_info& ti= info(l);
256 ti->pi.freeze_border= true;
257 }
258
259 bool
is_child_enforcing(tree t)260 drd_info_rep::is_child_enforcing (tree t) {
261 return ((info[L(t)]->pi.border_mode & BORDER_INNER) != 0) &&
262 (N(t) != 0);
263 }
264
265 bool
is_parent_enforcing(tree t)266 drd_info_rep::is_parent_enforcing (tree t) {
267 return ((info[L(t)]->pi.border_mode & BORDER_OUTER) != 0) &&
268 (N(t) != 0);
269 }
270
271 bool
var_without_border(tree_label l)272 drd_info_rep::var_without_border (tree_label l) {
273 return ((info[l]->pi.border_mode & BORDER_INNER) != 0) &&
274 (!std_contains (as_string (l)));
275 }
276
277 /******************************************************************************
278 * With-like structures correspond to macros which just modify
279 * the current environment, such as the 'strong' tag
280 ******************************************************************************/
281
282 void
set_with_like(tree_label l,bool is_with_like)283 drd_info_rep::set_with_like (tree_label l, bool is_with_like) {
284 if (info[l]->pi.freeze_with) return;
285 if (!info->contains (l)) info(l)= copy (info[l]);
286 tag_info& ti= info(l);
287 ti->pi.with_like= is_with_like;
288 }
289
290 bool
get_with_like(tree_label l)291 drd_info_rep::get_with_like (tree_label l) {
292 return info[l]->pi.with_like;
293 }
294
295 void
freeze_with_like(tree_label l)296 drd_info_rep::freeze_with_like (tree_label l) {
297 if (!info->contains (l)) info(l)= copy (info[l]);
298 tag_info& ti= info(l);
299 ti->pi.freeze_with= true;
300 }
301
302 bool
is_with_like(tree t)303 drd_info_rep::is_with_like (tree t) {
304 return info[L(t)]->pi.with_like && N(t) > 0;
305 }
306
307 /******************************************************************************
308 * The var_type determines whether the tag is a regular macro,
309 * or rather an environment variable (which could be a macro).
310 ******************************************************************************/
311
312 void
set_var_type(tree_label l,int vt)313 drd_info_rep::set_var_type (tree_label l, int vt) {
314 if (info[l]->pi.freeze_with) return;
315 if (!info->contains (l)) info(l)= copy (info[l]);
316 tag_info& ti= info(l);
317 ti->pi.var_type= vt;
318 }
319
320 int
get_var_type(tree_label l)321 drd_info_rep::get_var_type (tree_label l) {
322 return info[l]->pi.var_type;
323 }
324
325 void
freeze_var_type(tree_label l)326 drd_info_rep::freeze_var_type (tree_label l) {
327 if (!info->contains (l)) info(l)= copy (info[l]);
328 tag_info& ti= info(l);
329 ti->pi.freeze_with= true;
330 }
331
332 /******************************************************************************
333 * Other attributes
334 ******************************************************************************/
335
336 void
set_attribute(tree_label l,string which,tree val)337 drd_info_rep::set_attribute (tree_label l, string which, tree val) {
338 if (!info->contains (l)) info(l)= copy (info[l]);
339 tag_info& ti= info(l);
340 ti->set_attribute (which, val);
341 }
342
343 tree
get_attribute(tree_label l,string which)344 drd_info_rep::get_attribute (tree_label l, string which) {
345 tree val= info[l]->get_attribute (which);
346 if ((which == "name") && (val == ""))
347 return as_string (l);
348 return val;
349 }
350
351 void
set_name(tree_label l,string val)352 drd_info_rep::set_name (tree_label l, string val) {
353 set_attribute (l, "name", val);
354 }
355
356 void
set_long_name(tree_label l,string val)357 drd_info_rep::set_long_name (tree_label l, string val) {
358 set_attribute (l, "long-name", val);
359 }
360
361 void
set_syntax(tree_label l,tree val)362 drd_info_rep::set_syntax (tree_label l, tree val) {
363 set_attribute (l, "syntax", val);
364 }
365
366 string
get_name(tree_label l)367 drd_info_rep::get_name (tree_label l) {
368 return as_string (get_attribute (l, "name"));
369 }
370
371 string
get_long_name(tree_label l)372 drd_info_rep::get_long_name (tree_label l) {
373 string r= as_string (get_attribute (l, "long-name"));
374 if (r != "") return r;
375 return as_string (get_attribute (l, "name"));
376 }
377
378 tree
get_syntax(tree_label l)379 drd_info_rep::get_syntax (tree_label l) {
380 tree r= get_attribute (l, "syntax");
381 if (r != "") return r;
382 if (env->contains (as_string (l))) return env[as_string (l)];
383 return UNINIT;
384 }
385
386 static tree
replace(tree t,hashmap<tree,tree> h)387 replace (tree t, hashmap<tree,tree> h) {
388 if (h->contains (t)) return h[t];
389 else if (is_atomic (t)) return t;
390 else {
391 int i, n= N(t);
392 tree r (t, n);
393 for (i=0; i<n; i++)
394 r[i]= replace (t[i], h);
395 return r;
396 }
397 }
398
399 tree
get_syntax(tree t,path p)400 drd_info_rep::get_syntax (tree t, path p) {
401 if (is_func (t, VALUE, 1) && is_atomic (t[0])) {
402 string s= t[0]->label;
403 if (!existing_tree_label (s)) return UNINIT;
404 return get_syntax (as_tree_label (s));
405 }
406 else if (L(t) < START_EXTENSIONS || is_atomic (t))
407 return UNINIT;
408 else {
409 tree fun= the_drd->get_syntax (L(t));
410 if (fun == UNINIT) return UNINIT;
411 else if (N(t) == 0 && !is_func (fun, MACRO)) return fun;
412 else if (!is_func (fun, MACRO)) return UNINIT;
413 else {
414 int i, n= N(fun)-1;
415 hashmap<tree,tree> tab (UNINIT);
416 for (i=0; i<n; i++) {
417 tree var= tree (ARG, fun[i]);
418 tree val= "";
419 if (i < N(t)) {
420 if (p == path (-1)) val= t[i];
421 else val= tree (QUASI, t[i], (tree) (p * i));
422 }
423 tab (var)= val;
424 }
425 return replace (fun[n], tab);
426 }
427 }
428 }
429
430 /******************************************************************************
431 * Children's mode
432 ******************************************************************************/
433
434 void
set_type(tree_label l,int nr,int tp)435 drd_info_rep::set_type (tree_label l, int nr, int tp) {
436 if (!info->contains (l)) info(l)= copy (info[l]);
437 tag_info & ti= info(l);
438 if (nr >= N(ti->ci)) return;
439 child_info& ci= ti->ci[nr];
440 if (ci.freeze_type) return;
441 ci.type= tp;
442 }
443
444 int
get_type(tree_label l,int nr)445 drd_info_rep::get_type (tree_label l, int nr) {
446 if (nr >= N(info[l]->ci)) return TYPE_ADHOC;
447 return info[l]->ci[nr].type;
448 }
449
450 void
freeze_type(tree_label l,int nr)451 drd_info_rep::freeze_type (tree_label l, int nr) {
452 if (!info->contains (l)) info(l)= copy (info[l]);
453 tag_info & ti= info(l);
454 if (nr >= N(ti->ci)) return;
455 child_info& ci= ti->ci[nr];
456 ci.freeze_type= true;
457 }
458
459 int
get_type_child(tree t,int i)460 drd_info_rep::get_type_child (tree t, int i) {
461 tag_info ti= info[L(t)];
462 if (is_func (t, EXTERN) && N(t)>0 && is_atomic (t[0])) {
463 tree_label lab= make_tree_label ("extern:" * t[0]->label);
464 if (info->contains(lab)) { ti= info[lab]; }
465 else { ti = info(EXTERN); info(lab)= ti; }
466 }
467 int index= ti->get_index (i, N(t));
468 if ((index<0) || (index>=N(ti->ci))) return TYPE_INVALID;
469 int r= ti->ci[index].type;
470 if (r != TYPE_BINDING) return r;
471 if ((i & 1) == 0) return TYPE_VARIABLE;
472 return TYPE_REGULAR;
473 }
474
475 /******************************************************************************
476 * Children's accessability related methods
477 ******************************************************************************/
478
479 void
set_accessible(tree_label l,int nr,int is_accessible)480 drd_info_rep::set_accessible (tree_label l, int nr, int is_accessible) {
481 if (!info->contains (l)) info(l)= copy (info[l]);
482 tag_info & ti= info(l);
483 if (nr >= N(ti->ci)) return;
484 child_info& ci= ti->ci[nr];
485 if (ci.freeze_accessible) return;
486 ci.accessible= is_accessible;
487 }
488
489 int
get_accessible(tree_label l,int nr)490 drd_info_rep::get_accessible (tree_label l, int nr) {
491 if (nr >= N(info[l]->ci)) return ACCESSIBLE_NEVER;
492 return info[l]->ci[nr].accessible;
493 }
494
495 void
freeze_accessible(tree_label l,int nr)496 drd_info_rep::freeze_accessible (tree_label l, int nr) {
497 if (!info->contains (l)) info(l)= copy (info[l]);
498 tag_info & ti= info(l);
499 if (nr >= N(ti->ci)) return;
500 child_info& ci= ti->ci[nr];
501 ci.freeze_accessible= true;
502 }
503
504 bool
all_accessible(tree_label l)505 drd_info_rep::all_accessible (tree_label l) {
506 int i, n= N(info[l]->ci);
507 for (i=0; i<n; i++)
508 if (info[l]->ci[i].accessible != ACCESSIBLE_ALWAYS)
509 return false;
510 return n>0;
511 }
512
513 bool
none_accessible(tree_label l)514 drd_info_rep::none_accessible (tree_label l) {
515 int i, n= N(info[l]->ci);
516 for (i=0; i<n; i++)
517 if (info[l]->ci[i].accessible != ACCESSIBLE_NEVER)
518 return false;
519 return true;
520 }
521
522 bool
is_accessible_child(tree t,int i)523 drd_info_rep::is_accessible_child (tree t, int i) {
524 //cout << "l= " << as_string (L(t)) << "\n";
525 tag_info ti= info[L(t)];
526 if (is_func (t, EXTERN) && N(t)>0 && is_atomic (t[0])) {
527 tree_label lab= make_tree_label ("extern:" * t[0]->label);
528 if (info->contains(lab)) { ti= info[lab]; }
529 else { ti = info(EXTERN); info(lab)= ti; }
530 }
531 int index= ti->get_index (i, N(t));
532 if ((index<0) || (index>=N(ti->ci))) {
533 if (get_access_mode () == DRD_ACCESS_SOURCE)
534 return !is_atomic (t) && i >= 0 && i < N(t);
535 else return false;
536 }
537 switch (get_access_mode ()) {
538 case DRD_ACCESS_NORMAL:
539 return ti->ci[index].accessible == ACCESSIBLE_ALWAYS;
540 case DRD_ACCESS_HIDDEN:
541 return ti->ci[index].accessible == ACCESSIBLE_ALWAYS ||
542 ti->ci[index].accessible == ACCESSIBLE_HIDDEN;
543 case DRD_ACCESS_SOURCE:
544 return true;
545 }
546 return true; // NOT REACHED
547 }
548
549 bool
is_accessible_path(tree t,path p)550 drd_info_rep::is_accessible_path (tree t, path p) {
551 if (is_nil (p)) return true;
552 return
553 is_accessible_child (t, p->item) &&
554 (p->item < N(t)) &&
555 is_accessible_path (t[p->item], p->next);
556 }
557
558 /******************************************************************************
559 * Children's writability
560 ******************************************************************************/
561
562 void
set_writability(tree_label l,int nr,int writability)563 drd_info_rep::set_writability (tree_label l, int nr, int writability) {
564 if (!info->contains (l)) info(l)= copy (info[l]);
565 tag_info & ti= info(l);
566 if (nr >= N(ti->ci)) return;
567 child_info& ci= ti->ci[nr];
568 if (ci.freeze_writability) return;
569 ci.writability= writability;
570 }
571
572 int
get_writability(tree_label l,int nr)573 drd_info_rep::get_writability (tree_label l, int nr) {
574 if (nr >= N(info[l]->ci)) return WRITABILITY_NORMAL;
575 return info[l]->ci[nr].writability;
576 }
577
578 void
freeze_writability(tree_label l,int nr)579 drd_info_rep::freeze_writability (tree_label l, int nr) {
580 if (!info->contains (l)) info(l)= copy (info[l]);
581 tag_info & ti= info(l);
582 if (nr >= N(ti->ci)) return;
583 child_info& ci= ti->ci[nr];
584 ci.freeze_writability= true;
585 }
586
587 int
get_writability_child(tree t,int i)588 drd_info_rep::get_writability_child (tree t, int i) {
589 tag_info ti= info[L(t)];
590 if (is_func (t, EXTERN) && N(t)>0 && is_atomic (t[0])) {
591 tree_label lab= make_tree_label ("extern:" * t[0]->label);
592 if (info->contains(lab)) { ti= info[lab]; }
593 else { ti = info(EXTERN); info(lab)= ti; }
594 }
595 int index= ti->get_index (i, N(t));
596 if ((index<0) || (index>=N(ti->ci))) return WRITABILITY_DISABLE;
597 return ti->ci[index].writability;
598 }
599
600 /******************************************************************************
601 * Child names, based on set/get attribute for parent
602 ******************************************************************************/
603
604 void
set_child_name(tree_label l,int nr,string val)605 drd_info_rep::set_child_name (tree_label l, int nr, string val) {
606 set_attribute (l, "name-" * as_string (nr), val);
607 }
608
609 void
set_child_long_name(tree_label l,int nr,string val)610 drd_info_rep::set_child_long_name (tree_label l, int nr, string val) {
611 set_attribute (l, "long-name-" * as_string (nr), val);
612 }
613
614 string
get_child_name(tree_label l,int nr)615 drd_info_rep::get_child_name (tree_label l, int nr) {
616 return as_string (get_attribute (l, "name-" * as_string (nr)));
617 }
618
619 string
get_child_long_name(tree_label l,int nr)620 drd_info_rep::get_child_long_name (tree_label l, int nr) {
621 return as_string (get_attribute (l, "long-name-" * as_string (nr)));
622 }
623
624 string
get_child_name(tree t,int i)625 drd_info_rep::get_child_name (tree t, int i) {
626 tag_info ti= info[L(t)];
627 if (is_func (t, EXTERN) && N(t)>0 && is_atomic (t[0])) {
628 tree_label lab= make_tree_label ("extern:" * t[0]->label);
629 if (info->contains(lab)) { ti= info[lab]; }
630 else { ti = info(EXTERN); info(lab)= ti; }
631 }
632 int index= ti->get_index (i, N(t));
633 if ((index<0) || (index>=N(ti->ci))) return "";
634 return get_child_name (L(t), index);
635 }
636
637 string
get_child_long_name(tree t,int i)638 drd_info_rep::get_child_long_name (tree t, int i) {
639 tag_info ti= info[L(t)];
640 if (is_func (t, EXTERN) && N(t)>0 && is_atomic (t[0])) {
641 tree_label lab= make_tree_label ("extern:" * t[0]->label);
642 if (info->contains(lab)) { ti= info[lab]; }
643 else { ti = info(EXTERN); info(lab)= ti; }
644 }
645 int index= ti->get_index (i, N(t));
646 if ((index<0) || (index>=N(ti->ci))) return "";
647 string r= get_child_long_name (L(t), index);
648 if (r != "") return r;
649 return get_child_name (L(t), index);
650 }
651
652 /******************************************************************************
653 * Environment determination
654 ******************************************************************************/
655
656 tree
drd_env_write(tree env,string var,tree val)657 drd_env_write (tree env, string var, tree val) {
658 for (int i=0; i<=N(env); i+=2)
659 if (i == N(env))
660 return env * tree (ATTR, var, val);
661 else if (var <= env[i]->label) {
662 if (var == env[i]->label)
663 return env (0, i) * tree (ATTR, var, val) * env (i+2, N(env));
664 return env (0, i) * tree (ATTR, var, val) * env (i, N(env));
665 }
666 return env;
667 }
668
669 tree
drd_env_merge(tree env,tree t)670 drd_env_merge (tree env, tree t) {
671 int i, n= N(t);
672 for (i=0; (i+1)<n; i+=2)
673 if (is_atomic (t[i]))
674 env= drd_env_write (env, t[i]->label, t[i+1]);
675 return env;
676 }
677
678 tree
drd_env_read(tree env,string var,tree val)679 drd_env_read (tree env, string var, tree val) {
680 int i, n= N(env);
681 for (i=0; i<n; i+=2)
682 if (env[i] == var)
683 return env[i+1];
684 return val;
685 }
686
687 void
set_env(tree_label l,int nr,tree env)688 drd_info_rep::set_env (tree_label l, int nr, tree env) {
689 //if (as_string (l) == "section")
690 //cout << as_string (l) << ", " << nr << " -> " << env << "\n";
691 //if (as_string (l) == "session")
692 //cout << as_string (l) << ", " << nr << " -> " << env << "\n";
693 if (!info->contains (l)) info(l)= copy (info[l]);
694 tag_info & ti= info(l);
695 if (nr >= N(ti->ci)) return;
696 child_info& ci= ti->ci[nr];
697 if (ci.freeze_env) return;
698 ci.env= drd_encode (env);
699 }
700
701 tree
get_env(tree_label l,int nr)702 drd_info_rep::get_env (tree_label l, int nr) {
703 if (nr >= N(info[l]->ci)) return tree (ATTR);
704 return drd_decode (info[l]->ci[nr].env);
705 }
706
707 void
freeze_env(tree_label l,int nr)708 drd_info_rep::freeze_env (tree_label l, int nr) {
709 if (!info->contains (l)) info(l)= copy (info[l]);
710 tag_info & ti= info(l);
711 if (nr >= N(ti->ci)) return;
712 child_info& ci= ti->ci[nr];
713 ci.freeze_env= true;
714 }
715
716 tree
get_env_child(tree t,int i,tree env)717 drd_info_rep::get_env_child (tree t, int i, tree env) {
718 if (L(t) == WITH && i == N(t)-1)
719 return drd_env_merge (env, t (0, N(t)-1));
720 else {
721 /* makes cursor movement (is_accessible_cursor) slow for large preambles
722 if (L(t) == DOCUMENT && N(t) > 0 &&
723 (is_compound (t[0], "hide-preamble", 1) ||
724 is_compound (t[0], "show-preamble", 1)))
725 {
726 tree u= t[0][0];
727 if (!is_func (u, DOCUMENT)) u= tree (DOCUMENT, u);
728 tree cenv (ATTR);
729 for (int i=0; i<N(u); i++)
730 if (is_func (u[i], ASSIGN, 2))
731 cenv << copy (u[i][0]) << copy (u[i][1]);
732 env= drd_env_merge (env, cenv);
733 }
734 */
735
736 tag_info ti= info[L(t)];
737 int index= ti->get_index (i, N(t));
738 if ((index<0) || (index>=N(ti->ci))) return "";
739 tree cenv= drd_decode (ti->ci[index].env);
740 for (int i=1; i<N(cenv); i+=2)
741 if (is_func (cenv[i], ARG, 1) && is_int (cenv[i][0])) {
742 cenv= copy (cenv);
743 int j= as_int (cenv[i][0]);
744 if (j>=0 && j<N(t)) cenv[i]= copy (t[j]);
745 }
746 return drd_env_merge (env, cenv);
747 }
748 }
749
750 tree
get_env_child(tree t,int i,string var,tree val)751 drd_info_rep::get_env_child (tree t, int i, string var, tree val) {
752 tree env= get_env_child (t, i, tree (ATTR));
753 return drd_env_read (env, var, val);
754 }
755
756 tree
get_env_descendant(tree t,path p,tree env)757 drd_info_rep::get_env_descendant (tree t, path p, tree env) {
758 if (is_nil (p) || env == "") return env;
759 int i= p->item;
760 path q= p->next;
761 if (is_compound (t) && i >= 0 && i < N(t))
762 return get_env_descendant (t[i], q, get_env_child (t, i, env));
763 return "";
764 }
765
766 /******************************************************************************
767 * Heuristic initialization of DRD
768 ******************************************************************************/
769
770 void
set_environment(hashmap<string,tree> env2)771 drd_info_rep::set_environment (hashmap<string,tree> env2) {
772 env= env2;
773 }
774
775 tree
arg_access(tree t,tree arg,tree env,int & type)776 drd_info_rep::arg_access (tree t, tree arg, tree env, int& type) {
777 // returns "" if unaccessible and the env if accessible
778 //cout << " arg_access " << t << ", " << arg << ", " << env << "\n";
779 if (is_atomic (t)) return "";
780 else if (t == arg) return env;
781 else if (is_func (t, QUOTE_ARG, 1) && N(arg) == 1 && t[0] == arg[0])
782 return env;
783 else if (is_func (t, MAP_ARGS) && (t[2] == arg[0])) {
784 if ((N(t) >= 4) && (N(arg) >= 2) && (as_int (t[3]) > as_int (arg[1])))
785 return "";
786 if ((N(t) == 5) && (N(arg) >= 2) && (as_int (t[3]) <= as_int (arg[1])))
787 return "";
788 tree_label inner= make_tree_label (as_string (t[0]));
789 tree_label outer= make_tree_label (as_string (t[1]));
790 if (get_nr_indices (inner) > 0)
791 type= get_type_child (tree (inner, arg), 0);
792 if ((get_nr_indices (inner) > 0) &&
793 (get_accessible (inner, 0) == ACCESSIBLE_ALWAYS) &&
794 all_accessible (outer))
795 return env;
796 return "";
797 }
798 else if (is_func (t, MACRO)) return "";
799 else if (is_func (t, WITH)) {
800 int n= N(t)-1;
801 //cout << "env= " << drd_env_merge (env, t (0, n)) << "\n";
802 return arg_access (t[n], arg, drd_env_merge (env, t (0, n)), type);
803 }
804 else if (is_func (t, TFORMAT)) {
805 int n= N(t)-1;
806 tree oldf= drd_env_read (env, CELL_FORMAT, tree (TFORMAT));
807 tree newf= oldf * tree (TFORMAT, A (t (0, n)));
808 tree w = tree (ATTR, CELL_FORMAT, newf);
809 tree cenv= get_env_child (t, n, drd_env_merge (env, w));
810 return arg_access (t[n], arg, cenv, type);
811 }
812 else if (is_func (t, COMPOUND) && N(t) >= 1 && is_atomic (t[0]))
813 return arg_access (compound (t[0]->label, A (t (1, N(t)))),
814 arg, env, type);
815 else if ((is_func (t, IF) || is_func (t, VAR_IF)) && N(t) >= 2)
816 return arg_access (t[1], arg, env, type);
817 else {
818 int i, n= N(t);
819 for (i=0; i<n; i++) {
820 int ctype= get_type_child (t, i);
821 tree cenv = get_env_child (t, i, env);
822 tree aenv = arg_access (t[i], arg, cenv, ctype);
823 if (aenv != "") {
824 if (ctype != TYPE_INVALID) type= ctype;
825 if (is_accessible_child (t, i)) return aenv;
826 }
827 else if (type == TYPE_UNKNOWN &&
828 ctype != TYPE_INVALID &&
829 ctype != TYPE_UNKNOWN) {
830 type= ctype;
831 //cout << " found type " << t << ", " << arg << ", " << type << "\n";
832 }
833 }
834 return "";
835 }
836 }
837
838 static void
rewrite_symbolic_arguments(tree macro,tree & env)839 rewrite_symbolic_arguments (tree macro, tree& env) {
840 if (!is_func (env, ATTR)) return;
841 for (int i=1; i<N(env); i+=2)
842 if (is_func (env[i], ARG, 1)) {
843 for (int j=0; j+1<N(macro); j++)
844 if (macro[j] == env[i][0])
845 env[i]= tree (ARG, as_tree (j));
846 }
847 }
848
849 static bool
is_length(string s)850 is_length (string s) {
851 int i;
852 for (i=0; (i<N(s)) && ((s[i]<'a') || (s[i]>'z')); i++) {}
853 return is_double (s (0, i)) && is_locase_alpha (s (i, N(s)));
854 }
855
856 bool
heuristic_with_like(tree t,tree arg)857 drd_info_rep::heuristic_with_like (tree t, tree arg) {
858 if (arg == "") {
859 if (!is_func (t, MACRO) || N(t) < 2) return false;
860 return heuristic_with_like (t[N(t)-1], t[N(t)-2]);
861 }
862 else if (t == tree (ARG, arg))
863 return true;
864 else if (is_with_like (t))
865 return heuristic_with_like (t[N(t)-1], arg);
866 else return false;
867 }
868
869 bool
heuristic_init_macro(string var,tree macro)870 drd_info_rep::heuristic_init_macro (string var, tree macro) {
871 //cout << "init_macro " << var << " -> " << macro << "\n";
872 tree_label l = make_tree_label (var);
873 tag_info old_ti= copy (info[l]);
874 int i, n= N(macro)-1;
875 set_arity (l, n, 0, ARITY_NORMAL, CHILD_DETAILED);
876 if (n == 0 && is_compound (macro[0], "localize", 1) &&
877 is_atomic (macro[0][0])) {
878 set_type (l, TYPE_STRING);
879 set_var_type (l, VAR_MACRO_PARAMETER);
880 }
881 else if (n == 0 && is_atomic (macro[0]) &&
882 is_length (macro[0]->label)) {
883 set_type (l, TYPE_LENGTH);
884 set_var_type (l, VAR_MACRO_PARAMETER);
885 }
886 else set_type (l, get_type (macro[n]));
887 set_with_like (l, heuristic_with_like (macro, ""));
888 //if (heuristic_with_like (macro, ""))
889 //cout << "With-like: " << var << LF;
890 for (i=0; i<n; i++) {
891 if (is_atomic (macro[i]))
892 if (l >= START_EXTENSIONS || get_child_name (l, i) == "")
893 set_child_name (l, i, macro[i]->label);
894 int type= TYPE_UNKNOWN;
895 tree arg (ARG, macro[i]);
896 tree env= arg_access (macro[n], arg, tree (ATTR), type);
897 //if (var == "section" || var == "section-title")
898 //cout << var << " -> " << env << ", " << macro << "\n";
899 //if (var == "math")
900 //cout << var << ", " << i << " -> " << type << ", " << env << ", " << macro << "\n";
901 set_type (l, i, type);
902 if (env != "") {
903 //if (var == "eqnarray*")
904 //cout << var << " -> " << env << "\n";
905 //if (var == "session")
906 //cout << var << " = " << macro << ", " << i << " -> " << env << "\n";
907 rewrite_symbolic_arguments (macro, env);
908 set_accessible (l, i, ACCESSIBLE_ALWAYS);
909 set_env (l, i, env);
910 }
911 }
912 //if (old_ti != info[l])
913 //cout << var << ": " << old_ti << " -> " << info[l] << "\n";
914 return (old_ti != info[l]);
915 }
916
917 static int
minimal_arity(tree t,tree var)918 minimal_arity (tree t, tree var) {
919 if (is_atomic (t)) return 0;
920 else if (is_func (t, ARG, 2) && (t[0] == var))
921 return as_int (t[1]) + 1;
922 else if (is_func (t, MAP_ARGS) && (N(t)>=4) && (t[2] == var))
923 return as_int (t[3]);
924 else {
925 int i, n= N(t), m= 0;
926 for (i=0; i<n; i++)
927 m= max (m, minimal_arity (t[i], var));
928 return m;
929 }
930 }
931
932 bool
heuristic_init_xmacro(string var,tree xmacro)933 drd_info_rep::heuristic_init_xmacro (string var, tree xmacro) {
934 tree_label l = make_tree_label (var);
935 tag_info old_ti= copy (info[l]);
936 int i, m= minimal_arity (xmacro[1], xmacro[0]);
937 set_arity (l, m, 1, ARITY_REPEAT, CHILD_DETAILED);
938 set_type (l, get_type (xmacro[1]));
939 for (i=0; i<=m; i++) {
940 int type= TYPE_UNKNOWN;
941 tree arg (ARG, xmacro[0], as_string (i));
942 tree env= arg_access (xmacro[1], arg, tree (ATTR), type);
943 //cout << var << ", " << xmacro << ", " << i << " -> " << type << "\n";
944 set_type (l, i, type);
945 if (env != "") {
946 set_accessible (l, i, ACCESSIBLE_ALWAYS);
947 set_env (l, i, env);
948 }
949 }
950 // if (old_ti != info[l])
951 // cout << var << ": " << old_ti << " -> " << info[l] << "\n";
952 return (old_ti != info[l]);
953 }
954
955 bool
heuristic_init_parameter(string var,string val)956 drd_info_rep::heuristic_init_parameter (string var, string val) {
957 tree_label l = make_tree_label (var);
958 tag_info old_ti= copy (info[l]);
959 set_arity (l, 0, 0, ARITY_NORMAL, CHILD_UNIFORM);
960 set_var_type (l, VAR_PARAMETER);
961 if (ends (var, "-color")) set_type (l, TYPE_COLOR);
962 else if (ends (var, "-length")) set_type (l, TYPE_LENGTH);
963 else if (ends (var, "-width")) set_type (l, TYPE_LENGTH);
964 else if (val == "true" || val == "false") set_type (l, TYPE_BOOLEAN);
965 else if (is_int (val)) set_type (l, TYPE_INTEGER);
966 else if (is_double (val)) set_type (l, TYPE_NUMERIC);
967 else if (is_length (val)) set_type (l, TYPE_LENGTH);
968 else set_type (l, TYPE_STRING);
969 return (old_ti != info[l]);
970 }
971
972 bool
heuristic_init_parameter(string var,tree val)973 drd_info_rep::heuristic_init_parameter (string var, tree val) {
974 tree_label l = make_tree_label (var);
975 tag_info old_ti= copy (info[l]);
976 set_arity (l, 0, 0, ARITY_NORMAL, CHILD_UNIFORM);
977 set_var_type (l, VAR_PARAMETER);
978 if (ends (var, "-color")) set_type (l, TYPE_COLOR);
979 else if (ends (var, "-length")) set_type (l, TYPE_LENGTH);
980 else if (ends (var, "-width")) set_type (l, TYPE_LENGTH);
981 set_type (l, get_type (val));
982 return (old_ti != info[l]);
983 }
984
985 void
heuristic_init(hashmap<string,tree> env2)986 drd_info_rep::heuristic_init (hashmap<string,tree> env2) {
987 // time_t tt= texmacs_time ();
988 set_environment (env2);
989 bool flag= true;
990 int round= 0;
991 while (flag) {
992 // cout << HRULE;
993 flag= false;
994 iterator<string> it= iterate (env);
995 while (it->busy()) {
996 string var= it->next();
997 tree val= env[var];
998 if (is_atomic (val))
999 flag= heuristic_init_parameter (var, val->label) | flag;
1000 else if (is_func (val, MACRO))
1001 flag= heuristic_init_macro (var, val) | flag;
1002 else if (is_func (val, XMACRO))
1003 flag= heuristic_init_xmacro (var, val) | flag;
1004 else
1005 flag= heuristic_init_parameter (var, val) | flag;
1006 }
1007 if ((round++) == 10) {
1008 cout << "TeXmacs] Warning: bad heuristic drd convergence\n";
1009 flag= false;
1010 }
1011 }
1012 // cout << "--> " << (texmacs_time ()-tt) << "ms\n";
1013 }
1014