moids-misc.c
1 //! @file moids-misc.c
2 //! @author J. Marcel van der Veer
3
4 //! @section Copyright
5 //!
6 //! This file is part of Algol68G - an Algol 68 compiler-interpreter.
7 //! Copyright 2001-2024 J. Marcel van der Veer [algol68g@xs4all.nl].
8
9 //! @section License
10 //!
11 //! This program is free software; you can redistribute it and/or modify it
12 //! under the terms of the GNU General Public License as published by the
13 //! Free Software Foundation; either version 3 of the License, or
14 //! (at your option) any later version.
15 //!
16 //! This program is distributed in the hope that it will be useful, but
17 //! WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
18 //! or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
19 //! more details. You should have received a copy of the GNU General Public
20 //! License along with this program. If not, see [http://www.gnu.org/licenses/].
21
22 //! @section Synopsis
23 //!
24 //! Miscellaneous MOID routines.
25
26 #include "a68g.h"
27 #include "a68g-parser.h"
28 #include "a68g-moids.h"
29
30 // MODE checker routines.
31
32 //! @brief Absorb nested series modes recursively.
33
34 void absorb_series_pack (MOID_T ** p)
35 {
36 BOOL_T siga;
37 do {
38 PACK_T *z = NO_PACK;
39 siga = A68_FALSE;
40 for (PACK_T *t = PACK (*p); t != NO_PACK; FORWARD (t)) {
41 if (MOID (t) != NO_MOID && IS (MOID (t), SERIES_MODE)) {
42 siga = A68_TRUE;
43 for (PACK_T *s = PACK (MOID (t)); s != NO_PACK; FORWARD (s)) {
44 add_mode_to_pack (&z, MOID (s), NO_TEXT, NODE (s));
45 }
46 } else {
47 add_mode_to_pack (&z, MOID (t), NO_TEXT, NODE (t));
48 }
49 }
50 PACK (*p) = z;
51 } while (siga);
52 }
53
54 //! @brief Make SERIES (u, v).
55
56 MOID_T *make_series_from_moids (MOID_T * u, MOID_T * v)
57 {
58 MOID_T *x = new_moid ();
59 ATTRIBUTE (x) = SERIES_MODE;
60 add_mode_to_pack (&(PACK (x)), u, NO_TEXT, NODE (u));
61 add_mode_to_pack (&(PACK (x)), v, NO_TEXT, NODE (v));
62 absorb_series_pack (&x);
63 DIM (x) = count_pack_members (PACK (x));
64 (void) register_extra_mode (&TOP_MOID (&A68_JOB), x);
65 if (DIM (x) == 1) {
66 return MOID (PACK (x));
67 } else {
68 return x;
69 }
70 }
71
72 //! @brief Absorb firmly related unions in mode.
73
74 MOID_T *absorb_related_subsets (MOID_T * m)
75 {
76 // For instance invalid UNION (PROC REF UNION (A, B), A, B) -> valid UNION (A, B),
77 // which is used in balancing conformity clauses.
78 BOOL_T siga;
79 do {
80 PACK_T *u = NO_PACK;
81 siga = A68_FALSE;
82 for (PACK_T *v = PACK (m); v != NO_PACK; FORWARD (v)) {
83 MOID_T *n = depref_completely (MOID (v));
84 if (IS (n, UNION_SYMBOL) && is_subset (n, m, SAFE_DEFLEXING)) {
85 // Unpack it.
86 for (PACK_T *w = PACK (n); w != NO_PACK; FORWARD (w)) {
87 add_mode_to_pack (&u, MOID (w), NO_TEXT, NODE (w));
88 }
89 siga = A68_TRUE;
90 } else {
91 add_mode_to_pack (&u, MOID (v), NO_TEXT, NODE (v));
92 }
93 }
94 PACK (m) = absorb_union_pack (u);
95 } while (siga);
96 return m;
97 }
98
99 //! @brief Absorb nested series and united modes recursively.
100
101 void absorb_series_union_pack (MOID_T ** p)
102 {
103 BOOL_T siga;
104 do {
105 PACK_T *z = NO_PACK;
106 siga = A68_FALSE;
107 for (PACK_T *t = PACK (*p); t != NO_PACK; FORWARD (t)) {
108 if (MOID (t) != NO_MOID && (IS (MOID (t), SERIES_MODE) || IS (MOID (t), UNION_SYMBOL))) {
109 siga = A68_TRUE;
110 for (PACK_T *s = PACK (MOID (t)); s != NO_PACK; FORWARD (s)) {
111 add_mode_to_pack (&z, MOID (s), NO_TEXT, NODE (s));
112 }
113 } else {
114 add_mode_to_pack (&z, MOID (t), NO_TEXT, NODE (t));
115 }
116 }
117 PACK (*p) = z;
118 } while (siga);
119 }
120
121 //! @brief Make united mode, from mode that is a SERIES (..).
122
123 MOID_T *make_united_mode (MOID_T * m)
124 {
125 if (m == NO_MOID) {
126 return M_ERROR;
127 } else if (ATTRIBUTE (m) != SERIES_MODE) {
128 return m;
129 }
130 // Do not unite a single UNION.
131 if (DIM (m) == 1 && IS (MOID (PACK (m)), UNION_SYMBOL)) {
132 return MOID (PACK (m));
133 }
134 // Straighten the series.
135 absorb_series_union_pack (&m);
136 // Copy the series into a UNION.
137 MOID_T *u = new_moid ();
138 ATTRIBUTE (u) = UNION_SYMBOL;
139 PACK (u) = NO_PACK;
140 for (PACK_T *w = PACK (m); w != NO_PACK; FORWARD (w)) {
141 add_mode_to_pack (&(PACK (u)), MOID (w), NO_TEXT, NODE (m));
142 }
143 // Absorb and contract the new UNION.
144 absorb_series_union_pack (&u);
145 DIM (u) = count_pack_members (PACK (u));
146 PACK (u) = absorb_union_pack (PACK (u));
147 contract_union (u);
148 DIM (u) = count_pack_members (PACK (u));
149 // A UNION of one mode is that mode itself.
150 if (DIM (u) == 1) {
151 return MOID (PACK (u));
152 } else {
153 return register_extra_mode (&TOP_MOID (&A68_JOB), u);
154 }
155 }
156
157 //! @brief Make SOID data structure.
158
159 void make_soid (SOID_T * s, int sort, MOID_T * type, int attribute)
160 {
161 ATTRIBUTE (s) = attribute;
162 SORT (s) = sort;
163 MOID (s) = type;
164 CAST (s) = A68_FALSE;
165 }
166
167 //! @brief Whether mode is not well defined.
168
169 BOOL_T is_mode_isnt_well (MOID_T * p)
170 {
171 if (p == NO_MOID) {
172 return A68_TRUE;
173 } else if (!IF_MODE_IS_WELL (p)) {
174 return A68_TRUE;
175 } else if (PACK (p) != NO_PACK) {
176 for (PACK_T *q = PACK (p); q != NO_PACK; FORWARD (q)) {
177 if (!IF_MODE_IS_WELL (MOID (q))) {
178 return A68_TRUE;
179 }
180 }
181 }
182 return A68_FALSE;
183 }
184
185 //! @brief Add SOID data to free chain.
186
187 void free_soid_list (SOID_T * root)
188 {
189 if (root != NO_SOID) {
190 SOID_T *q = root;
191 for (; NEXT (q) != NO_SOID; FORWARD (q)) {
192 ;
193 }
194 NEXT (q) = A68 (top_soid_list);
195 A68 (top_soid_list) = root;
196 }
197 }
198
199 //! @brief Add SOID data structure to soid list.
200
201 void add_to_soid_list (SOID_T ** root, NODE_T * where, SOID_T * soid)
202 {
203 if (*root != NO_SOID) {
204 add_to_soid_list (&(NEXT (*root)), where, soid);
205 } else {
206 SOID_T *new_one;
207 if (A68 (top_soid_list) == NO_SOID) {
208 new_one = (SOID_T *) get_temp_heap_space ((size_t) SIZE_ALIGNED (SOID_T));
209 } else {
210 new_one = A68 (top_soid_list);
211 FORWARD (A68 (top_soid_list));
212 }
213 make_soid (new_one, SORT (soid), MOID (soid), 0);
214 NODE (new_one) = where;
215 NEXT (new_one) = NO_SOID;
216 *root = new_one;
217 }
218 }
219
220 //! @brief Pack soids in moid, gather resulting moids from terminators in a clause.
221
222 MOID_T *pack_soids_in_moid (SOID_T * top_sl, int attribute)
223 {
224 MOID_T *x = new_moid ();
225 PACK_T *t, **p;
226 ATTRIBUTE (x) = attribute;
227 DIM (x) = 0;
228 SUB (x) = NO_MOID;
229 EQUIVALENT (x) = NO_MOID;
230 SLICE (x) = NO_MOID;
231 DEFLEXED (x) = NO_MOID;
232 NAME (x) = NO_MOID;
233 NEXT (x) = NO_MOID;
234 PACK (x) = NO_PACK;
235 p = &(PACK (x));
236 for (; top_sl != NO_SOID; FORWARD (top_sl)) {
237 t = new_pack ();
238 MOID (t) = MOID (top_sl);
239 TEXT (t) = NO_TEXT;
240 NODE (t) = NODE (top_sl);
241 NEXT (t) = NO_PACK;
242 DIM (x)++;
243 *p = t;
244 p = &NEXT (t);
245 }
246 (void) register_extra_mode (&TOP_MOID (&A68_JOB), x);
247 return x;
248 }
249
250 //! @brief Whether "p" is compatible with "q".
251
252 BOOL_T is_equal_modes (MOID_T * p, MOID_T * q, int deflex)
253 {
254 if (deflex == FORCE_DEFLEXING) {
255 return DEFLEX (p) == DEFLEX (q);
256 } else if (deflex == ALIAS_DEFLEXING) {
257 if (IS (p, REF_SYMBOL) && IS (q, REF_SYMBOL)) {
258 return p == q || DEFLEX (p) == q;
259 } else if (!IS (p, REF_SYMBOL) && !IS (q, REF_SYMBOL)) {
260 return DEFLEX (p) == DEFLEX (q);
261 }
262 } else if (deflex == SAFE_DEFLEXING) {
263 if (!IS (p, REF_SYMBOL) && !IS (q, REF_SYMBOL)) {
264 return DEFLEX (p) == DEFLEX (q);
265 }
266 }
267 return p == q;
268 }
269
270 //! @brief Whether mode is deprefable.
271
272 BOOL_T is_deprefable (MOID_T * p)
273 {
274 if (IS_REF (p)) {
275 return A68_TRUE;
276 } else {
277 return (BOOL_T) (IS (p, PROC_SYMBOL) && PACK (p) == NO_PACK);
278 }
279 }
280
281 //! @brief Depref mode once.
282
283 MOID_T *depref_once (MOID_T * p)
284 {
285 if (IS_REF_FLEX (p)) {
286 return SUB_SUB (p);
287 } else if (IS_REF (p)) {
288 return SUB (p);
289 } else if (IS (p, PROC_SYMBOL) && PACK (p) == NO_PACK) {
290 return SUB (p);
291 } else {
292 return NO_MOID;
293 }
294 }
295
296 //! @brief Depref mode completely.
297
298 MOID_T *depref_completely (MOID_T * p)
299 {
300 while (is_deprefable (p)) {
301 p = depref_once (p);
302 }
303 return p;
304 }
305
306 //! @brief Deproc_completely.
307
308 MOID_T *deproc_completely (MOID_T * p)
309 {
310 while (IS (p, PROC_SYMBOL) && PACK (p) == NO_PACK) {
311 p = depref_once (p);
312 }
313 return p;
314 }
315
316 //! @brief Depref rows.
317
318 MOID_T *depref_rows (MOID_T * p, MOID_T * q)
319 {
320 if (q == M_ROWS) {
321 while (is_deprefable (p)) {
322 p = depref_once (p);
323 }
324 return p;
325 } else {
326 return q;
327 }
328 }
329
330 //! @brief Derow mode, strip FLEX and BOUNDS.
331
332 MOID_T *derow (MOID_T * p)
333 {
334 if (IS_ROW (p) || IS_FLEX (p)) {
335 return derow (SUB (p));
336 } else {
337 return p;
338 }
339 }
340
341 //! @brief Whether rows type.
342
343 BOOL_T is_rows_type (MOID_T * p)
344 {
345 switch (ATTRIBUTE (p)) {
346 case ROW_SYMBOL:
347 case FLEX_SYMBOL: {
348 return A68_TRUE;
349 }
350 case UNION_SYMBOL: {
351 PACK_T *t = PACK (p);
352 BOOL_T siga = A68_TRUE;
353 while (t != NO_PACK && siga) {
354 siga &= is_rows_type (MOID (t));
355 FORWARD (t);
356 }
357 return siga;
358 }
359 default: {
360 return A68_FALSE;
361 }
362 }
363 }
364
365 //! @brief Whether mode is PROC (REF FILE) VOID or FORMAT.
366
367 BOOL_T is_proc_ref_file_void_or_format (const MOID_T * p)
368 {
369 if (p == M_PROC_REF_FILE_VOID) {
370 return A68_TRUE;
371 } else if (p == M_FORMAT) {
372 return A68_TRUE;
373 } else {
374 return A68_FALSE;
375 }
376 }
377
378 //! @brief Whether mode can be transput.
379
380 BOOL_T is_transput_mode (MOID_T * p, char rw)
381 {
382 if (p == M_INT) {
383 return A68_TRUE;
384 } else if (p == M_LONG_INT) {
385 return A68_TRUE;
386 } else if (p == M_LONG_LONG_INT) {
387 return A68_TRUE;
388 } else if (p == M_REAL) {
389 return A68_TRUE;
390 } else if (p == M_LONG_REAL) {
391 return A68_TRUE;
392 } else if (p == M_LONG_LONG_REAL) {
393 return A68_TRUE;
394 } else if (p == M_BOOL) {
395 return A68_TRUE;
396 } else if (p == M_CHAR) {
397 return A68_TRUE;
398 } else if (p == M_BITS) {
399 return A68_TRUE;
400 } else if (p == M_LONG_BITS) {
401 return A68_TRUE;
402 } else if (p == M_LONG_LONG_BITS) {
403 return A68_TRUE;
404 } else if (p == M_COMPLEX) {
405 return A68_TRUE;
406 } else if (p == M_LONG_COMPLEX) {
407 return A68_TRUE;
408 } else if (p == M_LONG_LONG_COMPLEX) {
409 return A68_TRUE;
410 } else if (p == M_ROW_CHAR) {
411 return A68_TRUE;
412 } else if (p == M_STRING) {
413 return A68_TRUE;
414 } else if (p == M_SOUND) {
415 return A68_TRUE;
416 } else if (IS (p, UNION_SYMBOL) || IS (p, STRUCT_SYMBOL)) {
417 for (PACK_T *q = PACK (p); q != NO_PACK; FORWARD (q)) {
418 if (! (is_transput_mode (MOID (q), rw) || is_proc_ref_file_void_or_format (MOID (q)))) {
419 return A68_FALSE;
420 }
421 }
422 return A68_TRUE;
423 } else if (IS_FLEX (p)) {
424 if (SUB (p) == M_ROW_CHAR) {
425 return A68_TRUE;
426 } else {
427 return (BOOL_T) (rw == 'w' ? is_transput_mode (SUB (p), rw) : A68_FALSE);
428 }
429 } else if (IS_ROW (p)) {
430 return (BOOL_T) (is_transput_mode (SUB (p), rw) || is_proc_ref_file_void_or_format (SUB (p)));
431 } else {
432 return A68_FALSE;
433 }
434 }
435
436 //! @brief Whether mode is printable.
437
438 BOOL_T is_printable_mode (MOID_T * p)
439 {
440 if (is_proc_ref_file_void_or_format (p)) {
441 return A68_TRUE;
442 } else {
443 return is_transput_mode (p, 'w');
444 }
445 }
446
447 //! @brief Whether mode is readable.
448
449 BOOL_T is_readable_mode (MOID_T * p)
450 {
451 if (is_proc_ref_file_void_or_format (p)) {
452 return A68_TRUE;
453 } else if (IS_REF (p)) {
454 return is_transput_mode (SUB (p), 'r');
455 } else if (IS_UNION (p)) {
456 for (PACK_T *q = PACK (p); q != NO_PACK; FORWARD (q)) {
457 if (!IS_REF (MOID (q))) {
458 return A68_FALSE;
459 } else if (!is_transput_mode (SUB (MOID (q)), 'r')) {
460 return A68_FALSE;
461 }
462 }
463 return A68_TRUE;
464 } else {
465 return A68_FALSE;
466 }
467 }
468
469 //! @brief Whether name struct.
470
471 BOOL_T is_name_struct (MOID_T * p)
472 {
473 return (BOOL_T) (NAME (p) != NO_MOID ? IS (DEFLEX (SUB (p)), STRUCT_SYMBOL) : A68_FALSE);
474 }
475
476 //! @brief Yield mode to unite to.
477
478 MOID_T *unites_to (MOID_T * m, MOID_T * u)
479 {
480 // Uniting U (m).
481 MOID_T *v = NO_MOID;
482 if (u == M_SIMPLIN || u == M_SIMPLOUT) {
483 return m;
484 }
485 for (PACK_T *p = PACK (u); p != NO_PACK; FORWARD (p)) {
486 // Prefer []->[] over []->FLEX [].
487 if (m == MOID (p)) {
488 v = MOID (p);
489 } else if (v == NO_MOID && DEFLEX (m) == DEFLEX (MOID (p))) {
490 v = MOID (p);
491 }
492 }
493 return v;
494 }
495
496 //! @brief Whether moid in pack.
497
498 BOOL_T is_moid_in_pack (MOID_T * u, PACK_T * v, int deflex)
499 {
500 for (; v != NO_PACK; FORWARD (v)) {
501 if (is_equal_modes (u, MOID (v), deflex)) {
502 return A68_TRUE;
503 }
504 }
505 return A68_FALSE;
506 }
507
508 //! @brief Whether "p" is a subset of "q".
509
510 BOOL_T is_subset (MOID_T * p, MOID_T * q, int deflex)
511 {
512 BOOL_T j = A68_TRUE;
513 for (PACK_T *u = PACK (p); u != NO_PACK && j; FORWARD (u)) {
514 j = (BOOL_T) (j && is_moid_in_pack (MOID (u), PACK (q), deflex));
515 }
516 return j;
517 }
518
519 //! @brief Whether "p" can be united to UNION "q".
520
521 BOOL_T is_unitable (MOID_T * p, MOID_T * q, int deflex)
522 {
523 if (IS (q, UNION_SYMBOL)) {
524 if (IS (p, UNION_SYMBOL)) {
525 return is_subset (p, q, deflex);
526 } else {
527 return is_moid_in_pack (p, PACK (q), deflex);
528 }
529 }
530 return A68_FALSE;
531 }
532
533 //! @brief Whether all or some components of "u" can be firmly coerced to a component mode of "v"..
534
535 void investigate_firm_relations (PACK_T * u, PACK_T * v, BOOL_T * all, BOOL_T * some)
536 {
537 *all = A68_TRUE;
538 *some = A68_FALSE;
539 for (; v != NO_PACK; FORWARD (v)) {
540 BOOL_T k = A68_FALSE;
541 for (PACK_T *w = u; w != NO_PACK; FORWARD (w)) {
542 k |= is_coercible (MOID (w), MOID (v), FIRM, FORCE_DEFLEXING);
543 }
544 *some |= k;
545 *all &= k;
546 }
547 }
548
549 //! @brief Whether there is a soft path from "p" to "q".
550
551 BOOL_T is_softly_coercible (MOID_T * p, MOID_T * q, int deflex)
552 {
553 if (is_equal_modes (p, q, deflex)) {
554 return A68_TRUE;
555 } else if (IS (p, PROC_SYMBOL) && PACK (p) == NO_PACK) {
556 return is_softly_coercible (SUB (p), q, deflex);
557 } else {
558 return A68_FALSE;
559 }
560 }
561
562 //! @brief Whether there is a weak path from "p" to "q".
563
564 BOOL_T is_weakly_coercible (MOID_T * p, MOID_T * q, int deflex)
565 {
566 if (is_equal_modes (p, q, deflex)) {
567 return A68_TRUE;
568 } else if (is_deprefable (p)) {
569 return is_weakly_coercible (depref_once (p), q, deflex);
570 } else {
571 return A68_FALSE;
572 }
573 }
574
575 //! @brief Whether there is a meek path from "p" to "q".
576
577 BOOL_T is_meekly_coercible (MOID_T * p, MOID_T * q, int deflex)
578 {
579 if (is_equal_modes (p, q, deflex)) {
580 return A68_TRUE;
581 } else if (is_deprefable (p)) {
582 return is_meekly_coercible (depref_once (p), q, deflex);
583 } else {
584 return A68_FALSE;
585 }
586 }
587
588 //! @brief Whether there is a firm path from "p" to "q".
589
590 BOOL_T is_firmly_coercible (MOID_T * p, MOID_T * q, int deflex)
591 {
592 if (is_equal_modes (p, q, deflex)) {
593 return A68_TRUE;
594 } else if (q == M_ROWS && is_rows_type (p)) {
595 return A68_TRUE;
596 } else if (is_unitable (p, q, deflex)) {
597 return A68_TRUE;
598 } else if (is_deprefable (p)) {
599 return is_firmly_coercible (depref_once (p), q, deflex);
600 } else {
601 return A68_FALSE;
602 }
603 }
604
605 //! @brief Whether firm.
606
607 BOOL_T is_firm (MOID_T * p, MOID_T * q)
608 {
609 return (BOOL_T) (is_firmly_coercible (p, q, SAFE_DEFLEXING) || is_firmly_coercible (q, p, SAFE_DEFLEXING));
610 }
611
612 //! @brief Whether "p" widens to "q".
613
614 MOID_T *widens_to (const MOID_T * p, const MOID_T * q)
615 {
616 if (p == M_INT) {
617 if (q == M_LONG_INT || q == M_LONG_LONG_INT || q == M_LONG_REAL || q == M_LONG_LONG_REAL || q == M_LONG_COMPLEX || q == M_LONG_LONG_COMPLEX) {
618 return M_LONG_INT;
619 } else if (q == M_REAL || q == M_COMPLEX) {
620 return M_REAL;
621 } else {
622 return NO_MOID;
623 }
624 } else if (p == M_LONG_INT) {
625 if (q == M_LONG_LONG_INT) {
626 return M_LONG_LONG_INT;
627 } else if (q == M_LONG_REAL || q == M_LONG_LONG_REAL || q == M_LONG_COMPLEX || q == M_LONG_LONG_COMPLEX) {
628 return M_LONG_REAL;
629 } else {
630 return NO_MOID;
631 }
632 } else if (p == M_LONG_LONG_INT) {
633 if (q == M_LONG_LONG_REAL || q == M_LONG_LONG_COMPLEX) {
634 return M_LONG_LONG_REAL;
635 } else {
636 return NO_MOID;
637 }
638 } else if (p == M_REAL) {
639 if (q == M_LONG_REAL || q == M_LONG_LONG_REAL || q == M_LONG_COMPLEX || q == M_LONG_LONG_COMPLEX) {
640 return M_LONG_REAL;
641 } else if (q == M_COMPLEX) {
642 return M_COMPLEX;
643 } else {
644 return NO_MOID;
645 }
646 } else if (p == M_COMPLEX) {
647 if (q == M_LONG_COMPLEX || q == M_LONG_LONG_COMPLEX) {
648 return M_LONG_COMPLEX;
649 } else {
650 return NO_MOID;
651 }
652 } else if (p == M_LONG_REAL) {
653 if (q == M_LONG_LONG_REAL || q == M_LONG_LONG_COMPLEX) {
654 return M_LONG_LONG_REAL;
655 } else if (q == M_LONG_COMPLEX) {
656 return M_LONG_COMPLEX;
657 } else {
658 return NO_MOID;
659 }
660 } else if (p == M_LONG_COMPLEX) {
661 if (q == M_LONG_LONG_COMPLEX) {
662 return M_LONG_LONG_COMPLEX;
663 } else {
664 return NO_MOID;
665 }
666 } else if (p == M_LONG_LONG_REAL) {
667 if (q == M_LONG_LONG_COMPLEX) {
668 return M_LONG_LONG_COMPLEX;
669 } else {
670 return NO_MOID;
671 }
672 } else if (p == M_BITS) {
673 if (q == M_LONG_BITS || q == M_LONG_LONG_BITS) {
674 return M_LONG_BITS;
675 } else if (q == M_ROW_BOOL) {
676 return M_ROW_BOOL;
677 } else if (q == M_FLEX_ROW_BOOL) {
678 return M_FLEX_ROW_BOOL;
679 } else {
680 return NO_MOID;
681 }
682 } else if (p == M_LONG_BITS) {
683 if (q == M_LONG_LONG_BITS) {
684 return M_LONG_LONG_BITS;
685 } else if (q == M_ROW_BOOL) {
686 return M_ROW_BOOL;
687 } else if (q == M_FLEX_ROW_BOOL) {
688 return M_FLEX_ROW_BOOL;
689 } else {
690 return NO_MOID;
691 }
692 } else if (p == M_LONG_LONG_BITS) {
693 if (q == M_ROW_BOOL) {
694 return M_ROW_BOOL;
695 } else if (q == M_FLEX_ROW_BOOL) {
696 return M_FLEX_ROW_BOOL;
697 } else {
698 return NO_MOID;
699 }
700 } else if (p == M_BYTES && q == M_ROW_CHAR) {
701 return M_ROW_CHAR;
702 } else if (p == M_LONG_BYTES && q == M_ROW_CHAR) {
703 return M_ROW_CHAR;
704 } else if (p == M_BYTES && q == M_FLEX_ROW_CHAR) {
705 return M_FLEX_ROW_CHAR;
706 } else if (p == M_LONG_BYTES && q == M_FLEX_ROW_CHAR) {
707 return M_FLEX_ROW_CHAR;
708 } else {
709 return NO_MOID;
710 }
711 }
712
713 //! @brief Whether "p" widens to "q".
714
715 BOOL_T is_widenable (MOID_T * p, MOID_T * q)
716 {
717 MOID_T *z = widens_to (p, q);
718 if (z != NO_MOID) {
719 return (BOOL_T) (z == q ? A68_TRUE : is_widenable (z, q));
720 } else {
721 return A68_FALSE;
722 }
723 }
724
725 //! @brief Whether "p" is a REF ROW.
726
727 BOOL_T is_ref_row (MOID_T * p)
728 {
729 return (BOOL_T) (NAME (p) != NO_MOID ? IS_ROW (DEFLEX (SUB (p))) : A68_FALSE);
730 }
731
732 //! @brief Whether strong name.
733
734 BOOL_T is_strong_name (MOID_T * p, MOID_T * q)
735 {
736 if (p == q) {
737 return A68_TRUE;
738 } else if (is_ref_row (q)) {
739 return is_strong_name (p, NAME (q));
740 } else {
741 return A68_FALSE;
742 }
743 }
744
745 //! @brief Whether strong slice.
746
747 BOOL_T is_strong_slice (MOID_T * p, MOID_T * q)
748 {
749 if (p == q || is_widenable (p, q)) {
750 return A68_TRUE;
751 } else if (SLICE (q) != NO_MOID) {
752 return is_strong_slice (p, SLICE (q));
753 } else if (IS_FLEX (q)) {
754 return is_strong_slice (p, SUB (q));
755 } else if (is_ref_row (q)) {
756 return is_strong_name (p, q);
757 } else {
758 return A68_FALSE;
759 }
760 }
761
762 //! @brief Whether strongly coercible.
763
764 BOOL_T is_strongly_coercible (MOID_T * p, MOID_T * q, int deflex)
765 {
766 // Keep this sequence of statements.
767 if (is_equal_modes (p, q, deflex)) {
768 return A68_TRUE;
769 } else if (q == M_VOID) {
770 return A68_TRUE;
771 } else if ((q == M_SIMPLIN || q == M_ROW_SIMPLIN) && is_readable_mode (p)) {
772 return A68_TRUE;
773 } else if (q == M_ROWS && is_rows_type (p)) {
774 return A68_TRUE;
775 } else if (is_unitable (p, derow (q), deflex)) {
776 return A68_TRUE;
777 }
778 if (is_ref_row (q) && is_strong_name (p, q)) {
779 return A68_TRUE;
780 } else if (SLICE (q) != NO_MOID && is_strong_slice (p, q)) {
781 return A68_TRUE;
782 } else if (IS_FLEX (q) && is_strong_slice (p, q)) {
783 return A68_TRUE;
784 } else if (is_widenable (p, q)) {
785 return A68_TRUE;
786 } else if (is_deprefable (p)) {
787 return is_strongly_coercible (depref_once (p), q, deflex);
788 } else if (q == M_SIMPLOUT || q == M_ROW_SIMPLOUT) {
789 return is_printable_mode (p);
790 } else {
791 return A68_FALSE;
792 }
793 }
794
795 //! @brief Basic coercions.
796
797 BOOL_T basic_coercions (MOID_T * p, MOID_T * q, int c, int deflex)
798 {
799 if (is_equal_modes (p, q, deflex)) {
800 return A68_TRUE;
801 } else if (c == NO_SORT) {
802 return (BOOL_T) (p == q);
803 } else if (c == SOFT) {
804 return is_softly_coercible (p, q, deflex);
805 } else if (c == WEAK) {
806 return is_weakly_coercible (p, q, deflex);
807 } else if (c == MEEK) {
808 return is_meekly_coercible (p, q, deflex);
809 } else if (c == FIRM) {
810 return is_firmly_coercible (p, q, deflex);
811 } else if (c == STRONG) {
812 return is_strongly_coercible (p, q, deflex);
813 } else {
814 return A68_FALSE;
815 }
816 }
817
818 //! @brief Whether coercible stowed.
819
820 BOOL_T is_coercible_stowed (MOID_T * p, MOID_T * q, int c, int deflex)
821 {
822 if (c != STRONG) {
823 // Such construct is always in a strong position, is it not?
824 return A68_FALSE;
825 } else if (q == M_VOID) {
826 return A68_TRUE;
827 } else if (IS_FLEX (q)) {
828 BOOL_T j = A68_TRUE;
829 for (PACK_T *u = PACK (p); u != NO_PACK && j; FORWARD (u)) {
830 j &= is_coercible (MOID (u), SLICE (SUB (q)), c, deflex);
831 }
832 return j;
833 } else if (IS_ROW (q)) {
834 BOOL_T j = A68_TRUE;
835 for (PACK_T *u = PACK (p); u != NO_PACK && j; FORWARD (u)) {
836 j &= is_coercible (MOID (u), SLICE (q), c, deflex);
837 }
838 return j;
839 } else if (IS (q, PROC_SYMBOL) || IS (q, STRUCT_SYMBOL)) {
840 if (DIM (p) != DIM (q)) {
841 return A68_FALSE;
842 } else {
843 PACK_T *u = PACK (p), *v = PACK (q);
844 BOOL_T j = A68_TRUE;
845 while (u != NO_PACK && v != NO_PACK && j) {
846 j &= is_coercible (MOID (u), MOID (v), c, deflex);
847 FORWARD (u);
848 FORWARD (v);
849 }
850 return j;
851 }
852 } else {
853 return A68_FALSE;
854 }
855 }
856
857 //! @brief Whether coercible series.
858
859 BOOL_T is_coercible_series (MOID_T * p, MOID_T * q, int c, int deflex)
860 {
861 if (c == NO_SORT) {
862 return A68_FALSE;
863 } else if (p == NO_MOID || q == NO_MOID) {
864 return A68_FALSE;
865 } else if (IS (p, SERIES_MODE) && PACK (p) == NO_PACK) {
866 return A68_FALSE;
867 } else if (IS (q, SERIES_MODE) && PACK (q) == NO_PACK) {
868 return A68_FALSE;
869 } else if (PACK (p) == NO_PACK) {
870 return is_coercible (p, q, c, deflex);
871 } else {
872 BOOL_T j = A68_TRUE;
873 for (PACK_T *u = PACK (p); u != NO_PACK && j; FORWARD (u)) {
874 if (MOID (u) != NO_MOID) {
875 j &= is_coercible (MOID (u), q, c, deflex);
876 }
877 }
878 return j;
879 }
880 }
881
882 //! @brief Whether "p" can be coerced to "q" in a "c" context.
883
884 BOOL_T is_coercible (MOID_T * p, MOID_T * q, int c, int deflex)
885 {
886 if (is_mode_isnt_well (p) || is_mode_isnt_well (q)) {
887 return A68_TRUE;
888 } else if (is_equal_modes (p, q, deflex)) {
889 return A68_TRUE;
890 } else if (p == M_HIP) {
891 return A68_TRUE;
892 } else if (IS (p, STOWED_MODE)) {
893 return is_coercible_stowed (p, q, c, deflex);
894 } else if (IS (p, SERIES_MODE)) {
895 return is_coercible_series (p, q, c, deflex);
896 } else if (p == M_VACUUM && IS_ROW (DEFLEX (q))) {
897 return A68_TRUE;
898 } else {
899 return basic_coercions (p, q, c, deflex);
900 }
901 }
902
903 //! @brief Whether coercible in context.
904
905 BOOL_T is_coercible_in_context (SOID_T * p, SOID_T * q, int deflex)
906 {
907 if (SORT (p) != SORT (q)) {
908 return A68_FALSE;
909 } else if (MOID (p) == MOID (q)) {
910 return A68_TRUE;
911 } else {
912 return is_coercible (MOID (p), MOID (q), SORT (q), deflex);
913 }
914 }
915
916 //! @brief Whether list "y" is balanced.
917
918 BOOL_T is_balanced (NODE_T * n, SOID_T * y, int sort)
919 {
920 if (sort == STRONG) {
921 return A68_TRUE;
922 } else {
923 BOOL_T k = A68_FALSE;
924 for (; y != NO_SOID && !k; FORWARD (y)) {
925 k = (BOOL_T) (!IS (MOID (y), STOWED_MODE));
926 }
927 if (k == A68_FALSE) {
928 diagnostic (A68_ERROR, n, ERROR_NO_UNIQUE_MODE);
929 }
930 return k;
931 }
932 }
933
934 //! @brief A moid from "m" to which all other members can be coerced.
935
936 MOID_T *get_balanced_mode (MOID_T * m, int sort, BOOL_T return_depreffed, int deflex)
937 {
938 MOID_T *common_moid = NO_MOID;
939 if (m != NO_MOID && !is_mode_isnt_well (m) && IS (m, UNION_SYMBOL)) {
940 int depref_level;
941 BOOL_T siga = A68_TRUE;
942 // Test for increasing depreffing.
943 for (depref_level = 0; siga; depref_level++) {
944 siga = A68_FALSE;
945 // Test the whole pack.
946 for (PACK_T *p = PACK (m); p != NO_PACK; FORWARD (p)) {
947 // HIPs are not eligible of course.
948 if (MOID (p) != M_HIP) {
949 MOID_T *candidate = MOID (p);
950 int k;
951 // Depref as far as allowed.
952 for (k = depref_level; k > 0 && is_deprefable (candidate); k--) {
953 candidate = depref_once (candidate);
954 }
955 // Only need testing if all allowed deprefs succeeded.
956 if (k == 0) {
957 MOID_T *to = (return_depreffed ? depref_completely (candidate) : candidate);
958 BOOL_T all_coercible = A68_TRUE;
959 siga = A68_TRUE;
960 for (PACK_T *q = PACK (m); q != NO_PACK && all_coercible; FORWARD (q)) {
961 MOID_T *from = MOID (q);
962 if (p != q && from != to) {
963 all_coercible &= is_coercible (from, to, sort, deflex);
964 }
965 }
966 // If the pack is coercible to the candidate, we mark the candidate.
967 // We continue searching for longest series of REF REF PROC REF.
968 if (all_coercible) {
969 MOID_T *mark = (return_depreffed ? MOID (p) : candidate);
970 if (common_moid == NO_MOID) {
971 common_moid = mark;
972 } else if (IS_FLEX (candidate) && DEFLEX (candidate) == common_moid) {
973 // We prefer FLEX.
974 common_moid = mark;
975 }
976 }
977 }
978 }
979 } // for
980 } // for
981 }
982 return common_moid == NO_MOID ? m : common_moid;
983 }
984
985 //! @brief Whether we can search a common mode from a clause or not.
986
987 BOOL_T clause_allows_balancing (int att)
988 {
989 switch (att) {
990 case CLOSED_CLAUSE:
991 case CONDITIONAL_CLAUSE:
992 case CASE_CLAUSE:
993 case SERIAL_CLAUSE:
994 case CONFORMITY_CLAUSE: {
995 return A68_TRUE;
996 }
997 }
998 return A68_FALSE;
999 }
1000
1001 //! @brief A unique mode from "z".
1002
1003 MOID_T *determine_unique_mode (SOID_T * z, int deflex)
1004 {
1005 if (z == NO_SOID) {
1006 return NO_MOID;
1007 } else {
1008 MOID_T *x = MOID (z);
1009 if (is_mode_isnt_well (x)) {
1010 return M_ERROR;
1011 }
1012 x = make_united_mode (x);
1013 if (clause_allows_balancing (ATTRIBUTE (z))) {
1014 return get_balanced_mode (x, STRONG, NO_DEPREF, deflex);
1015 } else {
1016 return x;
1017 }
1018 }
1019 }
1020
1021 //! @brief Insert coercion "a" in the tree.
1022
1023 void make_coercion (NODE_T * l, int a, MOID_T * m)
1024 {
1025 make_sub (l, l, a);
1026 MOID (l) = depref_rows (MOID (l), m);
1027 }
1028
1029 //! @brief Make widening coercion.
1030
1031 void make_widening_coercion (NODE_T * n, MOID_T * p, MOID_T * q)
1032 {
1033 MOID_T *z = widens_to (p, q);
1034 make_coercion (n, WIDENING, z);
1035 if (z != q) {
1036 make_widening_coercion (n, z, q);
1037 }
1038 }
1039
1040 //! @brief Make ref rowing coercion.
1041
1042 void make_ref_rowing_coercion (NODE_T * n, MOID_T * p, MOID_T * q)
1043 {
1044 if (DEFLEX (p) != DEFLEX (q)) {
1045 if (is_widenable (p, q)) {
1046 make_widening_coercion (n, p, q);
1047 } else if (is_ref_row (q)) {
1048 make_ref_rowing_coercion (n, p, NAME (q));
1049 make_coercion (n, ROWING, q);
1050 }
1051 }
1052 }
1053
1054 //! @brief Make rowing coercion.
1055
1056 void make_rowing_coercion (NODE_T * n, MOID_T * p, MOID_T * q)
1057 {
1058 if (DEFLEX (p) != DEFLEX (q)) {
1059 if (is_widenable (p, q)) {
1060 make_widening_coercion (n, p, q);
1061 } else if (SLICE (q) != NO_MOID) {
1062 make_rowing_coercion (n, p, SLICE (q));
1063 make_coercion (n, ROWING, q);
1064 } else if (IS_FLEX (q)) {
1065 make_rowing_coercion (n, p, SUB (q));
1066 } else if (is_ref_row (q)) {
1067 make_ref_rowing_coercion (n, p, q);
1068 }
1069 }
1070 }
1071
1072 //! @brief Make uniting coercion.
1073
1074 void make_uniting_coercion (NODE_T * n, MOID_T * q)
1075 {
1076 make_coercion (n, UNITING, derow (q));
1077 if (IS_ROW (q) || IS_FLEX (q)) {
1078 make_rowing_coercion (n, derow (q), q);
1079 }
1080 }
1081
1082 //! @brief Make depreffing coercion.
1083
1084 void make_depreffing_coercion (NODE_T * n, MOID_T * p, MOID_T * q)
1085 {
1086 if (DEFLEX (p) == DEFLEX (q)) {
1087 return;
1088 } else if (q == M_SIMPLOUT && is_printable_mode (p)) {
1089 make_coercion (n, UNITING, q);
1090 } else if (q == M_ROW_SIMPLOUT && is_printable_mode (p)) {
1091 make_coercion (n, UNITING, M_SIMPLOUT);
1092 make_coercion (n, ROWING, M_ROW_SIMPLOUT);
1093 } else if (q == M_SIMPLIN && is_readable_mode (p)) {
1094 make_coercion (n, UNITING, q);
1095 } else if (q == M_ROW_SIMPLIN && is_readable_mode (p)) {
1096 make_coercion (n, UNITING, M_SIMPLIN);
1097 make_coercion (n, ROWING, M_ROW_SIMPLIN);
1098 } else if (q == M_ROWS && is_rows_type (p)) {
1099 make_coercion (n, UNITING, M_ROWS);
1100 MOID (n) = M_ROWS;
1101 } else if (is_widenable (p, q)) {
1102 make_widening_coercion (n, p, q);
1103 } else if (is_unitable (p, derow (q), SAFE_DEFLEXING)) {
1104 make_uniting_coercion (n, q);
1105 } else if (is_ref_row (q) && is_strong_name (p, q)) {
1106 make_ref_rowing_coercion (n, p, q);
1107 } else if (SLICE (q) != NO_MOID && is_strong_slice (p, q)) {
1108 make_rowing_coercion (n, p, q);
1109 } else if (IS_FLEX (q) && is_strong_slice (p, q)) {
1110 make_rowing_coercion (n, p, q);
1111 } else if (IS_REF (p)) {
1112 MOID_T *r = depref_once (p);
1113 make_coercion (n, DEREFERENCING, r);
1114 make_depreffing_coercion (n, r, q);
1115 } else if (IS (p, PROC_SYMBOL) && PACK (p) == NO_PACK) {
1116 MOID_T *r = SUB (p);
1117 make_coercion (n, DEPROCEDURING, r);
1118 make_depreffing_coercion (n, r, q);
1119 } else if (p != q) {
1120 cannot_coerce (n, p, q, NO_SORT, SKIP_DEFLEXING, 0);
1121 }
1122 }
1123
1124 //! @brief Whether p is a nonproc mode (that is voided directly).
1125
1126 BOOL_T is_nonproc (MOID_T * p)
1127 {
1128 if (IS (p, PROC_SYMBOL) && PACK (p) == NO_PACK) {
1129 return A68_FALSE;
1130 } else if (IS_REF (p)) {
1131 return is_nonproc (SUB (p));
1132 } else {
1133 return A68_TRUE;
1134 }
1135 }
1136
1137 //! @brief Make_void: voiden in an appropriate way.
1138
1139 void make_void (NODE_T * p, MOID_T * q)
1140 {
1141 switch (ATTRIBUTE (p)) {
1142 case ASSIGNATION:
1143 case IDENTITY_RELATION:
1144 case GENERATOR:
1145 case CAST:
1146 case DENOTATION: {
1147 make_coercion (p, VOIDING, M_VOID);
1148 return;
1149 }
1150 }
1151 // MORFs are an involved case.
1152 switch (ATTRIBUTE (p)) {
1153 case SELECTION:
1154 case SLICE:
1155 case ROUTINE_TEXT:
1156 case FORMULA:
1157 case CALL:
1158 case IDENTIFIER: {
1159 // A nonproc moid value is eliminated directly.
1160 if (is_nonproc (q)) {
1161 make_coercion (p, VOIDING, M_VOID);
1162 return;
1163 } else {
1164 // Descend the chain of e.g. REF PROC .. until a nonproc moid remains.
1165 MOID_T *z = q;
1166 while (!is_nonproc (z)) {
1167 if (IS_REF (z)) {
1168 make_coercion (p, DEREFERENCING, SUB (z));
1169 }
1170 if (IS (z, PROC_SYMBOL) && NODE_PACK (p) == NO_PACK) {
1171 make_coercion (p, DEPROCEDURING, SUB (z));
1172 }
1173 z = SUB (z);
1174 }
1175 if (z != M_VOID) {
1176 make_coercion (p, VOIDING, M_VOID);
1177 }
1178 return;
1179 }
1180 }
1181 }
1182 // All other is voided straight away.
1183 make_coercion (p, VOIDING, M_VOID);
1184 }
1185
1186 //! @brief Make strong coercion.
1187
1188 void make_strong (NODE_T * n, MOID_T * p, MOID_T * q)
1189 {
1190 if (q == M_VOID && p != M_VOID) {
1191 make_void (n, p);
1192 } else {
1193 make_depreffing_coercion (n, p, q);
1194 }
1195 }
1196
© 2002-2024 J.M. van der Veer (jmvdveer@xs4all.nl)
|