1 
2 /******************************************************************************
3 * MODULE     : tag_info.cpp
4 * DESCRIPTION: DRD information about tags
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 "tag_info.hpp"
13 #include "hashmap.hpp"
14 
15 #define get_bits(which,nr) which=i&((1<<nr)-1);i=i>>nr
16 #define set_bits(which,nr) i+=((int)which)<<offset;offset+=nr
17 
18 /******************************************************************************
19 * Compact representation for environment changes
20 ******************************************************************************/
21 
22 static hashmap<tree,int> encode_table (-1);
23 static array<tree>       decode_table;
24 
25 int
drd_encode(tree t)26 drd_encode (tree t) {
27   if (encode_table->contains (t))
28     return encode_table[t];
29   int n= N(decode_table);
30   ASSERT (n < (1 << 16), "drd_encode overflow");
31   encode_table (t) = n;
32   decode_table << t;
33   return n;
34 }
35 
36 tree
drd_decode(int i)37 drd_decode (int i) {
38   ASSERT (i >= 0 && i < N (decode_table), "out of range");
39   return decode_table[i];
40 }
41 
42 /******************************************************************************
43 * Names for drd types
44 ******************************************************************************/
45 
46 string
drd_decode_type(int i)47 drd_decode_type (int i) {
48   switch (i) {
49   case TYPE_REGULAR: return "regular";
50   case TYPE_ADHOC: return "adhoc";
51   case TYPE_VARIABLE: return "variable";
52   case TYPE_ARGUMENT: return "argument";
53   case TYPE_BOOLEAN: return "boolean";
54   case TYPE_INTEGER: return "integer";
55   case TYPE_STRING: return "string";
56   case TYPE_LENGTH: return "length";
57   case TYPE_NUMERIC: return "numeric";
58   case TYPE_CODE: return "code";
59   case TYPE_IDENTIFIER: return "identifier";
60   case TYPE_URL: return "url";
61   case TYPE_COLOR: return "color";
62   case TYPE_GRAPHICAL: return "graphical";
63   case TYPE_POINT: return "point";
64   case TYPE_ANIMATION: return "animation";
65   case TYPE_DURATION: return "duration";
66   case TYPE_UNKNOWN: return "unknown";
67   case TYPE_ERROR: return "error";
68   default: return "unknown";
69   }
70 }
71 
72 int
drd_encode_type(string s)73 drd_encode_type (string s) {
74   if (s == "regular") return TYPE_REGULAR;
75   else if (s == "adhoc") return TYPE_ADHOC;
76   else if (s == "variable") return TYPE_VARIABLE;
77   else if (s == "argument") return TYPE_ARGUMENT;
78   else if (s == "boolean") return TYPE_BOOLEAN;
79   else if (s == "integer") return TYPE_INTEGER;
80   else if (s == "string") return TYPE_STRING;
81   else if (s == "length") return TYPE_LENGTH;
82   else if (s == "numeric") return TYPE_NUMERIC;
83   else if (s == "code") return TYPE_CODE;
84   else if (s == "identifier") return TYPE_IDENTIFIER;
85   else if (s == "url") return TYPE_URL;
86   else if (s == "color") return TYPE_COLOR;
87   else if (s == "graphical") return TYPE_GRAPHICAL;
88   else if (s == "point") return TYPE_POINT;
89   else if (s == "animation") return TYPE_ANIMATION;
90   else if (s == "duration") return TYPE_DURATION;
91   else if (s == "unknown") return TYPE_UNKNOWN;
92   else if (s == "error") return TYPE_ERROR;
93   else return -1;
94 }
95 
96 /******************************************************************************
97 * Properties of the tag
98 ******************************************************************************/
99 
parent_info(int a,int x,int am,int cm,bool frozen)100 parent_info::parent_info (int a, int x, int am, int cm, bool frozen) {
101   type             = TYPE_REGULAR;
102   arity_mode       = am;
103   arity_base       = a;
104   arity_extra      = x;
105   child_mode       = cm;
106   border_mode      = BORDER_YES;
107   block            = BLOCK_NO;
108   with_like        = false;
109   var_type         = VAR_MACRO;
110   freeze_arity     = frozen;
111   freeze_border    = frozen;
112   freeze_block     = frozen;
113   freeze_with      = frozen;
114   freeze_var_type  = frozen;
115 }
116 
parent_info(tree t)117 parent_info::parent_info (tree t) {
118   long int i= as_long_int (t);
119   get_bits (type            , 5);
120   get_bits (arity_mode      , 2);
121   get_bits (arity_base      , 6);
122   get_bits (arity_extra     , 4);
123   get_bits (child_mode      , 2);
124   get_bits (border_mode     , 2);
125   get_bits (block           , 2);
126   get_bits (with_like       , 1);
127   get_bits (var_type        , 2);
128   get_bits (freeze_type     , 1);
129   get_bits (freeze_arity    , 1);
130   get_bits (freeze_border   , 1);
131   get_bits (freeze_block    , 1);
132   get_bits (freeze_with     , 1);
133   get_bits (freeze_var_type , 1);
134 }
135 
operator tree()136 parent_info::operator tree () {
137   long int i=0;
138   int offset=0;
139   set_bits (type            , 5);
140   set_bits (arity_mode      , 2);
141   set_bits (arity_base      , 6);
142   set_bits (arity_extra     , 4);
143   set_bits (child_mode      , 2);
144   set_bits (border_mode     , 2);
145   set_bits (block           , 2);
146   set_bits (with_like       , 1);
147   set_bits (var_type        , 2);
148   set_bits (freeze_type     , 1);
149   set_bits (freeze_arity    , 1);
150   set_bits (freeze_border   , 1);
151   set_bits (freeze_block    , 1);
152   set_bits (freeze_with     , 1);
153   set_bits (freeze_var_type , 1);
154   return as_string (i);
155 }
156 
157 bool
operator ==(const parent_info & pi)158 parent_info::operator == (const parent_info& pi) {
159   return
160     (type             == pi.type            ) &&
161     (arity_mode       == pi.arity_mode      ) &&
162     (arity_base       == pi.arity_base      ) &&
163     (arity_extra      == pi.arity_extra     ) &&
164     (child_mode       == pi.child_mode      ) &&
165     (border_mode      == pi.border_mode     ) &&
166     (block            == pi.block           ) &&
167     (with_like        == pi.with_like       ) &&
168     (var_type         == pi.var_type        ) &&
169     (freeze_arity     == pi.freeze_arity    ) &&
170     (freeze_border    == pi.freeze_border   ) &&
171     (freeze_block     == pi.freeze_block    ) &&
172     (freeze_with      == pi.freeze_with     ) &&
173     (freeze_var_type  == pi.freeze_var_type );
174 }
175 
176 bool
operator !=(const parent_info & pi)177 parent_info::operator != (const parent_info& pi) {
178   return !(operator == (pi));
179 }
180 
181 tm_ostream&
operator <<(tm_ostream & out,parent_info pi)182 operator << (tm_ostream& out, parent_info pi) {
183   return out << ((tree) pi);
184 }
185 
186 /******************************************************************************
187 * Properties of the children of the tag
188 ******************************************************************************/
189 
child_info(bool frozen)190 child_info::child_info (bool frozen) {
191   type               = TYPE_ADHOC;
192   accessible         = ACCESSIBLE_NEVER;
193   writability        = WRITABILITY_NORMAL;
194   block              = 0;
195   env                = drd_encode (tree (WITH));
196   freeze_type        = frozen;
197   freeze_accessible  = frozen;
198   freeze_writability = frozen;
199   freeze_block       = frozen;
200   freeze_env         = frozen;
201 }
202 
child_info(tree t)203 child_info::child_info (tree t) {
204   int i= as_int (is_atomic (t)? t: t[N(t)-1]);
205   get_bits (type              ,  5);
206   get_bits (accessible        ,  2);
207   get_bits (writability       ,  2);
208   get_bits (block             ,  2);
209   get_bits (freeze_type       ,  1);
210   get_bits (freeze_accessible ,  1);
211   get_bits (freeze_writability,  1);
212   get_bits (freeze_block      ,  1);
213   get_bits (freeze_env        ,  1);
214   if (is_atomic (t)) env= drd_encode (tree (WITH));
215   else env= drd_encode (t (0, N(t)-1));
216 }
217 
operator tree()218 child_info::operator tree () {
219   int i=0, offset=0;
220   set_bits (type              ,  5);
221   set_bits (accessible        ,  2);
222   set_bits (writability       ,  2);
223   set_bits (block             ,  2);
224   set_bits (freeze_type       ,  1);
225   set_bits (freeze_accessible ,  1);
226   set_bits (freeze_writability,  1);
227   set_bits (freeze_block      ,  1);
228   set_bits (freeze_env        ,  1);
229   if (drd_decode (env) == tree (WITH)) return as_string (i);
230   else return drd_decode (env) * tree (WITH, as_string (i));
231 }
232 
233 bool
operator ==(const child_info & ci)234 child_info::operator == (const child_info& ci) {
235   return
236     (type               == ci.type              ) &&
237     (accessible         == ci.accessible        ) &&
238     (writability        == ci.writability       ) &&
239     (block              == ci.block             ) &&
240     (env                == ci.env               ) &&
241     (freeze_type        == ci.freeze_type       ) &&
242     (freeze_accessible  == ci.freeze_accessible ) &&
243     (freeze_writability == ci.freeze_writability) &&
244     (freeze_block       == ci.freeze_block      ) &&
245     (freeze_env         == ci.freeze_env        );
246 }
247 
248 bool
operator !=(const child_info & ci)249 child_info::operator != (const child_info& ci) {
250   return !(operator == (ci));
251 }
252 
253 tm_ostream&
operator <<(tm_ostream & out,child_info ci)254 operator << (tm_ostream& out, child_info ci) {
255   return out << ((tree) ci);
256 }
257 
258 /******************************************************************************
259 * Constructors, destructors and converters
260 ******************************************************************************/
261 
tag_info_rep(parent_info pi2,array<child_info> ci2,tree x)262 tag_info_rep::tag_info_rep (parent_info pi2, array<child_info> ci2, tree x):
263   pi (pi2), ci (ci2), extra (x) {}
264 
tag_info_rep(int a,int x,int am,int cm,bool frozen)265 tag_info_rep::tag_info_rep (int a, int x, int am, int cm, bool frozen):
266   pi (a, x, am, cm, frozen),
267   ci ((a+x)==0? 0: (cm==CHILD_UNIFORM? 1: (cm==CHILD_BIFORM? 2: (a+x))))
268 {
269   if (frozen) {
270     int i, n= N(ci);
271     for (i=0; i<n; i++)
272       ci[i]= child_info (true);
273   }
274 }
275 
tag_info(parent_info pi,array<child_info> ci,tree extra)276 tag_info::tag_info (parent_info pi, array<child_info> ci, tree extra) {
277   rep= tm_new<tag_info_rep> (pi, ci, extra);
278 }
279 
tag_info(int a,int x,int am,int cm,bool frozen)280 tag_info::tag_info (int a, int x, int am, int cm, bool frozen) {
281   rep= tm_new<tag_info_rep> (a, x, am, cm, frozen);
282 }
283 
tag_info(tree t)284 tag_info::tag_info (tree t) {
285   if ((!is_func (t, TUPLE)) || (N(t)<2) || (L(t[1]) != TUPLE)) {
286     failed_error << "t= " << t << "\n";
287     FAILED ("bad tag_info");
288   }
289   parent_info pi (t[0]);
290   int i, n= N(t[1]);
291   array<child_info> ci (n);
292   for (i=0; i<n; i++)
293     ci[i]= child_info (t[1][i]);
294   rep= tm_new<tag_info_rep> (pi, ci, N(t)==3? t[2]: tree (""));
295 }
296 
operator tree()297 tag_info::operator tree () {
298   if (rep->extra == "") return tree (TUPLE, (tree) rep->pi, (tree) rep->ci);
299   else return tree (TUPLE, (tree) rep->pi, (tree) rep->ci, rep->extra);
300 }
301 
302 /******************************************************************************
303 * Access routines and getting the index of a child
304 ******************************************************************************/
305 
306 tag_info
inner_border()307 tag_info_rep::inner_border () {
308   pi.border_mode= BORDER_INNER;
309   return tag_info (pi, ci, extra);
310 }
311 
312 tag_info
outer_border()313 tag_info_rep::outer_border () {
314   pi.border_mode= BORDER_OUTER;
315   return tag_info (pi, ci, extra);
316 }
317 
318 tag_info
with_like()319 tag_info_rep::with_like () {
320   pi.with_like= true;
321   return tag_info (pi, ci, extra);
322 }
323 
324 tag_info
var_parameter()325 tag_info_rep::var_parameter () {
326   pi.var_type= VAR_PARAMETER;
327   return tag_info (pi, ci, extra);
328 }
329 
330 tag_info
var_macro_parameter()331 tag_info_rep::var_macro_parameter () {
332   pi.var_type= VAR_MACRO_PARAMETER;
333   return tag_info (pi, ci, extra);
334 }
335 
336 tag_info
type(int tp)337 tag_info_rep::type (int tp) {
338   pi.type= tp;
339   return tag_info (pi, ci, extra);
340 }
341 
342 tag_info
type(int i,int tp)343 tag_info_rep::type (int i, int tp) {
344   if (i < 0 || i >= N(ci)) cout << i << " out of " << N(ci) << "\n";
345   ASSERT (i >= 0 && i<N(ci), "index out of range");
346   ci[i].type= tp;
347   return tag_info (pi, ci, extra);
348 }
349 
350 tag_info
accessible(int i)351 tag_info_rep::accessible (int i) {
352   if (i < 0 || i >= N(ci)) cout << i << " out of " << N(ci) << "\n";
353   ASSERT (i >= 0 && i<N(ci), "index out of range");
354   ci[i].type= TYPE_REGULAR;
355   ci[i].accessible= ACCESSIBLE_ALWAYS;
356   return tag_info (pi, ci, extra);
357 }
358 
359 tag_info
hidden(int i)360 tag_info_rep::hidden (int i) {
361   if (i < 0 || i >= N(ci)) cout << i << " out of " << N(ci) << "\n";
362   ASSERT (i >= 0 && i<N(ci), "index out of range");
363   ci[i].type= TYPE_REGULAR;
364   ci[i].accessible= ACCESSIBLE_HIDDEN;
365   return tag_info (pi, ci, extra);
366 }
367 
368 tag_info
disable_writable(int i)369 tag_info_rep::disable_writable (int i) {
370   if (i < 0 || i >= N(ci)) cout << i << " out of " << N(ci) << "\n";
371   ASSERT (i >= 0 && i<N(ci), "index out of range");
372   ci[i].writability= WRITABILITY_DISABLE;
373   return tag_info (pi, ci, extra);
374 }
375 
376 tag_info
enable_writable(int i)377 tag_info_rep::enable_writable (int i) {
378   if (i < 0 || i >= N(ci)) cout << i << " out of " << N(ci) << "\n";
379   ASSERT (i >= 0 && i<N(ci), "index out of range");
380   ci[i].writability= WRITABILITY_ENABLE;
381   return tag_info (pi, ci, extra);
382 }
383 
384 tag_info
locals(int i,string var,string val)385 tag_info_rep::locals (int i, string var, string val) {
386   if (i < 0 || i >= N(ci)) cout << i << " out of " << N(ci) << "\n";
387   ASSERT (i >= 0 && i<N(ci), "index out of range");
388   ci[i].env= drd_encode (tree (ATTR, var, val));
389   return tag_info (pi, ci, extra);
390 }
391 
392 void
set_attribute(string which,tree val)393 tag_info_rep::set_attribute (string which, tree val) {
394   if (extra == "") extra= tree (ATTR);
395   for (int i=0; i+1<N(extra); i+=2)
396     if (extra[i] == tree (which)) {
397       extra[i+1]= val;
398       return;
399     }
400   extra << tree (which) << val;
401 }
402 
403 tree
get_attribute(string which)404 tag_info_rep::get_attribute (string which) {
405   if (!is_func (extra, ATTR)) return "";
406   int i, n= N(extra);
407   for (i=0; i+1<n; i+=2)
408     if (extra[i] == which)
409       return extra[i+1];
410   return "";
411 }
412 
413 tag_info
name(string s)414 tag_info_rep::name (string s) {
415   set_attribute ("name", s);
416   return tag_info (pi, ci, extra);
417 }
418 
419 tag_info
long_name(string s)420 tag_info_rep::long_name (string s) {
421   set_attribute ("long-name", s);
422   return tag_info (pi, ci, extra);
423 }
424 
425 tag_info
name(int i,string s)426 tag_info_rep::name (int i, string s) {
427   if (i < 0 || i >= N(ci)) cout << i << " out of " << N(ci) << "\n";
428   ASSERT (i >= 0 && i<N(ci), "index out of range");
429   set_attribute ("name-" * as_string (i), s);
430   return tag_info (pi, ci, extra);
431 }
432 
433 tag_info
long_name(int i,string s)434 tag_info_rep::long_name (int i, string s) {
435   if (i < 0 || i >= N(ci)) cout << i << " out of " << N(ci) << "\n";
436   ASSERT (i >= 0 && i<N(ci), "index out of range");
437   set_attribute ("long-name-" * as_string (i), s);
438   return tag_info (pi, ci, extra);
439 }
440 
441 int
get_index(int child,int n)442 tag_info_rep::get_index (int child, int n) {
443   int r= 0;
444   switch (pi.child_mode) {
445   case CHILD_UNIFORM:
446     r= 0;
447     break;
448   case CHILD_BIFORM:
449     if (pi.arity_mode != ARITY_VAR_REPEAT) {
450       if (child < ((int) pi.arity_base)) r= 0;
451       else r= 1;
452     }
453     else {
454       if (child < (n-((int) pi.arity_base))) r= 0;
455       else r= 1;
456     }
457     break;
458   case CHILD_DETAILED:
459     if (((int) pi.arity_mode) <= ARITY_OPTIONS)
460       r= child;
461     else if (pi.arity_mode == ARITY_REPEAT) {
462       if (child < ((int) pi.arity_base)) r= child;
463       else r= (child - pi.arity_base) % pi.arity_extra + pi.arity_base;
464     }
465     else {
466       if (child < (n-((int) pi.arity_base))) r= child % pi.arity_extra;
467       else r= pi.arity_base + pi.arity_extra + child - n;
468     }
469     break;
470   }
471   return r;
472 }
473 
474 child_info&
operator ()(int child,int n)475 tag_info::operator () (int child, int n) {
476   int index= rep->get_index (child, n);
477   if (index < 0 || index >= N(rep->ci)) {
478     failed_error << "child       = " << child << "\n";
479     failed_error << "out of      = " << n << "\n";
480     failed_error << "child_mode  = " << rep->pi.child_mode << "\n";
481     failed_error << "arity_mode  = " << rep->pi.arity_mode << "\n";
482     failed_error << "arity_base  = " << rep->pi.arity_base << "\n";
483     failed_error << "arity_extra = " << rep->pi.arity_extra << "\n";
484     failed_error << "N(ci)       = " << N(rep->ci) << "\n";
485     FAILED ("index out of range");
486   }
487   return rep->ci [index];
488 }
489 
490 /******************************************************************************
491 * Usual extra routines
492 ******************************************************************************/
493 
494 tm_ostream&
operator <<(tm_ostream & out,tag_info ti)495 operator << (tm_ostream& out, tag_info ti) {
496   out << "[ " << ti->pi << ", " << ti->ci;
497   if (ti->extra != "") out << ", " << ti->extra << "\n";
498   return out << " ]";
499 }
500 
501 tag_info
copy(tag_info ti)502 copy (tag_info ti) {
503   return tag_info (ti->pi, copy (ti->ci), copy (ti->extra));
504 }
505 
506 bool
operator ==(tag_info ti1,tag_info ti2)507 operator == (tag_info ti1, tag_info ti2) {
508   return
509     (ti1->pi == ti2->pi) && (ti1->ci == ti2->ci) && (ti1->extra == ti2->extra);
510 }
511 
512 bool
operator !=(tag_info ti1,tag_info ti2)513 operator != (tag_info ti1, tag_info ti2) {
514   return !(ti1 == ti2);
515 }
516