1#include "include/pw.h"
2#include "src/pw_alloc.h"
3#include "src/pw_interfaces_internal.h"
4#include "src/types/array/array_internal.h"
5#include "src/types/compound_internal.h"
6#include "src/types/map/map_internal.h"
7#include "src/types/status_internal.h"
8#include "src/types/string/string_internal.h"
9#include "src/types/struct_internal.h"
10
11#include <libpussy/alignment.h>
12#include <libpussy/mmarray.h>
13
14
15PwType** _pw_types = nullptr;
16static unsigned num_pw_types = 0;
17
18/****************************************************************
19 * Null type
20 */
21
22static bool null_create(PwMethod_Basic_create* mthis, PwValuePtr result, PwCtorArgs* ctor_args)
23{
24 *result = PwNull();
25 return true;
26}
27
28static bool null_hash(PwMethod_Basic_hash* mthis, PwValuePtr self, PwHashContext* ctx, _PwCompoundChain* tail)
29{
30 _pw_hash_uint64(ctx, PwTypeId_Null);
31 return true;
32}
33
34static bool null_dump(PwMethod_Basic_dump* mthis, PwValuePtr self, FILE* fp, int indent, _PwCompoundChain* tail)
35{
36 _pw_print_indent(fp, indent);
37 _pw_print_type(fp, self);
38 fputc('\n', fp);
39 return true;
40}
41
42static bool null_equal(PwMethod_Basic_equal* mthis, PwValuePtr self, PwValuePtr other, _PwCompoundChain* tail)
43{
44 uint16_t t = other->type_id;
45 if (_pw_likely(t == PwTypeId_Null)) {
46 return true;
47 }
48 if (_pw_likely(t == PwTypeId_Ptr)) {
49 return other->ptr == nullptr;
50 }
51 PwType* type = _pw_types[t];
52 PwType** base_type = type->base_types;
53 if (base_type) {
54 PwType** base_types_end = base_type + type->num_base_types;
55 while (base_type < base_types_end) {
56 t = (*base_type)->id;
57 if (t == PwTypeId_Null) {
58 return true;
59 }
60 if (t == PwTypeId_Ptr) {
61 return other->ptr == nullptr;
62 }
63 base_type++;
64 }
65 }
66 return false;
67}
68
69static bool null_to_string(PwMethod_Basic_to_string* mthis, PwValuePtr self, PwValuePtr result, _PwCompoundChain* tail)
70{
71 pw_destroy(result);
72 *result = PwString("null");
73 return true;
74}
75
76static bool null_is_true(PwMethod_Basic_is_true* mthis, PwValuePtr self, _PwCompoundChain* tail)
77{
78 return false;
79}
80
81#define null_destroy nullptr
82#define null_clone nullptr
83#define null_decref nullptr
84#define null_deepcopy nullptr
85#define null_iter_children nullptr
86
87static PwInterface_Basic null_basic_interface = {
88#define X(name, ...) .name = { .func = null_##name } __VA_OPT__(,)
89 PW_BASIC_INTERFACE_METHODS
90#undef X
91};
92
93/****************************************************************
94 * Bool type
95 */
96
97static bool bool_create(PwMethod_Basic_create* mthis, PwValuePtr result, PwCtorArgs* ctor_args)
98{
99 // XXX use ctor_args for initializer?
100 *result = PwBool(false);
101 return true;
102}
103
104static bool bool_hash(PwMethod_Basic_hash* mthis, PwValuePtr self, PwHashContext* ctx, _PwCompoundChain* tail)
105{
106 // mind maps: the hash should be the same for subtypes, that's why not using self->type_id here
107 _pw_hash_uint64(ctx, PwTypeId_Bool);
108 _pw_hash_uint64(ctx, self->bool_value);
109 return true;
110}
111
112static bool bool_dump(PwMethod_Basic_dump* mthis, PwValuePtr self, FILE* fp, int indent, _PwCompoundChain* tail)
113{
114 _pw_print_indent(fp, indent);
115 _pw_print_type(fp, self);
116 fprintf(fp, ": %s\n", self->bool_value? "true" : "false");
117 return true;
118}
119
120static bool bool_equal(PwMethod_Basic_equal* mthis, PwValuePtr self, PwValuePtr other, _PwCompoundChain* tail)
121{
122 bool v = self->bool_value;
123 uint16_t t = other->type_id;
124 if (_pw_likely(t == PwTypeId_Bool)) {
125 return v == other->bool_value;
126 }
127 PwType* type = _pw_types[t];
128 PwType** base_type = type->base_types;
129 if (base_type) {
130 PwType** base_types_end = base_type + type->num_base_types;
131 while (base_type < base_types_end) {
132 t = (*base_type)->id;
133 if (t == PwTypeId_Bool) {
134 return v == other->bool_value;
135 }
136 base_type++;
137 }
138 }
139 return false;
140}
141
142static bool bool_to_string(PwMethod_Basic_to_string* mthis, PwValuePtr self, PwValuePtr result, _PwCompoundChain* tail)
143{
144 pw_destroy(result);
145 if (self->bool_value) {
146 *result = PwString("true");
147 } else {
148 *result = PwString("false");
149 }
150 return true;
151}
152
153static bool bool_is_true(PwMethod_Basic_is_true* mthis, PwValuePtr self, _PwCompoundChain* tail)
154{
155 return self->bool_value;
156}
157
158#define bool_destroy nullptr
159#define bool_clone nullptr
160#define bool_decref nullptr
161#define bool_deepcopy nullptr
162#define bool_iter_children nullptr
163
164static PwInterface_Basic bool_basic_interface = {
165#define X(name, ...) .name = { .func = bool_##name } __VA_OPT__(,)
166 PW_BASIC_INTERFACE_METHODS
167#undef X
168};
169
170/****************************************************************
171 * Abstract Integer type
172 */
173
174static bool int_create(PwMethod_Basic_create* mthis, PwValuePtr result, PwCtorArgs* ctor_args)
175{
176 pw_set_status(PwStatus(PW_ERROR_NOT_IMPLEMENTED));
177 return false;
178}
179
180static bool int_hash(PwMethod_Basic_hash* mthis, PwValuePtr self, PwHashContext* ctx, _PwCompoundChain* tail)
181{
182 _pw_hash_uint64(ctx, PwTypeId_Int);
183 return true;
184}
185
186static bool int_dump(PwMethod_Basic_dump* mthis, PwValuePtr self, FILE* fp, int indent, _PwCompoundChain* tail)
187{
188 _pw_print_indent(fp, indent);
189 _pw_print_type(fp, self);
190 fputs(": abstract\n", fp);
191 return true;
192}
193
194static bool int_equal(PwMethod_Basic_equal* mthis, PwValuePtr self, PwValuePtr other, _PwCompoundChain* tail)
195{
196 return false;
197}
198
199static bool int_to_string(PwMethod_Basic_to_string* mthis, PwValuePtr self, PwValuePtr result, _PwCompoundChain* tail)
200{
201 pw_set_status(PwStatus(PW_ERROR_NOT_IMPLEMENTED));
202 return false;
203}
204
205static bool int_is_true(PwMethod_Basic_is_true* mthis, PwValuePtr self, _PwCompoundChain* tail)
206{
207 return self->signed_value;
208}
209
210#define int_destroy nullptr
211#define int_clone nullptr
212#define int_decref nullptr
213#define int_deepcopy nullptr
214#define int_iter_children nullptr
215
216static PwInterface_Basic int_basic_interface = {
217#define X(name, ...) .name = { .func = int_##name } __VA_OPT__(,)
218 PW_BASIC_INTERFACE_METHODS
219#undef X
220};
221
222/****************************************************************
223 * Signed type
224 */
225
226static bool signed_create(PwMethod_Basic_create* mthis, PwValuePtr result, PwCtorArgs* ctor_args)
227{
228 // XXX use ctor_args for initializer?
229 *result = PwSigned(0);
230 return true;
231}
232
233static bool signed_hash(PwMethod_Basic_hash* mthis, PwValuePtr self, PwHashContext* ctx, _PwCompoundChain* tail)
234{
235 // mind maps: same signed and unsigned integers must have same hash, so
236 if (self->signed_value < 0) {
237 _pw_hash_uint64(ctx, PwTypeId_Signed);
238 } else {
239 _pw_hash_uint64(ctx, PwTypeId_Unsigned);
240 }
241 _pw_hash_uint64(ctx, self->signed_value);
242 return true;
243}
244
245static bool signed_dump(PwMethod_Basic_dump* mthis, PwValuePtr self, FILE* fp, int indent, _PwCompoundChain* tail)
246{
247 _pw_print_indent(fp, indent);
248 _pw_print_type(fp, self);
249 fprintf(fp, ": %lld\n", (long long) self->signed_value);
250 return true;
251}
252
253static bool signed_to_string(PwMethod_Basic_to_string* mthis, PwValuePtr self, PwValuePtr result, _PwCompoundChain* tail)
254{
255 pw_destroy(result);
256 pw_set_status(PwStatus(PW_ERROR_NOT_IMPLEMENTED));
257 return false;
258}
259
260static bool signed_is_true(PwMethod_Basic_is_true* mthis, PwValuePtr self, _PwCompoundChain* tail)
261{
262 return self->signed_value;
263}
264
265static inline bool compare_signed_unsigned(PwType_Signed self, PwType_Unsigned other)
266{
267 if (self < 0) {
268 return false;
269 } else {
270 return self == (PwType_Signed) other;
271 }
272}
273
274static bool signed_equal(PwMethod_Basic_equal* mthis, PwValuePtr self, PwValuePtr other, _PwCompoundChain* tail)
275{
276 PwType_Signed v = self->signed_value;
277 uint16_t t = other->type_id;
278 if (_pw_likely(t == PwTypeId_Signed)) {
279 return v == other->signed_value;
280 }
281 if (_pw_likely(t == PwTypeId_Unsigned)) {
282 return compare_signed_unsigned(v, other->unsigned_value);
283 }
284 if (_pw_likely(t == PwTypeId_Float)) {
285 return v == other->float_value;
286 }
287 PwType* type = _pw_types[t];
288 PwType** base_type = type->base_types;
289 if (base_type) {
290 PwType** base_types_end = base_type + type->num_base_types;
291 while (base_type < base_types_end) {
292 t = (*base_type)->id;
293 if (t == PwTypeId_Signed) {
294 return v == other->signed_value;
295 }
296 if (t == PwTypeId_Unsigned) {
297 return compare_signed_unsigned(v, other->unsigned_value);
298 }
299 if (t == PwTypeId_Float) {
300 return v == other->float_value;
301 }
302 base_type++;
303 }
304 }
305 return false;
306}
307
308#define signed_destroy nullptr
309#define signed_clone nullptr
310#define signed_decref nullptr
311#define signed_deepcopy nullptr
312#define signed_iter_children nullptr
313
314static PwInterface_Basic signed_basic_interface = {
315#define X(name, ...) .name = { .func = signed_##name } __VA_OPT__(,)
316 PW_BASIC_INTERFACE_METHODS
317#undef X
318};
319
320/****************************************************************
321 * Unsigned type
322 */
323
324static bool unsigned_create(PwMethod_Basic_create* mthis, PwValuePtr result, PwCtorArgs* ctor_args)
325{
326 // XXX use ctor_args for initializer?
327 *result = PwUnsigned(0);
328 return true;
329}
330
331static bool unsigned_hash(PwMethod_Basic_hash* mthis, PwValuePtr self, PwHashContext* ctx, _PwCompoundChain* tail)
332{
333 // mind maps: same signed and unsigned integers must have same hash,
334 // so using PwTypeId_Unsigned, not self->type_id
335 _pw_hash_uint64(ctx, PwTypeId_Unsigned);
336 _pw_hash_uint64(ctx, self->unsigned_value);
337 return true;
338}
339
340static bool unsigned_dump(PwMethod_Basic_dump* mthis, PwValuePtr self, FILE* fp, int indent, _PwCompoundChain* tail)
341{
342 _pw_print_indent(fp, indent);
343 _pw_print_type(fp, self);
344 fprintf(fp, ": %llu\n", (unsigned long long) self->unsigned_value);
345 return true;
346}
347
348static inline bool compare_unsigned_signed(PwType_Unsigned self, PwType_Signed other)
349{
350 if (other < 0) {
351 return false;
352 } else {
353 return ((PwType_Signed) self) == other;
354 }
355}
356
357static bool unsigned_equal(PwMethod_Basic_equal* mthis, PwValuePtr self, PwValuePtr other, _PwCompoundChain* tail)
358{
359 PwType_Unsigned v = self->signed_value;
360 uint16_t t = other->type_id;
361 if (_pw_likely(t == PwTypeId_Signed)) {
362 return compare_unsigned_signed(v, other->signed_value);
363 }
364 if (_pw_likely(t == PwTypeId_Unsigned)) {
365 return v == other->unsigned_value;
366 }
367 if (_pw_likely(t == PwTypeId_Float)) {
368 return v == other->float_value;
369 }
370 PwType* type = _pw_types[t];
371 PwType** base_type = type->base_types;
372 if (base_type) {
373 PwType** base_types_end = base_type + type->num_base_types;
374 while (base_type < base_types_end) {
375 t = (*base_type)->id;
376 if (t == PwTypeId_Signed) {
377 return compare_unsigned_signed(v, other->signed_value);
378 }
379 if (t == PwTypeId_Unsigned) {
380 return v == other->unsigned_value;
381 }
382 if (t == PwTypeId_Float) {
383 return v == other->float_value;
384 }
385 base_type++;
386 }
387 }
388 return false;
389}
390
391static bool unsigned_to_string(PwMethod_Basic_to_string* mthis, PwValuePtr self, PwValuePtr result, _PwCompoundChain* tail)
392{
393 pw_destroy(result);
394 pw_set_status(PwStatus(PW_ERROR_NOT_IMPLEMENTED));
395 return false;
396}
397
398static bool unsigned_is_true(PwMethod_Basic_is_true* mthis, PwValuePtr self, _PwCompoundChain* tail)
399{
400 return self->unsigned_value;
401}
402
403#define unsigned_destroy nullptr
404#define unsigned_clone nullptr
405#define unsigned_decref nullptr
406#define unsigned_deepcopy nullptr
407#define unsigned_iter_children nullptr
408
409static PwInterface_Basic unsigned_basic_interface = {
410#define X(name, ...) .name = { .func = unsigned_##name } __VA_OPT__(,)
411 PW_BASIC_INTERFACE_METHODS
412#undef X
413};
414
415/****************************************************************
416 * Float type
417 */
418
419static bool float_create(PwMethod_Basic_create* mthis, PwValuePtr result, PwCtorArgs* ctor_args)
420{
421 // XXX use ctor_args for initializer?
422 *result = PwFloat(0.0);
423 return true;
424}
425
426static bool float_hash(PwMethod_Basic_hash* mthis, PwValuePtr self, PwHashContext* ctx, _PwCompoundChain* tail)
427{
428 // mind maps: the hash should be the same for subtypes, that's why not using self->type_id here
429 _pw_hash_uint64(ctx, PwTypeId_Float);
430 _pw_hash_buffer(ctx, &self->float_value, sizeof(self->float_value));
431 return true;
432}
433
434static bool float_dump(PwMethod_Basic_dump* mthis, PwValuePtr self, FILE* fp, int indent, _PwCompoundChain* tail)
435{
436 _pw_print_indent(fp, indent);
437 _pw_print_type(fp, self);
438 fprintf(fp, ": %f\n", self->float_value);
439 return true;
440}
441
442static bool float_equal(PwMethod_Basic_equal* mthis, PwValuePtr self, PwValuePtr other, _PwCompoundChain* tail)
443{
444 PwType_Float v = self->float_value;
445 uint16_t t = other->type_id;
446 if (_pw_likely(t == PwTypeId_Signed)) {
447 return v == (PwType_Float) other->signed_value;
448 }
449 if (_pw_likely(t == PwTypeId_Unsigned)) {
450 return v == (PwType_Float) other->unsigned_value;
451 }
452 if (_pw_likely(t == PwTypeId_Float)) {
453 return v == other->float_value;
454 }
455 PwType* type = _pw_types[t];
456 PwType** base_type = type->base_types;
457 if (base_type) {
458 PwType** base_types_end = base_type + type->num_base_types;
459 while (base_type < base_types_end) {
460 t = (*base_type)->id;
461 if (t == PwTypeId_Signed) {
462 return v == (PwType_Float) other->signed_value;
463 }
464 if (t == PwTypeId_Unsigned) {
465 return v == (PwType_Float) other->unsigned_value;
466 }
467 if (t == PwTypeId_Float) {
468 return v == other->float_value;
469 }
470 base_type++;
471 }
472 }
473 return false;
474}
475
476static bool float_to_string(PwMethod_Basic_to_string* mthis, PwValuePtr self, PwValuePtr result, _PwCompoundChain* tail)
477{
478 pw_destroy(result);
479 pw_set_status(PwStatus(PW_ERROR_NOT_IMPLEMENTED));
480 return false;
481}
482
483static bool float_is_true(PwMethod_Basic_is_true* mthis, PwValuePtr self, _PwCompoundChain* tail)
484{
485 return self->float_value;
486}
487
488#define float_destroy nullptr
489#define float_clone nullptr
490#define float_decref nullptr
491#define float_deepcopy nullptr
492#define float_iter_children nullptr
493
494static PwInterface_Basic float_basic_interface = {
495#define X(name, ...) .name = { .func = float_##name } __VA_OPT__(,)
496 PW_BASIC_INTERFACE_METHODS
497#undef X
498};
499
500/****************************************************************
501 * DateTime type
502 */
503
504static bool datetime_create(PwMethod_Basic_create* mthis, PwValuePtr result, PwCtorArgs* ctor_args)
505{
506 // XXX use ctor_args for initializer?
507 *result = PwDateTime(0, 0, 0, 0, 0, 0);
508 return true;
509}
510
511static bool datetime_hash(PwMethod_Basic_hash* mthis, PwValuePtr self, PwHashContext* ctx, _PwCompoundChain* tail)
512{
513 // mind maps: the hash should be the same for subtypes, that's why not using self->type_id here
514 _pw_hash_uint64(ctx, PwTypeId_DateTime);
515 _pw_hash_uint64(ctx, self->year);
516 _pw_hash_uint64(ctx, self->month);
517 _pw_hash_uint64(ctx, self->day);
518 _pw_hash_uint64(ctx, self->hour);
519 _pw_hash_uint64(ctx, self->minute);
520 _pw_hash_uint64(ctx, self->second);
521 _pw_hash_uint64(ctx, self->nanosecond);
522 _pw_hash_uint64(ctx, self->gmt_offset + (1L << 8 * sizeof(self->gmt_offset))); // make positive (biased)
523 return true;
524}
525
526static bool datetime_dump(PwMethod_Basic_dump* mthis, PwValuePtr self, FILE* fp, int indent, _PwCompoundChain* tail)
527{
528 _pw_print_indent(fp, indent);
529 _pw_print_type(fp, self);
530 fprintf(fp, ": %04u-%02u-%02u %02u:%02u:%02u",
531 self->year, self->month, self->day,
532 self->hour, self->minute, self->second);
533
534 if (self->nanosecond) {
535 // format fractional part and print &frac[1] later
536 char frac[12];
537 snprintf(frac, sizeof(frac), "%u", self->nanosecond + 1000'000'000);
538 fputs(&frac[1], fp);
539 }
540 if (self->gmt_offset) {
541 // gmt_offset can be negative
542 int offset_hours = self->gmt_offset / 60;
543 int offset_minutes = self->gmt_offset % 60;
544 // make sure minutes are positive
545 if (offset_minutes < 0) {
546 offset_minutes = -offset_minutes;
547 }
548 fprintf(fp, "%c%02d:%02d", (offset_hours< 0)? '-' : '+', offset_hours, offset_minutes);
549 }
550 fputc('\n', fp);
551 return true;
552}
553
554static bool datetime_to_string(PwMethod_Basic_to_string* mthis, PwValuePtr self, PwValuePtr result, _PwCompoundChain* tail)
555{
556 pw_destroy(result);
557 pw_set_status(PwStatus(PW_ERROR_NOT_IMPLEMENTED));
558 return false;
559}
560
561static bool datetime_is_true(PwMethod_Basic_is_true* mthis, PwValuePtr self, _PwCompoundChain* tail)
562{
563 return self->year && self->month && self->day
564 && self->hour && self->minute && self->second && self->nanosecond;
565}
566
567static bool datetime_eq(PwValuePtr self, PwValuePtr other)
568{
569 return self->year == other->year &&
570 self->month == other->month &&
571 self->day == other->day &&
572 self->hour == other->hour &&
573 self->minute == other->minute &&
574 self->second == other->second &&
575 self->nanosecond == other->nanosecond &&
576 self->gmt_offset == other->gmt_offset;
577}
578
579static bool datetime_equal(PwMethod_Basic_equal* mthis, PwValuePtr self, PwValuePtr other, _PwCompoundChain* tail)
580{
581 PW_EQUAL_METHOD_IMPL(PwTypeId_DateTime, datetime_eq, self, other);
582 return false;
583}
584
585#define datetime_destroy nullptr
586#define datetime_clone nullptr
587#define datetime_decref nullptr
588#define datetime_deepcopy nullptr
589#define datetime_iter_children nullptr
590
591static PwInterface_Basic datetime_basic_interface = {
592#define X(name, ...) .name = { .func = datetime_##name } __VA_OPT__(,)
593 PW_BASIC_INTERFACE_METHODS
594#undef X
595};
596
597/****************************************************************
598 * Timestamp type
599 */
600
601static bool timestamp_create(PwMethod_Basic_create* mthis, PwValuePtr result, PwCtorArgs* ctor_args)
602{
603 // XXX use ctor_args for initializer?
604 *result = PwTimestamp(0, 0);
605 return true;
606}
607
608static bool timestamp_hash(PwMethod_Basic_hash* mthis, PwValuePtr self, PwHashContext* ctx, _PwCompoundChain* tail)
609{
610 // mind maps: the hash should be the same for subtypes, that's why not using self->type_id here
611 _pw_hash_uint64(ctx, PwTypeId_Timestamp);
612 _pw_hash_uint64(ctx, self->ts_seconds);
613 _pw_hash_uint64(ctx, self->ts_nanoseconds);
614 return true;
615}
616
617static bool timestamp_dump(PwMethod_Basic_dump* mthis, PwValuePtr self, FILE* fp, int indent, _PwCompoundChain* tail)
618{
619 _pw_print_indent(fp, indent);
620 _pw_print_type(fp, self);
621 fprintf(fp, ": %zu", self->ts_seconds);
622 if (self->ts_nanoseconds) {
623 // format fractional part and print &frac[1] later
624 char frac[12];
625 snprintf(frac, sizeof(frac), "%u", self->ts_nanoseconds + 1000'000'000);
626 fputs(&frac[1], fp);
627 }
628 fputc('\n', fp);
629 return true;
630}
631
632static inline bool timestamp_eq(PwValuePtr self, PwValuePtr other)
633{
634 return self->ts_seconds == other->ts_seconds
635 && self->ts_nanoseconds == other->ts_nanoseconds;
636}
637
638static bool timestamp_equal(PwMethod_Basic_equal* mthis, PwValuePtr self, PwValuePtr other, _PwCompoundChain* tail)
639{
640 PW_EQUAL_METHOD_IMPL(PwTypeId_Timestamp, timestamp_eq, self, other);
641 return false;
642}
643
644static bool timestamp_to_string(PwMethod_Basic_to_string* mthis, PwValuePtr self, PwValuePtr result, _PwCompoundChain* tail)
645{
646 pw_destroy(result);
647 char buf[32];
648 snprintf(buf, sizeof(buf), "%zu.%09u", self->ts_seconds, self->ts_nanoseconds);
649 return pw_create_string(result, buf);
650}
651
652static bool timestamp_is_true(PwMethod_Basic_is_true* mthis, PwValuePtr self, _PwCompoundChain* tail)
653{
654 return self->ts_seconds && self->ts_nanoseconds;
655}
656
657#define timestamp_destroy nullptr
658#define timestamp_clone nullptr
659#define timestamp_decref nullptr
660#define timestamp_deepcopy nullptr
661#define timestamp_iter_children nullptr
662
663static PwInterface_Basic timestamp_basic_interface = {
664#define X(name, ...) .name = { .func = timestamp_##name } __VA_OPT__(,)
665 PW_BASIC_INTERFACE_METHODS
666#undef X
667};
668
669/****************************************************************
670 * Pointer type
671 */
672
673static bool ptr_create(PwMethod_Basic_create* mthis, PwValuePtr result, PwCtorArgs* ctor_args)
674{
675 // XXX use ctor_args for initializer?
676 *result = PwPtr(nullptr);
677 return true;
678}
679
680static bool ptr_hash(PwMethod_Basic_hash* mthis, PwValuePtr self, PwHashContext* ctx, _PwCompoundChain* tail)
681{
682 // mind maps: the hash should be the same for subtypes, that's why not using self->type_id here
683 _pw_hash_uint64(ctx, PwTypeId_Ptr);
684 _pw_hash_buffer(ctx, &self->ptr, sizeof(self->ptr));
685 return true;
686}
687
688static bool ptr_dump(PwMethod_Basic_dump* mthis, PwValuePtr self, FILE* fp, int indent, _PwCompoundChain* tail)
689{
690 _pw_print_indent(fp, indent);
691 _pw_print_type(fp, self);
692 fprintf(fp, ": %p\n", self->ptr);
693 return true;
694}
695
696static bool ptr_equal(PwMethod_Basic_equal* mthis, PwValuePtr self, PwValuePtr other, _PwCompoundChain* tail)
697{
698 uint16_t t = other->type_id;
699 if (_pw_likely(t == PwTypeId_Ptr)) {
700 return self->ptr == other->ptr;
701 }
702 if (_pw_likely(t == PwTypeId_Null)) {
703 return self->ptr == nullptr;
704 }
705 PwType* type = _pw_types[t];
706 PwType** base_type = type->base_types;
707 if (base_type) {
708 PwType** base_types_end = base_type + type->num_base_types;
709 while (base_type < base_types_end) {
710 t = (*base_type)->id;
711 if (t == PwTypeId_Ptr) {
712 return self->ptr == other->ptr;
713 }
714 if (t == PwTypeId_Null) {
715 return self->ptr == nullptr;
716 }
717 base_type++;
718 }
719 }
720 return false;
721}
722
723static bool ptr_to_string(PwMethod_Basic_to_string* mthis, PwValuePtr self, PwValuePtr result, _PwCompoundChain* tail)
724{
725 pw_destroy(result);
726 pw_set_status(PwStatus(PW_ERROR_NOT_IMPLEMENTED));
727 return false;
728}
729
730static bool ptr_is_true(PwMethod_Basic_is_true* mthis, PwValuePtr self, _PwCompoundChain* tail)
731{
732 return self->ptr;
733}
734
735#define ptr_destroy nullptr
736#define ptr_clone nullptr
737#define ptr_decref nullptr
738#define ptr_deepcopy nullptr
739#define ptr_iter_children nullptr
740
741static PwInterface_Basic ptr_basic_interface = {
742#define X(name, ...) .name = { .func = ptr_##name } __VA_OPT__(,)
743 PW_BASIC_INTERFACE_METHODS
744#undef X
745};
746
747/****************************************************************
748 * Type system initialization.
749 */
750
751void pw_dump_types(FILE* fp);
752
753[[nodiscard]] uint16_t _pw_add_type(char* name, unsigned data_size, unsigned data_alignment, ...)
754{
755 if (num_pw_types >= 65534) { // upper limit to avoid overflow in calculations below
756 pw_panic("Too many types: %u\n", num_pw_types);
757 }
758
759 if (mmarray_grow(_pw_types, 1)) { /* no op, address not changed */ }
760
761 uint16_t type_id = (uint16_t) num_pw_types;
762
763 // reuse mmarray for temporary arrays
764 void* mmarray = mmarray_allocate(0, 0, 1);
765
766 // allocate type structure
767
768 PwType* type = _pw_arena_alloc(1, PwType);
769 bzero(type, sizeof(PwType));
770 _pw_types[type_id] = type;
771
772 // init basic fields
773
774 type->id = type_id;
775 type->name = name;
776 type->data_size = data_size;
777 type->data_alignment = data_alignment;
778 type->allocator = &default_allocator;
779
780 // start processing variadic arguments
781
782 va_list ap;
783 va_start(ap);
784
785 int separator = va_arg(ap, int);
786 if (separator == PW_PARENTS) {
787
788 // init parent and base types
789
790 uint16_t* parent_ids = (uint16_t*) mmarray;
791 mmarray_reset(mmarray, sizeof(uint16_t));
792 for (;;) {
793 int parent_id = va_arg(ap, int);
794 if (parent_id == PW_INTERFACES || parent_id == -1) {
795 separator = parent_id;
796 break;
797 }
798 if (parent_id >= (int) type_id) {
799 pw_panic("Parent %d for new type %s(id=%u) does not exist\n", parent_id, name, type_id);
800 }
801 // check if parent is duplicate
802 for (uint16_t i = 0; i < type->num_parents; i++) {
803 if (parent_id == parent_ids[i]) {
804 pw_panic("Duplicate parent %s(id=%d) for new type %s(id=%d)\n",
805 _pw_types[parent_id]->name, parent_id, name, type_id);
806 }
807 }
808 mmarray = parent_ids = mmarray_grow(parent_ids, 1);
809 parent_ids[type->num_parents++] = (uint16_t) parent_id;
810 }
811 if (type->num_parents) {
812
813 // allocate array for parent types
814 type->parents = _pw_arena_alloc(type->num_parents, PwType);
815
816 /* Type precedence lists (TPL) for each parent type used by C3 algorithm (CPL in terms of C3)
817 * TPLs are arrays of type ids. The underlying storage for all arrays is allocated on stack.
818 * TPL for a type includes the type itself plus all base types.
819 * The last TPL is the list of direct parents.
820 */
821 unsigned num_tpls = type->num_parents + 1; // if a type inherits all 65535 types, an overflow is possible
822 // that's why we limit the number of types with 65534
823 uint16_t *tpls[num_tpls]; // the underlying array will be defined after we calculate its size
824 unsigned tpl_array_size = type->num_parents;
825 uint16_t tpl_lengths[num_tpls];
826
827 unsigned max_base_types = type->num_parents; // just a sum of all base types for defining a temporary array for C3 result
828
829 // initialize parent types array and calculate TPL-related stuff
830 for (uint16_t i = 0; i < type->num_parents; i++) {
831 PwType* parent_type = _pw_types[parent_ids[i]];
832 type->parents[i] = parent_type;
833
834 uint16_t n = parent_type->num_base_types;
835 max_base_types += n;
836 tpl_array_size += 1 + n;
837 tpl_lengths[i] = 1 + n;
838 }
839 // the last TPL is the list of direct parents
840 tpl_lengths[type->num_parents] = type->num_parents;
841
842 // allocate temp arrays on the stack
843 uint16_t base_type_ids[max_base_types];
844 uint16_t tpl_array[tpl_array_size];
845
846 // init TPLs
847 uint16_t *tpl_item = tpl_array;
848 for (uint16_t i = 0; i < type->num_parents; i++) {
849 PwType* parent_type = type->parents[i];
850 tpls[i] = tpl_item;
851 // TPL of parent includes the parent type itself and grandparents
852 *tpl_item++ = parent_type->id;
853 PwType** grandparent = parent_type->base_types;
854 PwType** grandparent_end = grandparent + parent_type->num_base_types;
855 while (grandparent < grandparent_end) {
856 *tpl_item++ = (*grandparent)->id;
857 grandparent++;
858 }
859 }
860 // the last TPL is the list of direct parents
861 tpls[type->num_parents] = tpl_item;
862 for (uint16_t i = 0; i < type->num_parents; i++) {
863 *tpl_item++ = type->parents[i]->id;
864 }
865
866 // merge TPLs
867
868 for(;;) {
869 uint16_t *nonempty_tpls[num_tpls];
870 unsigned nonempty_tpl_index[num_tpls];
871 unsigned num_nonempty_tpls = 0;
872
873 for (unsigned i = 0; i < num_tpls; i++) {
874 if (tpl_lengths[i]) {
875 nonempty_tpl_index[num_nonempty_tpls] = i;
876 nonempty_tpls[num_nonempty_tpls] = tpls[i];
877 num_nonempty_tpls++;
878 }
879 }
880 if (num_nonempty_tpls == 0) {
881 // done
882 break;
883 }
884 // find merge candidate among TPL heads
885 unsigned candidate; // type_id or UINT_MAX if rejected
886 for (unsigned i = 0; i < num_nonempty_tpls; i++) {
887 candidate = nonempty_tpls[i][0];
888 for (unsigned j = 0; j < num_nonempty_tpls; j++) {
889 uint16_t *tpl = nonempty_tpls[j];
890 unsigned tpl_len = tpl_lengths[nonempty_tpl_index[j]];
891 for (unsigned k = 1; k < tpl_len; k++) {
892 if (tpl[k] == candidate) {
893 // reject
894 candidate = UINT_MAX;
895 goto reject;
896 }
897 }
898 }
899 // found
900 break;
901
902 reject:
903 }
904 if (candidate == UINT_MAX) {
905 pw_panic("Inconsistent inheritance for new type %s(id=%u)\n", name, type_id);
906 }
907 base_type_ids[type->num_base_types++] = candidate;
908
909 // remove candidate from TPLs
910
911 for (unsigned i = 0; i < num_nonempty_tpls; i++) {
912 uint16_t *tpl = nonempty_tpls[i];
913 if (tpl[0] == candidate) {
914 // remove
915 unsigned j = nonempty_tpl_index[i];
916 tpls[j]++;
917 tpl_lengths[j]--;
918 }
919 }
920 }
921 pw_assert(type->num_base_types);
922
923 // make base types
924 type->base_types = _pw_arena_alloc(type->num_base_types, PwType);
925 for (unsigned i = 0; i < type->num_base_types; i++) {
926 type->base_types[i] = _pw_types[base_type_ids[i]];
927 }
928 }
929 }
930
931 // init offsets for Struct-based type in method resolution order
932
933 if (type->num_base_types) {
934
935 type->struct_offsets = _pw_arena_alloc(type->num_base_types + 1, unsigned);
936
937 unsigned offset = 0;
938
939 // iterate base types backward and initialize offsets backward too
940 unsigned i = type->num_base_types;
941 PwType** base_type_end = type->base_types;
942 PwType** base_type = base_type_end + i;
943 while (base_type > base_type_end) {
944 base_type--;
945 PwType* t = *base_type;
946 type->struct_offsets[i--] = offset;
947 offset = align_unsigned(offset + t->data_size, t->data_alignment);
948 }
949 type->struct_offsets[0] = offset;
950 type->total_struct_size = offset + data_size;
951 }
952 if (type->total_struct_size && !_pw_is_subtype_t(type, PwTypeId_Struct)) {
953 pw_panic("New type %s(id=%u) has %u bytes of associated data but is not derived from struct\n",
954 name, type_id, type->total_struct_size);
955 }
956
957 // init interface definitions, set interface_id field
958
959 if (separator == PW_INTERFACES) {
960
961 PwInterface_Generic** idefs = (PwInterface_Generic**) mmarray;
962 mmarray_reset(mmarray, sizeof(PwInterface_Generic*));
963 for (;;) {
964 int interface_id = va_arg(ap, int);
965 if (interface_id == -1) {
966 separator = -1;
967 break;
968 }
969 if (!pw_interface_exists(interface_id)) {
970 pw_panic("Interface %d for new type %s(id=%u) does not exist\n", interface_id, name, type_id);
971 }
972 for (uint16_t i = 0; i < type->num_interface_definitions; i++) {
973 if (interface_id == idefs[i]->id) {
974 pw_panic("Duplicate interface %s(id=%d) for new type %s(id=%u)\n",
975 pw_get_interface_name(interface_id), interface_id, name, type_id);
976 }
977 }
978 PwInterface_Generic* interface = va_arg(ap, PwInterface_Generic*);
979 mmarray = idefs = mmarray_grow(idefs, 1);
980 idefs[type->num_interface_definitions++] = interface;
981 interface->id = interface_id;
982 }
983 if (type->num_interface_definitions) {
984 type->interface_definitions = _pw_arena_alloc(type->num_interface_definitions, PwInterface_Generic*);
985 memcpy(type->interface_definitions, idefs, type->num_interface_definitions * sizeof(PwInterface_Generic*));
986 }
987 }
988 if (separator != -1) {
989 pw_panic("%s: bad arguments\n", name);
990 }
991 va_end(ap);
992
993 // init interfaces
994
995 // collect interface ids
996 unsigned num_interfaces = 0;
997 uint16_t* all_interface_ids = (uint16_t*) mmarray;
998 mmarray_reset(mmarray, sizeof(uint16_t));
999
1000 // iterate base types backward, then process `type` itself
1001 PwType** base_type_end = type->base_types;
1002 PwType** base_type = base_type_end + type->num_base_types;
1003 for (;;) {
1004 if (base_type == &type) {
1005 break;
1006 } else if (base_type > base_type_end) {
1007 base_type--;
1008 } else if (base_type == base_type_end) {
1009 // finally, process new type
1010 base_type = &type;
1011 } else {
1012 pw_panic("oops\n");
1013 }
1014 PwType* t = *base_type;
1015
1016 PwInterface_Generic** interface = t->interface_definitions;
1017 PwInterface_Generic** interface_end = interface + t->num_interface_definitions;
1018 while (interface < interface_end) {
1019 uint16_t interface_id = (*interface)->id;
1020 bool unique = true;
1021 uint16_t* id_seen = all_interface_ids;
1022 uint16_t* id_seen_end = id_seen + num_interfaces;
1023 while (id_seen < id_seen_end) {
1024 if (interface_id == *id_seen++) {
1025 unique = false;
1026 break;
1027 }
1028 }
1029 if (unique) {
1030 mmarray = all_interface_ids = mmarray_grow(all_interface_ids, 1);
1031 all_interface_ids[num_interfaces++] = interface_id;
1032 }
1033 interface++;
1034 }
1035 }
1036
1037 // allocate array for non-builtin interfaces
1038 // count non-builtin interfaces
1039 for (unsigned i = 0; i < num_interfaces; i++) {
1040 if (all_interface_ids[i] >= PW_NUM_BUILTIN_INTERFACES) {
1041 type->num_other_interfaces++;
1042 }
1043 }
1044 if (type->num_other_interfaces) {
1045 type->other_interfaces = _pw_arena_alloc(type->num_other_interfaces, PwInterface_Generic*);
1046 }
1047
1048 // make interfaces
1049
1050 unsigned other_interface_index = 0; // for initializing type->other_interfaces
1051
1052 for (unsigned i = 0; i < num_interfaces; i++) {
1053 uint16_t interface_id = all_interface_ids[i];
1054 if (interface_id >= PW_NUM_BUILTIN_INTERFACES) {
1055 type->other_interfaces[other_interface_index++] = _pw_make_interface(type, interface_id);
1056 } else {
1057 type->builtin_interfaces[interface_id] = _pw_make_interface(type, interface_id);
1058 }
1059 }
1060
1061 mmarray_free(mmarray);
1062
1063 num_pw_types++;
1064 return type_id;
1065}
1066
1067extern PwInterface_Basic _pw_status_basic_interface;
1068
1069[[gnu::constructor]]
1070void _pw_init_types()
1071{
1072 _pw_init_interfaces();
1073
1074 if (_pw_types) {
1075 return;
1076 }
1077
1078 _pw_types = mmarray_allocate(65536, 0, sizeof(PwType*));
1079
1080 pw_assert( PwTypeId_Null == pw_add_type("Null", PW_INTERFACES, PwInterfaceId_Basic, &null_basic_interface ));
1081 pw_assert( PwTypeId_Bool == pw_add_type("Bool", PW_INTERFACES, PwInterfaceId_Basic, &bool_basic_interface ));
1082 pw_assert( PwTypeId_Int == pw_add_type("Int", PW_INTERFACES, PwInterfaceId_Basic, &int_basic_interface ));
1083 pw_assert( PwTypeId_Signed == pw_add_type("Signed", PW_PARENTS, PwTypeId_Int, PW_INTERFACES, PwInterfaceId_Basic, &signed_basic_interface ));
1084 pw_assert( PwTypeId_Unsigned == pw_add_type("Unsigned", PW_PARENTS, PwTypeId_Int, PW_INTERFACES, PwInterfaceId_Basic, &unsigned_basic_interface ));
1085 pw_assert( PwTypeId_Float == pw_add_type("Float", PW_INTERFACES, PwInterfaceId_Basic, &float_basic_interface ));
1086 pw_assert( PwTypeId_DateTime == pw_add_type("DateTime", PW_INTERFACES, PwInterfaceId_Basic, &datetime_basic_interface ));
1087 pw_assert( PwTypeId_Timestamp == pw_add_type("Timestamp", PW_INTERFACES, PwInterfaceId_Basic, ×tamp_basic_interface ));
1088 pw_assert( PwTypeId_Ptr == pw_add_type("Ptr", PW_INTERFACES, PwInterfaceId_Basic, &ptr_basic_interface ));
1089
1090 pw_assert( PwTypeId_String == pw_add_type2("String", _PwStringData,
1091 PW_INTERFACES,
1092 PwInterfaceId_Basic, &_pw_string_basic_interface,
1093 PwInterfaceId_Append, &_pw_string_append_interface) );
1094
1095 pw_assert( PwTypeId_Struct == pw_add_type2("Struct", _PwStructData,
1096 PW_INTERFACES,
1097 PwInterfaceId_Basic, &_pw_struct_basic_interface) );
1098
1099 pw_assert( PwTypeId_Compound == pw_add_type2("Compound", _PwCompoundData,
1100 PW_PARENTS,
1101 PwTypeId_Struct,
1102 PW_INTERFACES,
1103 PwInterfaceId_Basic, &_pw_compound_basic_interface) );
1104
1105 pw_assert( PwTypeId_Status == pw_add_type2("Status", _PwStatusData,
1106 PW_PARENTS,
1107 PwTypeId_Struct,
1108 PW_INTERFACES,
1109 PwInterfaceId_Basic, &_pw_status_basic_interface) );
1110
1111 pw_assert( PwTypeId_BasicArray == pw_add_type2("BasicArray", _PwArray,
1112 PW_PARENTS,
1113 PwTypeId_Struct,
1114 PW_INTERFACES,
1115 PwInterfaceId_Basic, &_pw_basic_array_basic_interface,
1116 PwInterfaceId_RandomAccess, &_pw_basic_array_random_access_interface,
1117 PwInterfaceId_Append, &_pw_basic_array_append_interface) );
1118
1119 pw_assert( PwTypeId_Array == pw_add_type("Array", PW_PARENTS, PwTypeId_BasicArray, PwTypeId_Compound) );
1120
1121 pw_assert( PwTypeId_BasicMap == pw_add_type2("BasicMap", _PwMap,
1122 PW_PARENTS,
1123 PwTypeId_Struct,
1124 PW_INTERFACES,
1125 PwInterfaceId_Basic, &_pw_basic_map_basic_interface,
1126 PwInterfaceId_RandomAccess, &_pw_basic_map_random_access_interface) );
1127
1128 pw_assert( PwTypeId_Map == pw_add_type("Map", PW_PARENTS, PwTypeId_BasicMap, PwTypeId_Compound) );
1129}
1130
1131/****************************************************************
1132 * Misc. helpers
1133 */
1134
1135void* _pw_get_subtype_struct_ptr(PwValuePtr value, uint16_t type_id)
1136{
1137 PwType* value_type = _pw_types[value->type_id];
1138 PwType** base_type = value_type->base_types;
1139 if (base_type) {
1140 PwType** base_types_end = base_type + value_type->num_base_types;
1141 unsigned* struct_offset = &value_type->struct_offsets[1];
1142 while (base_type < base_types_end) {
1143 if (type_id == (*base_type)->id) {
1144 return (void*)( ((uint8_t*) value->struct_data) + *struct_offset );
1145 }
1146 base_type++;
1147 struct_offset++;
1148 }
1149 }
1150 return nullptr;
1151}
1152
1153[[nodiscard]] bool _pw_iteration_in_progress(PwValuePtr value, unsigned line_number)
1154{
1155 _PwStructData* struct_data = (_PwStructData*) value->struct_data;
1156 if (!struct_data) {
1157 return false;
1158 }
1159 if (_pw_atomic_load(&struct_data->itercount) == 0) {
1160 return false;
1161 }
1162 pw_set_status(PwStatus(PW_ERROR_ITERATION_IN_PROGRESS));
1163 _pw_set_status_location(¤t_task->status, __FILE__, line_number);
1164 return true;
1165}
1166
1167static void dump_interface(FILE* fp, PwInterface_Generic* interface, unsigned indent)
1168{
1169 _pw_print_indent(fp, indent);
1170 fprintf(fp, "%s; id=%u; %u methods:\n", interface->name, interface->id, interface->num_methods);
1171
1172 for (unsigned i = 0; i < interface->num_methods; i++) {
1173 PwMethod_Generic* method = &interface->methods[i];
1174 char* method_name = interface->method_names[i];
1175
1176 _pw_print_indent(fp, indent + 4);
1177
1178 void *p = (void*) &method->func; // work around lack of formatting for function pointers
1179 static_assert(sizeof(PwFunc_Generic) == sizeof(void*));
1180
1181 fprintf(fp, "%p %s %u", *((void**) p), method_name, method->struct_offset);
1182
1183 PwMethod_Generic* m = method->super;
1184 while (m) {
1185 void *p = (void*) &m->func; // work around lack of formatting for function pointers
1186 static_assert(sizeof(PwFunc_Generic) == sizeof(void*));
1187
1188 fprintf(fp, ", %p %s::%s %u", *((void**) p), m->self->type->name, method_name, m->struct_offset);
1189 m = m->super;
1190 }
1191 fputc('\n', fp);
1192 }
1193}
1194
1195void pw_dump_types(FILE* fp)
1196{
1197 fprintf(fp, "=== %u PW types (%p) ===\n", num_pw_types, (void*) _pw_types);
1198 for (uint16_t i = 0; i < num_pw_types; i++) {
1199 PwType* t = _pw_types[i];
1200 fprintf(fp, "%u: %s\n", t->id, t->name);
1201 if (t->num_parents) {
1202 fputs(" parent types: ", fp);
1203 for (unsigned j = 0; j < t->num_parents; j++) {
1204 if (j) {
1205 fputs(", ", fp);
1206 }
1207 fprintf(fp, "%s(%u)", t->parents[j]->name, t->parents[j]->id);
1208 }
1209 fputc('\n', fp);
1210 }
1211 if (t->num_base_types) {
1212 fputs(" all base types: ", fp);
1213 for (unsigned j = 0; j < t->num_base_types; j++) {
1214 if (j) {
1215 fputs(", ", fp);
1216 }
1217 fprintf(fp, "%s (%u)", t->base_types[j]->name, t->base_types[j]->id);
1218 }
1219 fputc('\n', fp);
1220 }
1221 if (t->total_struct_size) {
1222 fprintf(fp, " struct size: %u -- ", t->total_struct_size);
1223 for (unsigned j = t->num_base_types; j > 0;) {
1224 PwType* bt = t->base_types[--j];
1225 fprintf(fp, "%u: %s %u bytes@%u, ", t->struct_offsets[j + 1], bt->name, bt->data_size, bt->data_alignment);
1226 }
1227 fprintf(fp, "%u: %s %u bytes@%u\n", t->struct_offsets[0], t->name, t->data_size, t->data_alignment);
1228 }
1229 fprintf(fp, " builtin interfaces:\n");
1230 for (uint16_t interface_id = 0; interface_id < PW_NUM_BUILTIN_INTERFACES; interface_id++) {
1231 PwInterface_Generic* interface = t->builtin_interfaces[interface_id];
1232 if (interface) {
1233 dump_interface(fp, interface, 4);
1234 }
1235 }
1236 if (t->num_other_interfaces) {
1237 fprintf(fp, " other interfaces:\n");
1238 PwInterface_Generic** interface = t->other_interfaces;
1239 PwInterface_Generic** interface_end = interface + t->num_other_interfaces;
1240 while (interface < interface_end) {
1241 dump_interface(fp, *interface, 4);
1242 interface++;
1243 }
1244 }
1245 }
1246}