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