genie-coerce.c
1 //! @file genie-coerce.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 //! Interpreter mode coercion routines.
25
26 #include "a68g.h"
27 #include "a68g-genie.h"
28 #include "a68g-frames.h"
29 #include "a68g-prelude.h"
30 #include "a68g-mp.h"
31 #include "a68g-double.h"
32 #include "a68g-parser.h"
33
34 //! @brief Push result of cast (coercions are deeper in the tree).
35
36 PROP_T genie_cast (NODE_T * p)
37 {
38 GENIE_UNIT (NEXT_SUB (p));
39 PROP_T self;
40 UNIT (&self) = genie_cast;
41 SOURCE (&self) = p;
42 return self;
43 }
44
45 //! @brief Unite value in the stack and push result.
46
47 PROP_T genie_uniting (NODE_T * p)
48 {
49 ADDR_T pop_sp = A68_SP;
50 MOID_T *u = MOID (p), *v = MOID (SUB (p));
51 if (ATTRIBUTE (v) != UNION_SYMBOL) {
52 MOID_T *w = unites_to (v, u);
53 PUSH_UNION (p, (void *) w);
54 GENIE_UNIT (SUB (p));
55 STACK_DNS (p, SUB (v), A68_FP);
56 } else {
57 A68_UNION *m = (A68_UNION *) STACK_TOP;
58 GENIE_UNIT (SUB (p));
59 STACK_DNS (p, SUB (v), A68_FP);
60 VALUE (m) = (void *) unites_to ((MOID_T *) VALUE (m), u);
61 if (!IS (u, ROWS_SYMBOL) && VALUE (m) == NO_MOID) {
62 diagnostic (A68_RUNTIME_ERROR, p, ERROR_EMPTY_VALUE_FROM, v);
63 exit_genie (p, A68_RUNTIME_ERROR);
64 }
65 }
66 A68_SP = pop_sp + SIZE (u);
67 PROP_T self;
68 UNIT (&self) = genie_uniting;
69 SOURCE (&self) = p;
70 return self;
71 }
72
73 //! @brief Store widened constant as a constant.
74
75 void make_constant_widening (NODE_T * p, MOID_T * m, PROP_T * self)
76 {
77 if (SUB (p) != NO_NODE && CONSTANT (GINFO (SUB (p))) != NO_CONSTANT) {
78 int size = SIZE (m);
79 UNIT (self) = genie_constant;
80 CONSTANT (GINFO (p)) = (void *) get_heap_space ((size_t) size);
81 SIZE (GINFO (p)) = size;
82 COPY (CONSTANT (GINFO (p)), (void *) (STACK_OFFSET (-size)), size);
83 }
84 }
85
86 //! @brief (optimised) push INT widened to REAL
87
88 PROP_T genie_widen_int_to_real (NODE_T * p)
89 {
90 A68_INT *i = (A68_INT *) STACK_TOP;
91 A68_REAL *z = (A68_REAL *) STACK_TOP;
92 GENIE_UNIT (SUB (p));
93 INCREMENT_STACK_POINTER (p, SIZE_ALIGNED (A68_REAL) - SIZE (M_INT));
94 VALUE (z) = (REAL_T) VALUE (i);
95 STATUS (z) = INIT_MASK;
96 return GPROP (p);
97 }
98
99 //! @brief Widen value in the stack.
100
101 PROP_T genie_widen (NODE_T * p)
102 {
103 #define COERCE_FROM_TO(p, a, b) (MOID (p) == (b) && MOID (SUB (p)) == (a))
104 PROP_T self;
105 UNIT (&self) = genie_widen;
106 SOURCE (&self) = p;
107 // INT widenings.
108 if (COERCE_FROM_TO (p, M_INT, M_REAL)) {
109 (void) genie_widen_int_to_real (p);
110 UNIT (&self) = genie_widen_int_to_real;
111 make_constant_widening (p, M_REAL, &self);
112 } else if (COERCE_FROM_TO (p, M_INT, M_LONG_INT)) {
113 GENIE_UNIT (SUB (p));
114 #if (A68_LEVEL >= 3)
115 genie_lengthen_int_to_double_int (p);
116 #else
117 genie_lengthen_int_to_mp (p);
118 #endif
119 make_constant_widening (p, M_LONG_INT, &self);
120 } else if (COERCE_FROM_TO (p, M_LONG_INT, M_LONG_LONG_INT)) {
121 GENIE_UNIT (SUB (p));
122 #if (A68_LEVEL >= 3)
123 genie_lengthen_double_int_to_mp (p);
124 #else
125 genie_lengthen_mp_to_long_mp (p);
126 #endif
127 make_constant_widening (p, M_LONG_LONG_INT, &self);
128 } else if (COERCE_FROM_TO (p, M_LONG_INT, M_LONG_REAL)) {
129 #if (A68_LEVEL >= 3)
130 (void) genie_widen_double_int_to_double (p);
131 #else
132 // 1-1 mapping.
133 GENIE_UNIT (SUB (p));
134 #endif
135 make_constant_widening (p, M_LONG_REAL, &self);
136 } else if (COERCE_FROM_TO (p, M_LONG_LONG_INT, M_LONG_LONG_REAL)) {
137 GENIE_UNIT (SUB (p));
138 // 1-1 mapping.
139 make_constant_widening (p, M_LONG_LONG_REAL, &self);
140 }
141 // REAL widenings.
142 else if (COERCE_FROM_TO (p, M_REAL, M_LONG_REAL)) {
143 GENIE_UNIT (SUB (p));
144 #if (A68_LEVEL >= 3)
145 genie_lengthen_real_to_double (p);
146 #else
147 genie_lengthen_real_to_mp (p);
148 #endif
149 make_constant_widening (p, M_LONG_REAL, &self);
150 } else if (COERCE_FROM_TO (p, M_LONG_REAL, M_LONG_LONG_REAL)) {
151 GENIE_UNIT (SUB (p));
152 #if (A68_LEVEL >= 3)
153 genie_lengthen_double_to_mp (p);
154 #else
155 genie_lengthen_mp_to_long_mp (p);
156 #endif
157 make_constant_widening (p, M_LONG_LONG_REAL, &self);
158 } else if (COERCE_FROM_TO (p, M_REAL, M_COMPLEX)) {
159 GENIE_UNIT (SUB (p));
160 PUSH_VALUE (p, 0.0, A68_REAL);
161 make_constant_widening (p, M_COMPLEX, &self);
162 } else if (COERCE_FROM_TO (p, M_LONG_REAL, M_LONG_COMPLEX)) {
163 #if (A68_LEVEL >= 3)
164 DOUBLE_NUM_T z;
165 z.f = 0.0q;
166 GENIE_UNIT (SUB (p));
167 PUSH_VALUE (p, z, A68_LONG_REAL);
168 #else
169 GENIE_UNIT (SUB (p));
170 (void) nil_mp (p, DIGITS (M_LONG_REAL));
171 make_constant_widening (p, M_LONG_COMPLEX, &self);
172 #endif
173 } else if (COERCE_FROM_TO (p, M_LONG_LONG_REAL, M_LONG_LONG_COMPLEX)) {
174 GENIE_UNIT (SUB (p));
175 (void) nil_mp (p, DIGITS (M_LONG_LONG_REAL));
176 make_constant_widening (p, M_LONG_LONG_COMPLEX, &self);
177 } else if (COERCE_FROM_TO (p, M_COMPLEX, M_LONG_COMPLEX)) {
178 // COMPLEX widenings.
179 GENIE_UNIT (SUB (p));
180 #if (A68_LEVEL >= 3)
181 genie_lengthen_complex_to_double_compl (p);
182 #else
183 genie_lengthen_complex_to_mp_complex (p);
184 #endif
185 make_constant_widening (p, M_LONG_COMPLEX, &self);
186 } else if (COERCE_FROM_TO (p, M_LONG_COMPLEX, M_LONG_LONG_COMPLEX)) {
187 GENIE_UNIT (SUB (p));
188 #if (A68_LEVEL >= 3)
189 genie_lengthen_double_compl_to_long_mp_complex (p);
190 #else
191 genie_lengthen_mp_complex_to_long_mp_complex (p);
192 #endif
193 make_constant_widening (p, M_LONG_LONG_COMPLEX, &self);
194 } else if (COERCE_FROM_TO (p, M_BITS, M_LONG_BITS)) {
195 // BITS widenings.
196 GENIE_UNIT (SUB (p));
197 #if (A68_LEVEL >= 3)
198 genie_lengthen_bits_to_double_bits (p);
199 #else
200 genie_lengthen_int_to_mp (p);
201 #endif
202 make_constant_widening (p, M_LONG_BITS, &self);
203 } else if (COERCE_FROM_TO (p, M_LONG_BITS, M_LONG_LONG_BITS)) {
204 #if (A68_LEVEL >= 3)
205 ABEND (A68_TRUE, ERROR_INTERNAL_CONSISTENCY, __func__);
206 #else
207 GENIE_UNIT (SUB (p));
208 genie_lengthen_mp_to_long_mp (p);
209 make_constant_widening (p, M_LONG_LONG_BITS, &self);
210 #endif
211 } else if (COERCE_FROM_TO (p, M_BITS, M_ROW_BOOL) || COERCE_FROM_TO (p, M_BITS, M_FLEX_ROW_BOOL)) {
212 GENIE_UNIT (SUB (p));
213 A68_BITS x;
214 POP_OBJECT (p, &x, A68_BITS);
215 A68_REF z, row; A68_ARRAY arr; A68_TUPLE tup;
216 NEW_ROW_1D (z, row, arr, tup, M_ROW_BOOL, M_BOOL, A68_BITS_WIDTH);
217 BYTE_T *base = ADDRESS (&row) + SIZE (M_BOOL) * (A68_BITS_WIDTH - 1);
218 UNSIGNED_T bit = 1;
219 for (int k = A68_BITS_WIDTH - 1; k >= 0; k--, base -= SIZE (M_BOOL), bit <<= 1) {
220 STATUS ((A68_BOOL *) base) = INIT_MASK;
221 VALUE ((A68_BOOL *) base) = (BOOL_T) ((VALUE (&x) & bit) != 0 ? A68_TRUE : A68_FALSE);
222 }
223 PUSH_REF (p, z);
224 } else if (COERCE_FROM_TO (p, M_LONG_BITS, M_ROW_BOOL) || COERCE_FROM_TO (p, M_LONG_BITS, M_FLEX_ROW_BOOL)) {
225 #if (A68_LEVEL >= 3)
226 GENIE_UNIT (SUB (p));
227 A68_LONG_BITS x;
228 POP_OBJECT (p, &x, A68_LONG_BITS);
229 A68_REF z, row; A68_ARRAY arr; A68_TUPLE tup;
230 NEW_ROW_1D (z, row, arr, tup, M_ROW_BOOL, M_BOOL, A68_LONG_BITS_WIDTH);
231 BYTE_T *base = ADDRESS (&row) + SIZE (M_BOOL) * (A68_LONG_BITS_WIDTH - 1);
232 UNSIGNED_T bit = 1;
233 for (int k = A68_BITS_WIDTH - 1; k >= 0; k--, base -= SIZE (M_BOOL), bit <<= 1) {
234 STATUS ((A68_BOOL *) base) = INIT_MASK;
235 VALUE ((A68_BOOL *) base) = (BOOL_T) ((LW (VALUE (&x)) & bit) != 0 ? A68_TRUE : A68_FALSE);
236 }
237 bit = 1;
238 for (int k = A68_BITS_WIDTH - 1; k >= 0; k--, base -= SIZE (M_BOOL), bit <<= 1) {
239 STATUS ((A68_BOOL *) base) = INIT_MASK;
240 VALUE ((A68_BOOL *) base) = (BOOL_T) ((HW (VALUE (&x)) & bit) != 0 ? A68_TRUE : A68_FALSE);
241 }
242 PUSH_REF (p, z);
243 #else
244 GENIE_UNIT (SUB (p));
245 genie_lengthen_long_bits_to_row_bool (p);
246 #endif
247 } else if (COERCE_FROM_TO (p, M_LONG_LONG_BITS, M_ROW_BOOL) || COERCE_FROM_TO (p, M_LONG_LONG_BITS, M_FLEX_ROW_BOOL)) {
248 #if (A68_LEVEL <= 2)
249 GENIE_UNIT (SUB (p));
250 genie_lengthen_long_bits_to_row_bool (p);
251 #endif
252 } else if (COERCE_FROM_TO (p, M_BYTES, M_ROW_CHAR) || COERCE_FROM_TO (p, M_BYTES, M_FLEX_ROW_CHAR)) {
253 GENIE_UNIT (SUB (p));
254 A68_BYTES z;
255 POP_OBJECT (p, &z, A68_BYTES);
256 PUSH_REF (p, c_string_to_row_char (p, VALUE (&z), A68_BYTES_WIDTH));
257 } else if (COERCE_FROM_TO (p, M_LONG_BYTES, M_ROW_CHAR) || COERCE_FROM_TO (p, M_LONG_BYTES, M_FLEX_ROW_CHAR)) {
258 GENIE_UNIT (SUB (p));
259 A68_LONG_BYTES z;
260 POP_OBJECT (p, &z, A68_LONG_BYTES);
261 PUSH_REF (p, c_string_to_row_char (p, VALUE (&z), A68_LONG_BYTES_WIDTH));
262 } else {
263 diagnostic (A68_RUNTIME_ERROR, p, ERROR_CANNOT_WIDEN, MOID (SUB (p)), MOID (p));
264 exit_genie (p, A68_RUNTIME_ERROR);
265 }
266 return self;
267 #undef COERCE_FROM_TO
268 }
269
270 //! @brief Cast a jump to a PROC VOID without executing the jump.
271
272 void genie_proceduring (NODE_T * p)
273 {
274 NODE_T *jump = SUB (p);
275 NODE_T *q = SUB (jump);
276 NODE_T *label = (IS (q, GOTO_SYMBOL) ? NEXT (q) : q);
277 A68_PROCEDURE z;
278 STATUS (&z) = INIT_MASK;
279 NODE (&(BODY (&z))) = jump;
280 STATIC_LINK_FOR_FRAME (ENVIRON (&z), 1 + TAG_LEX_LEVEL (TAX (label)));
281 LOCALE (&z) = NO_HANDLE;
282 MOID (&z) = M_PROC_VOID;
283 PUSH_PROCEDURE (p, z);
284 }
285
286 //! @brief (optimised) dereference value of a unit
287
288 PROP_T genie_dereferencing_quick (NODE_T * p)
289 {
290 BYTE_T *tos = STACK_TOP;
291 A68_REF *z = (A68_REF *) tos;
292 ADDR_T pop_sp = A68_SP;
293 GENIE_UNIT (SUB (p));
294 A68_SP = pop_sp;
295 CHECK_REF (p, *z, MOID (SUB (p)));
296 PUSH (p, ADDRESS (z), SIZE (MOID (p)));
297 genie_check_initialisation (p, tos, MOID (p));
298 return GPROP (p);
299 }
300
301 //! @brief Dereference an identifier.
302
303 PROP_T genie_dereference_frame_identifier (NODE_T * p)
304 {
305 MOID_T *deref = SUB_MOID (p);
306 BYTE_T *tos = STACK_TOP;
307 A68_REF *z;
308 FRAME_GET (z, A68_REF, p);
309 PUSH (p, ADDRESS (z), SIZE (deref));
310 genie_check_initialisation (p, tos, deref);
311 return GPROP (p);
312 }
313
314 //! @brief Dereference an identifier.
315
316 PROP_T genie_dereference_generic_identifier (NODE_T * p)
317 {
318 MOID_T *deref = SUB_MOID (p);
319 BYTE_T *tos = STACK_TOP;
320 A68_REF *z;
321 FRAME_GET (z, A68_REF, p);
322 CHECK_REF (p, *z, MOID (SUB (p)));
323 PUSH (p, ADDRESS (z), SIZE (deref));
324 genie_check_initialisation (p, tos, deref);
325 return GPROP (p);
326 }
327
328 //! @brief Slice REF [] A to A.
329
330 PROP_T genie_dereference_slice_name_quick (NODE_T * p)
331 {
332 MOID_T *ref_m = MOID (p); MOID_T *deref_m = SUB (ref_m);
333 ADDR_T pop_sp = A68_SP;
334 // Get REF [] and [].
335 BYTE_T *tos = STACK_TOP;
336 A68_REF *z = (A68_REF *) tos;
337 GENIE_UNIT (SUB (p));
338 CHECK_REF (p, *z, ref_m);
339 A68_ARRAY *arr; A68_TUPLE *tup;
340 GET_DESCRIPTOR (arr, tup, DEREF (A68_ROW, z));
341 // Compute index.
342 A68_SP = pop_sp;
343 int index = 0;
344 for (NODE_T *q = SEQUENCE (p); q != NO_NODE; q = SEQUENCE (q)) {
345 A68_INT *j = (A68_INT *) STACK_TOP;
346 GENIE_UNIT (q);
347 int k = VALUE (j);
348 if (k < LWB (tup) || k > UPB (tup)) {
349 diagnostic (A68_RUNTIME_ERROR, q, ERROR_INDEX_OUT_OF_BOUNDS);
350 exit_genie (q, A68_RUNTIME_ERROR);
351 }
352 index += (SPAN (tup) * k - SHIFT (tup));
353 tup++;
354 A68_SP = pop_sp;
355 }
356 // Push element.
357 PUSH (p, &((ADDRESS (&(ARRAY (arr))))[ROW_ELEMENT (arr, index)]), SIZE (deref_m));
358 genie_check_initialisation (p, tos, deref_m);
359 return GPROP (p);
360 }
361
362 //! @brief Dereference SELECTION from a name.
363
364 PROP_T genie_dereference_selection_name_quick (NODE_T * p)
365 {
366 NODE_T *selector = SUB (p);
367 MOID_T *struct_m = MOID (NEXT (selector));
368 MOID_T *result_m = SUB_MOID (selector);
369 BYTE_T *tos = STACK_TOP;
370 A68_REF *z = (A68_REF *) tos;
371 ADDR_T pop_sp = A68_SP;
372 GENIE_UNIT (NEXT (selector));
373 CHECK_REF (selector, *z, struct_m);
374 OFFSET (z) += OFFSET (NODE_PACK (SUB (selector)));
375 A68_SP = pop_sp;
376 PUSH (p, ADDRESS (z), SIZE (result_m));
377 genie_check_initialisation (p, tos, result_m);
378 return GPROP (p);
379 }
380
381 //! @brief Dereference name in the stack.
382
383 PROP_T genie_dereferencing (NODE_T * p)
384 {
385 PROP_T self;
386 GENIE_UNIT_2 (SUB (p), self);
387 A68_REF z;
388 POP_REF (p, &z);
389 CHECK_REF (p, z, MOID (SUB (p)));
390 PUSH (p, ADDRESS (&z), SIZE (MOID (p)));
391 genie_check_initialisation (p, STACK_OFFSET (-SIZE (MOID (p))), MOID (p));
392 if (UNIT (&self) == genie_frame_identifier) {
393 if (IS_IN_FRAME (&z)) {
394 UNIT (&self) = genie_dereference_frame_identifier;
395 } else {
396 UNIT (&self) = genie_dereference_generic_identifier;
397 }
398 UNIT (&PROP (GINFO (SOURCE (&self)))) = UNIT (&self);
399 } else if (UNIT (&self) == genie_slice_name_quick) {
400 UNIT (&self) = genie_dereference_slice_name_quick;
401 UNIT (&PROP (GINFO (SOURCE (&self)))) = UNIT (&self);
402 } else if (UNIT (&self) == genie_selection_name_quick) {
403 UNIT (&self) = genie_dereference_selection_name_quick;
404 UNIT (&PROP (GINFO (SOURCE (&self)))) = UNIT (&self);
405 } else {
406 UNIT (&self) = genie_dereferencing_quick;
407 SOURCE (&self) = p;
408 }
409 return self;
410 }
411
412 //! @brief Deprocedure PROC in the stack.
413
414 PROP_T genie_deproceduring (NODE_T * p)
415 {
416 NODE_T *proc = SUB (p);
417 MOID_T *proc_m = MOID (proc);
418 PROP_T self;
419 UNIT (&self) = genie_deproceduring;
420 SOURCE (&self) = p;
421 // Get procedure.
422 ADDR_T pop_sp = A68_SP, pop_fp = A68_FP;
423 A68_PROCEDURE *z = (A68_PROCEDURE *) STACK_TOP;
424 GENIE_UNIT (proc);
425 A68_SP = pop_sp;
426 genie_check_initialisation (p, (BYTE_T *) z, proc_m);
427 genie_call_procedure (p, proc_m, proc_m, M_VOID, z, pop_sp, pop_fp);
428 STACK_DNS (p, MOID (p), A68_FP);
429 return self;
430 }
431
432 //! @brief Voiden value in the stack.
433
434 PROP_T genie_voiding (NODE_T * p)
435 {
436 PROP_T self, source;
437 ADDR_T sp_for_voiding = A68_SP;
438 SOURCE (&self) = p;
439 GENIE_UNIT_2 (SUB (p), source);
440 A68_SP = sp_for_voiding;
441 if (UNIT (&source) == genie_assignation_quick) {
442 UNIT (&self) = genie_voiding_assignation;
443 SOURCE (&self) = SOURCE (&source);
444 } else if (UNIT (&source) == genie_assignation_constant) {
445 UNIT (&self) = genie_voiding_assignation_constant;
446 SOURCE (&self) = SOURCE (&source);
447 } else {
448 UNIT (&self) = genie_voiding;
449 }
450 return self;
451 }
452
453 //! @brief Coerce value in the stack.
454
455 PROP_T genie_coercion (NODE_T * p)
456 {
457 PROP_T self;
458 UNIT (&self) = genie_coercion;
459 SOURCE (&self) = p;
460 switch (ATTRIBUTE (p)) {
461 case VOIDING: {
462 self = genie_voiding (p);
463 break;
464 }
465 case UNITING: {
466 self = genie_uniting (p);
467 break;
468 }
469 case WIDENING: {
470 self = genie_widen (p);
471 break;
472 }
473 case ROWING: {
474 self = genie_rowing (p);
475 break;
476 }
477 case DEREFERENCING: {
478 self = genie_dereferencing (p);
479 break;
480 }
481 case DEPROCEDURING: {
482 self = genie_deproceduring (p);
483 break;
484 }
485 case PROCEDURING: {
486 genie_proceduring (p);
487 break;
488 }
489 }
490 GPROP (p) = self;
491 return self;
492 }
© 2002-2024 J.M. van der Veer (jmvdveer@xs4all.nl)
|