infix
A JIT-Powered FFI Library for C
Loading...
Searching...
No Matches
signature.c
Go to the documentation of this file.
1
39#include <ctype.h>
40#include <stdarg.h>
41#include <stdbool.h>
42#include <stdio.h>
43#include <stdlib.h>
44#include <string.h>
45
49
51#define MAX_RECURSION_DEPTH 32
52
58typedef struct {
59 const char * p;
60 const char * start;
62 int depth;
64
65// Forward Declarations for Mutually Recursive Parser Functions
66static infix_type * parse_type(parser_state * state);
68 infix_type ** out_ret_type,
69 infix_function_argument ** out_args,
70 size_t * out_num_args,
71 size_t * out_num_fixed_args);
72
73// Parser Helper Functions
74
82 _infix_set_error(INFIX_CATEGORY_PARSER, code, (size_t)(state->p - state->start));
83}
84
90static void skip_whitespace(parser_state * state) {
91 while (true) {
92 while (isspace((unsigned char)*state->p))
93 state->p++;
94 if (*state->p == '#') // C-style line comments
95 while (*state->p != '\n' && *state->p != '\0')
96 state->p++;
97 else
98 break;
99 }
100}
101
109static bool parse_size_t(parser_state * state, size_t * out_val) {
110 const char * start = state->p;
111 char * end;
112 unsigned long long val = strtoull(start, &end, 10);
113 if (end == start) {
115 return false;
116 }
117 *out_val = (size_t)val;
118 state->p = end;
119 return true;
120}
121
130static const char * parse_identifier(parser_state * state) {
131 skip_whitespace(state);
132 const char * start = state->p;
133 if (!isalpha((unsigned char)*start) && *start != '_')
134 return nullptr;
135 while (isalnum((unsigned char)*state->p) || *state->p == '_' || *state->p == ':') {
136 if (*state->p == ':' && state->p[1] != ':')
137 break; // A single ':' is not part of an identifier.
138 if (*state->p == ':')
139 state->p++; // Consume first ':' of '::'
140 state->p++;
141 }
142 size_t len = state->p - start;
143 if (len == 0)
144 return nullptr;
145 char * name = infix_arena_calloc(state->arena, 1, len + 1, 1);
146 if (!name) {
148 return nullptr;
149 }
150 infix_memcpy((void *)name, start, len);
151 name[len] = '\0';
152 return name;
153}
154
165static bool consume_keyword(parser_state * state, const char * keyword) {
166 skip_whitespace(state);
167 size_t len = strlen(keyword);
168 if (strncmp(state->p, keyword, len) == 0) {
169 // Ensure it's not a prefix of a longer word (e.g., "int" vs "integer").
170 if (isalnum((unsigned char)state->p[len]) || state->p[len] == '_')
171 return false;
172 state->p += len;
173 skip_whitespace(state);
174 return true;
175 }
176 return false;
177}
178
188static const char * parse_optional_name_prefix(parser_state * state) {
189 skip_whitespace(state);
190 // Save the current position in case we need to backtrack.
191 const char * p_before = state->p;
192 const char * name = parse_identifier(state);
193 if (name) {
194 skip_whitespace(state);
195 if (*state->p == ':') { // Found "identifier:", so consume the colon and return the name.
196 state->p++;
197 return name;
198 }
199 }
200 // If it wasn't a `name:`, backtrack to the original position.
201 state->p = p_before;
202 return nullptr;
203}
204
219static bool is_function_signature_ahead(const parser_state * state) {
220 const char * p = state->p;
221 if (*p != '(')
222 return false;
223 p++;
224 // Find the matching ')' by tracking nesting depth.
225 int depth = 1;
226 while (*p != '\0' && depth > 0) {
227 if (*p == '(')
228 depth++;
229 else if (*p == ')')
230 depth--;
231 p++;
232 }
233 if (depth != 0)
234 return false; // Mismatched parentheses.
235 // Skip any whitespace or comments after the ')'
236 while (isspace((unsigned char)*p) || *p == '#') {
237 if (*p == '#')
238 while (*p != '\n' && *p != '\0')
239 p++;
240 else
241 p++;
242 }
243 // Check for the '->' arrow.
244 return (p[0] == '-' && p[1] == '>');
245}
246
247// Aggregate Parsing Logic
248
260static infix_struct_member * parse_aggregate_members(parser_state * state, char end_char, size_t * out_num_members) {
261 // Use a temporary linked list to collect members, as the count is unknown in a single pass.
262 typedef struct member_node {
264 struct member_node * next;
265 } member_node;
266 member_node *head = nullptr, *tail = nullptr;
267 size_t num_members = 0;
268
269 skip_whitespace(state);
270 if (*state->p != end_char) {
271 while (1) {
272 const char * p_before_member = state->p;
273 const char * name = parse_optional_name_prefix(state);
274 // Disallow an empty member definition like `name,` without a type.
275 if (name && (*state->p == ',' || *state->p == end_char)) {
276 state->p = p_before_member + strlen(name); // Position error at end of name
278 return nullptr;
279 }
280
281 infix_type * member_type = parse_type(state);
282 if (!member_type)
283 return nullptr;
284 // Structs and unions cannot have `void` members.
285 if (member_type->category == INFIX_TYPE_VOID) {
287 return nullptr;
288 }
289
290 member_node * node = infix_arena_calloc(state->arena, 1, sizeof(member_node), _Alignof(member_node));
291 if (!node) {
293 INFIX_CATEGORY_ALLOCATION, INFIX_CODE_OUT_OF_MEMORY, (size_t)(state->p - state->start));
294 return nullptr;
295 }
296 // The member offset is not calculated here; it will be done later
297 // by `infix_type_create_struct` or `_infix_type_recalculate_layout`.
298 node->m = infix_type_create_member(name, member_type, 0);
299 node->next = nullptr;
300 if (!head)
301 head = tail = node;
302 else {
303 tail->next = node;
304 tail = node;
305 }
306 num_members++;
307 // Check for next token: ',' or end_char
308 skip_whitespace(state);
309
310 if (*state->p == ',') {
311 state->p++; // Consume comma.
312 skip_whitespace(state);
313 // A trailing comma like `{int,}` is a syntax error.
314 if (*state->p == end_char) {
316 return nullptr;
317 }
318 }
319 else if (*state->p == end_char)
320 break;
321 else { // Unexpected token (e.g., missing comma).
322 if (*state->p == '\0') {
324 return nullptr;
325 }
327 return nullptr;
328 }
329 }
330 }
331
332 *out_num_members = num_members;
333 if (num_members == 0)
334 return nullptr;
335
336 // Convert the temporary linked list to a flat array in the arena.
338 infix_arena_calloc(state->arena, num_members, sizeof(infix_struct_member), _Alignof(infix_struct_member));
339 if (!members) {
341 return nullptr;
342 }
343 member_node * current = head;
344 for (size_t i = 0; i < num_members; i++) {
345 members[i] = current->m;
346 current = current->next;
347 }
348 return members;
349}
350
359static infix_type * parse_aggregate(parser_state * state, char start_char, char end_char) {
360 if (state->depth >= MAX_RECURSION_DEPTH) {
362 return nullptr;
363 }
364 state->depth++;
365
366 if (*state->p != start_char) {
368 state->depth--;
369 return nullptr;
370 }
371 state->p++;
372
373 size_t num_members = 0;
374 infix_struct_member * members = parse_aggregate_members(state, end_char, &num_members);
375 // If member parsing failed, an error is already set. Propagate the failure.
377 state->depth--;
378 return nullptr;
379 }
380
381 if (*state->p != end_char) {
383 state->depth--;
384 return nullptr;
385 }
386 state->p++;
387
388 infix_type * agg_type = nullptr;
389 infix_status status = (start_char == '{') ? infix_type_create_struct(state->arena, &agg_type, members, num_members)
390 : infix_type_create_union(state->arena, &agg_type, members, num_members);
391
392 if (status != INFIX_SUCCESS) {
393 state->depth--;
394 return nullptr;
395 }
396
397 state->depth--;
398 return agg_type;
399}
400
408 size_t alignment = 1; // Default alignment for `!{...}` is 1.
409 if (*state->p == '!') {
410 state->p++;
411 if (isdigit((unsigned char)*state->p)) {
412 // This is the `!N:{...}` form with an explicit alignment.
413 if (!parse_size_t(state, &alignment))
414 return nullptr;
415 if (*state->p != ':') {
417 return nullptr;
418 }
419 state->p++;
420 }
421 }
422
423 skip_whitespace(state);
424 if (*state->p != '{') {
426 return nullptr;
427 }
428 state->p++;
429 size_t num_members = 0;
430 infix_struct_member * members = parse_aggregate_members(state, '}', &num_members);
432 return nullptr;
433
434 if (*state->p != '}') {
436 return nullptr;
437 }
438 state->p++;
439
440 infix_type * packed_type = nullptr;
441 // For packed structs, the total size is simply the sum of member sizes without padding.
442 // The user of `infix_type_create_packed_struct` must provide pre-calculated offsets.
443 // Since our parser doesn't know the offsets, we pass a preliminary size. The final
444 // layout pass will fix this if needed, but for packed structs, the user's offsets
445 // are king.
446 size_t total_size = 0;
447 for (size_t i = 0; i < num_members; ++i)
448 total_size += members[i].type->size;
449
451 infix_type_create_packed_struct(state->arena, &packed_type, total_size, alignment, members, num_members);
452
453 if (status != INFIX_SUCCESS)
454 return nullptr;
455 return packed_type;
456}
457
458// Main Parser Logic
459
471 if (consume_keyword(state, "sint8") || consume_keyword(state, "int8"))
473 if (consume_keyword(state, "uint8"))
475 if (consume_keyword(state, "sint16") || consume_keyword(state, "int16"))
477 if (consume_keyword(state, "uint16"))
479 if (consume_keyword(state, "sint32") || consume_keyword(state, "int32"))
481 if (consume_keyword(state, "uint32"))
483 if (consume_keyword(state, "sint64") || consume_keyword(state, "int64"))
485 if (consume_keyword(state, "uint64"))
487 if (consume_keyword(state, "sint128") || consume_keyword(state, "int128"))
489 if (consume_keyword(state, "uint128"))
491 if (consume_keyword(state, "float32"))
493 if (consume_keyword(state, "float64"))
495 if (consume_keyword(state, "bool"))
497 if (consume_keyword(state, "void"))
498 return infix_type_create_void();
499
500 // C-style convenience aliases
501 if (consume_keyword(state, "uchar"))
503 if (consume_keyword(state, "char"))
505 if (consume_keyword(state, "ushort"))
507 if (consume_keyword(state, "short"))
509 if (consume_keyword(state, "uint"))
511 if (consume_keyword(state, "int"))
513 if (consume_keyword(state, "ulonglong"))
515 if (consume_keyword(state, "longlong"))
517 // `long` is platform-dependent, so we use `sizeof` to pick the correct size.
518 if (consume_keyword(state, "ulong"))
519 return infix_type_create_primitive(sizeof(unsigned long) == 8 ? INFIX_PRIMITIVE_UINT64
521 if (consume_keyword(state, "long"))
523 if (consume_keyword(state, "double"))
525 if (consume_keyword(state, "float"))
527 if (consume_keyword(state, "longdouble"))
529 if (consume_keyword(state, "size_t"))
531 if (consume_keyword(state, "ssize_t"))
533 // uchar.h types
534 if (consume_keyword(state, "char8_t"))
536 if (consume_keyword(state, "char16_t"))
538 if (consume_keyword(state, "char32_t"))
540
541 // AVX convenience aliases
542 if (consume_keyword(state, "m256d")) {
543 infix_type * type = nullptr;
546 if (status != INFIX_SUCCESS)
547 return nullptr; // Propagate failure
548 type->alignment = 32; // YMM registers require 32-byte alignment
549 return type;
550 }
551
552 if (consume_keyword(state, "m256")) {
553 infix_type * type = nullptr;
556 if (status != INFIX_SUCCESS)
557 return nullptr; // Propagate failure
558 type->alignment = 32; // YMM registers require 32-byte alignment
559 return type;
560 }
561
562 if (consume_keyword(state, "m512d")) {
563 infix_type * type = nullptr;
566 if (status != INFIX_SUCCESS)
567 return nullptr;
568 type->alignment = 64; // ZMM registers have 64-byte alignment
569 return type;
570 }
571 if (consume_keyword(state, "m512")) {
572 infix_type * type = nullptr;
575 if (status != INFIX_SUCCESS)
576 return nullptr;
577 type->alignment = 64;
578 return type;
579 }
580 if (consume_keyword(state, "m512i")) {
581 infix_type * type = nullptr;
584 if (status != INFIX_SUCCESS)
585 return nullptr;
586 type->alignment = 64;
587 return type;
588 }
589
590 return nullptr;
591}
592
604 if (state->depth >= MAX_RECURSION_DEPTH) {
606 return nullptr;
607 }
608 state->depth++;
609 skip_whitespace(state);
610 infix_type * result_type = nullptr;
611 const char * p_before_type = state->p;
612
613 if (*state->p == '@') { // Named type reference: `@MyStruct`
614 state->p++;
615 const char * name = parse_identifier(state);
616 if (!name) {
618 state->depth--;
619 return nullptr;
620 }
621 if (infix_type_create_named_reference(state->arena, &result_type, name, INFIX_AGGREGATE_STRUCT) !=
623 result_type = nullptr;
624 }
625 else if (*state->p == '*') { // Pointer type: `*int`
626 state->p++;
627 skip_whitespace(state);
628 infix_type * pointee_type = parse_type(state);
629 if (!pointee_type) {
630 state->depth--;
631 return nullptr;
632 }
633 if (infix_type_create_pointer_to(state->arena, &result_type, pointee_type) != INFIX_SUCCESS)
634 result_type = nullptr;
635 }
636 else if (*state->p == '(') { // Grouped type `(type)` or function pointer `(...) -> type`
637 if (is_function_signature_ahead(state)) {
638 infix_type * ret_type = nullptr;
639 infix_function_argument * args = nullptr;
640 size_t num_args = 0, num_fixed = 0;
641 if (parse_function_signature_details(state, &ret_type, &args, &num_args, &num_fixed) != INFIX_SUCCESS) {
642 state->depth--;
643 return nullptr;
644 }
645 // Manually construct a function pointer type object.
646 // This is represented internally as a pointer-like type with extra metadata.
647 infix_type * func_type = infix_arena_calloc(state->arena, 1, sizeof(infix_type), _Alignof(infix_type));
648 if (!func_type) {
650 INFIX_CATEGORY_ALLOCATION, INFIX_CODE_OUT_OF_MEMORY, (size_t)(state->p - state->start));
651 state->depth--;
652 return nullptr;
653 }
654 func_type->size = sizeof(void *);
655 func_type->alignment = _Alignof(void *);
656 func_type->is_arena_allocated = true;
657 func_type->category = INFIX_TYPE_REVERSE_TRAMPOLINE; // Special category for function types.
659 func_type->meta.func_ptr_info.args = args;
660 func_type->meta.func_ptr_info.num_args = num_args;
661 func_type->meta.func_ptr_info.num_fixed_args = num_fixed;
662 result_type = func_type;
663 }
664 else { // Grouped type: `(type)`
665 state->p++;
666 skip_whitespace(state);
667 result_type = parse_type(state);
668 if (!result_type) {
669 state->depth--;
670 return nullptr;
671 }
672 skip_whitespace(state);
673 if (*state->p != ')') {
675 result_type = nullptr;
676 }
677 else
678 state->p++;
679 }
680 }
681 else if (*state->p == '[') { // Array type: `[size:type]`
682 state->p++;
683 skip_whitespace(state);
684 size_t num_elements;
685 if (!parse_size_t(state, &num_elements)) {
686 state->depth--;
687 return nullptr;
688 }
689 skip_whitespace(state);
690 if (*state->p != ':') {
692 state->depth--;
693 return nullptr;
694 }
695 state->p++;
696 skip_whitespace(state);
697 infix_type * element_type = parse_type(state);
698 if (!element_type) {
699 state->depth--;
700 return nullptr;
701 }
702 if (element_type->category == INFIX_TYPE_VOID) { // An array of `void` is illegal in C.
704 state->depth--;
705 return nullptr;
706 }
707 skip_whitespace(state);
708 if (*state->p != ']') {
710 state->depth--;
711 return nullptr;
712 }
713 state->p++;
714 if (infix_type_create_array(state->arena, &result_type, element_type, num_elements) != INFIX_SUCCESS)
715 result_type = nullptr;
716 }
717 else if (*state->p == '!') // Packed struct
718 result_type = parse_packed_struct(state);
719 else if (*state->p == '{') // Struct
720 result_type = parse_aggregate(state, '{', '}');
721 else if (*state->p == '<') // Union
722 result_type = parse_aggregate(state, '<', '>');
723 else if (*state->p == 'e' && state->p[1] == ':') { // Enum: `e:type`
724 state->p += 2;
725 skip_whitespace(state);
726 infix_type * underlying_type = parse_type(state);
727 if (!underlying_type || underlying_type->category != INFIX_TYPE_PRIMITIVE) {
729 state->depth--;
730 return nullptr;
731 }
732 if (infix_type_create_enum(state->arena, &result_type, underlying_type) != INFIX_SUCCESS)
733 result_type = nullptr;
734 }
735 else if (*state->p == 'c' && state->p[1] == '[') { // Complex: `c[type]`
736 state->p += 2;
737 skip_whitespace(state);
738 infix_type * base_type = parse_type(state);
739 if (!base_type) {
740 state->depth--;
741 return nullptr;
742 }
743 skip_whitespace(state);
744 if (*state->p != ']') {
746 state->depth--;
747 return nullptr;
748 }
749 state->p++;
750 if (infix_type_create_complex(state->arena, &result_type, base_type) != INFIX_SUCCESS)
751 result_type = nullptr;
752 }
753 else if (*state->p == 'v' && state->p[1] == '[') { // Vector: `v[size:type]`
754 state->p += 2;
755 skip_whitespace(state);
756 size_t num_elements;
757 if (!parse_size_t(state, &num_elements)) {
758 state->depth--;
759 return nullptr;
760 }
761 if (*state->p != ':') {
763 state->depth--;
764 return nullptr;
765 }
766 state->p++;
767 infix_type * element_type = parse_type(state);
768 if (!element_type) {
769 state->depth--;
770 return nullptr;
771 }
772 if (*state->p != ']') {
774 state->depth--;
775 return nullptr;
776 }
777 state->p++;
778 if (infix_type_create_vector(state->arena, &result_type, element_type, num_elements) != INFIX_SUCCESS)
779 result_type = nullptr;
780 }
781 else { // Primitive type or error
782 result_type = parse_primitive(state);
783 if (!result_type) {
784 // If no error was set by a failed `consume_keyword`, set a generic one.
786 state->p = p_before_type;
787 if (isalpha((unsigned char)*state->p) || *state->p == '_')
789 else
791 }
792 }
793 }
794
795 state->depth--;
796 return result_type;
797}
798
813 infix_type ** out_ret_type,
814 infix_function_argument ** out_args,
815 size_t * out_num_args,
816 size_t * out_num_fixed_args) {
817 if (*state->p != '(') {
820 }
821 state->p++;
822 skip_whitespace(state);
823
824 // Use a temporary linked list to collect arguments.
825 typedef struct arg_node {
827 struct arg_node * next;
828 } arg_node;
829 arg_node *head = nullptr, *tail = nullptr;
830 size_t num_args = 0;
831
832 // Parse Fixed Arguments
833 if (*state->p != ')' && *state->p != ';') {
834 while (1) {
835 skip_whitespace(state);
836 if (*state->p == ')' || *state->p == ';')
837 break;
838 const char * name = parse_optional_name_prefix(state);
839 infix_type * arg_type = parse_type(state);
840 if (!arg_type)
842
843 arg_node * node = infix_arena_calloc(state->arena, 1, sizeof(arg_node), _Alignof(arg_node));
844 if (!node) {
846 INFIX_CATEGORY_ALLOCATION, INFIX_CODE_OUT_OF_MEMORY, (size_t)(state->p - state->start));
848 }
849 node->arg.type = arg_type;
850 node->arg.name = name;
851 node->next = nullptr;
852 if (!head)
853 head = tail = node;
854 else {
855 tail->next = node;
856 tail = node;
857 }
858 num_args++;
859 skip_whitespace(state);
860 if (*state->p == ',') {
861 state->p++;
862 skip_whitespace(state);
863 if (*state->p == ')' || *state->p == ';') { // Trailing comma error.
866 }
867 }
868 else if (*state->p != ')' && *state->p != ';') {
871 }
872 else
873 break;
874 }
875 }
876 *out_num_fixed_args = num_args;
877
878 // Parse Variadic Arguments
879 if (*state->p == ';') {
880 state->p++;
881 if (*state->p != ')') {
882 while (1) {
883 skip_whitespace(state);
884 if (*state->p == ')')
885 break;
886 const char * name = parse_optional_name_prefix(state);
887 infix_type * arg_type = parse_type(state);
888 if (!arg_type)
890
891 arg_node * node = infix_arena_calloc(state->arena, 1, sizeof(arg_node), _Alignof(arg_node));
892 if (!node) {
894 INFIX_CATEGORY_ALLOCATION, INFIX_CODE_OUT_OF_MEMORY, (size_t)(state->p - state->start));
896 }
897 node->arg.type = arg_type;
898 node->arg.name = name;
899 node->next = nullptr;
900 if (!head)
901 head = tail = node;
902 else {
903 tail->next = node;
904 tail = node;
905 }
906 num_args++;
907 skip_whitespace(state);
908 if (*state->p == ',') {
909 state->p++;
910 skip_whitespace(state);
911 if (*state->p == ')') { // Trailing comma error.
914 }
915 }
916 else if (*state->p != ')') {
919 }
920 else
921 break;
922 }
923 }
924 }
925 skip_whitespace(state);
926 if (*state->p != ')') {
929 }
930 state->p++;
931
932 // Parse Return Type
933 skip_whitespace(state);
934 if (state->p[0] != '-' || state->p[1] != '>') {
937 }
938 state->p += 2;
939 *out_ret_type = parse_type(state);
940 if (!*out_ret_type)
942
943 // Convert linked list of args to a flat array.
944 infix_function_argument * args = (num_args > 0)
945 ? infix_arena_calloc(state->arena, num_args, sizeof(infix_function_argument), _Alignof(infix_function_argument))
946 : nullptr;
947 if (num_args > 0 && !args) {
950 }
951 arg_node * current = head;
952 for (size_t i = 0; i < num_args; i++) {
953 args[i] = current->arg;
954 current = current->next;
955 }
956 *out_args = args;
957 *out_num_args = num_args;
958 return INFIX_SUCCESS;
959}
960
961// High-Level API Implementation
962
980 infix_arena_t ** out_arena,
981 const char * signature) {
982 if (!out_type || !out_arena || !signature || *signature == '\0') {
985 }
986 // The top-level public API is responsible for setting g_infix_last_signature_context.
987 *out_arena = infix_arena_create(4096);
988 if (!*out_arena) {
991 }
992 parser_state state = {.p = signature, .start = signature, .arena = *out_arena, .depth = 0};
993 infix_type * type = parse_type(&state);
994 if (type) {
995 skip_whitespace(&state);
996 // After successfully parsing a type, ensure there is no trailing junk.
997 if (state.p[0] != '\0') {
999 type = nullptr;
1000 }
1001 }
1002 if (!type) {
1003 // If parsing failed at any point, clean up the temporary arena.
1004 infix_arena_destroy(*out_arena);
1005 *out_arena = nullptr;
1006 *out_type = nullptr;
1008 }
1009 *out_type = type;
1010 return INFIX_SUCCESS;
1011}
1012
1027 infix_arena_t ** out_arena,
1028 const char * signature,
1031 g_infix_last_signature_context = signature; // Set context for rich error reporting.
1032
1033 // 1. "Parse" stage: Create a raw, unresolved type graph in a temporary arena.
1034 infix_type * raw_type = nullptr;
1035 infix_arena_t * parser_arena = nullptr;
1036 infix_status status = _infix_parse_type_internal(&raw_type, &parser_arena, signature);
1037 if (status != INFIX_SUCCESS)
1038 return status;
1039
1040 // Create the final arena that will be returned to the caller.
1041 *out_arena = infix_arena_create(4096);
1042 if (!*out_arena) {
1043 infix_arena_destroy(parser_arena);
1046 }
1047
1048 // 2. "Copy" stage: Deep copy the raw graph into the final arena.
1049 infix_type * final_type = _copy_type_graph_to_arena(*out_arena, raw_type);
1050 infix_arena_destroy(parser_arena); // The temporary graph is no longer needed.
1051 if (!final_type) {
1052 infix_arena_destroy(*out_arena);
1053 *out_arena = nullptr;
1056 }
1057
1058 // 3. "Resolve" stage: Replace all named references (`@Name`) with concrete types.
1060 if (status != INFIX_SUCCESS) {
1061 infix_arena_destroy(*out_arena);
1062 *out_arena = nullptr;
1063 *out_type = nullptr;
1064 }
1065 else {
1066 // 4. "Layout" stage: Calculate the final size, alignment, and member offsets.
1068 *out_type = final_type;
1069 }
1070 return status;
1071}
1072
1073
1092 infix_arena_t ** out_arena,
1093 infix_type ** out_ret_type,
1094 infix_function_argument ** out_args,
1095 size_t * out_num_args,
1096 size_t * out_num_fixed_args,
1099 if (!signature || !out_arena || !out_ret_type || !out_args || !out_num_args || !out_num_fixed_args) {
1102 }
1104
1105 // 1. "Parse" stage
1106 infix_type * raw_func_type = nullptr;
1107 infix_arena_t * parser_arena = nullptr;
1108 infix_status status = _infix_parse_type_internal(&raw_func_type, &parser_arena, signature);
1109 if (status != INFIX_SUCCESS)
1110 return status;
1111
1112 if (raw_func_type->category != INFIX_TYPE_REVERSE_TRAMPOLINE) {
1113 infix_arena_destroy(parser_arena);
1116 }
1117
1118 // Create final arena
1119 *out_arena = infix_arena_create(8192);
1120 if (!*out_arena) {
1121 infix_arena_destroy(parser_arena);
1124 }
1125
1126 // 2. "Copy" stage
1127 infix_type * final_func_type = _copy_type_graph_to_arena(*out_arena, raw_func_type);
1128 infix_arena_destroy(parser_arena);
1129
1130 if (!final_func_type) {
1131 infix_arena_destroy(*out_arena);
1132 *out_arena = nullptr;
1135 }
1136
1137 // 3. "Resolve" and 4. "Layout" stages
1139 if (status != INFIX_SUCCESS) {
1140 infix_arena_destroy(*out_arena);
1141 *out_arena = nullptr;
1143 }
1144 _infix_type_recalculate_layout(final_func_type);
1145
1146 // Unpack the results for the caller from the final, processed function type object.
1147 *out_ret_type = final_func_type->meta.func_ptr_info.return_type;
1148 *out_args = final_func_type->meta.func_ptr_info.args;
1149 *out_num_args = final_func_type->meta.func_ptr_info.num_args;
1150 *out_num_fixed_args = final_func_type->meta.func_ptr_info.num_fixed_args;
1151
1152 return INFIX_SUCCESS;
1153}
1154// Type Printing Logic
1155
1161typedef struct {
1162 char * p;
1163 size_t remaining;
1166
1175static void _print(printer_state * state, const char * fmt, ...) {
1176 if (state->status != INFIX_SUCCESS)
1177 return;
1178 va_list args;
1179 va_start(args, fmt);
1180 int written = vsnprintf(state->p, state->remaining, fmt, args);
1181 va_end(args);
1182 if (written < 0 || (size_t)written >= state->remaining)
1183 // If snprintf failed or would have overflowed, mark an error.
1185 else {
1186 state->p += written;
1187 state->remaining -= written;
1188 }
1189}
1190
1191// Forward declaration for mutual recursion in printers.
1192static void _infix_type_print_signature_recursive(printer_state * state, const infix_type * type);
1193
1207 if (state->status != INFIX_SUCCESS || !type) {
1208 if (state->status == INFIX_SUCCESS)
1210 return;
1211 }
1212
1213 // CRITICAL: If the type has a semantic name, always prefer printing it.
1214 if (type->name) {
1215 _print(state, "@%s", type->name);
1216 return;
1217 }
1218
1219 switch (type->category) {
1220 case INFIX_TYPE_VOID:
1221 _print(state, "void");
1222 break;
1224 // This case should ideally not be hit with a fully resolved type, but we handle it for robustness.
1225 _print(state, "@%s", type->meta.named_reference.name);
1226 break;
1227 case INFIX_TYPE_POINTER:
1228 _print(state, "*");
1229 // Special handling for `void*` or recursive pointers to avoid infinite recursion.
1230 if (type->meta.pointer_info.pointee_type == type || type->meta.pointer_info.pointee_type == nullptr ||
1232 _print(state, "void");
1233 else
1235 break;
1236 case INFIX_TYPE_ARRAY:
1237 _print(state, "[%zu:", type->meta.array_info.num_elements);
1239 _print(state, "]");
1240 break;
1241 case INFIX_TYPE_STRUCT:
1242 _print(state, "{");
1243 for (size_t i = 0; i < type->meta.aggregate_info.num_members; ++i) {
1244 if (i > 0)
1245 _print(state, ",");
1246 const infix_struct_member * member = &type->meta.aggregate_info.members[i];
1247 if (member->name)
1248 _print(state, "%s:", member->name);
1250 }
1251 _print(state, "}");
1252 break;
1253 case INFIX_TYPE_UNION:
1254 _print(state, "<");
1255 for (size_t i = 0; i < type->meta.aggregate_info.num_members; ++i) {
1256 if (i > 0)
1257 _print(state, ",");
1258 const infix_struct_member * member = &type->meta.aggregate_info.members[i];
1259 if (member->name)
1260 _print(state, "%s:", member->name);
1262 }
1263 _print(state, ">");
1264 break;
1266 _print(state, "(");
1267 for (size_t i = 0; i < type->meta.func_ptr_info.num_fixed_args; ++i) {
1268 if (i > 0)
1269 _print(state, ",");
1270 const infix_function_argument * arg = &type->meta.func_ptr_info.args[i];
1271 if (arg->name)
1272 _print(state, "%s:", arg->name);
1274 }
1276 _print(state, ";");
1277 for (size_t i = type->meta.func_ptr_info.num_fixed_args; i < type->meta.func_ptr_info.num_args; ++i) {
1278 if (i > type->meta.func_ptr_info.num_fixed_args)
1279 _print(state, ",");
1280 const infix_function_argument * arg = &type->meta.func_ptr_info.args[i];
1281 if (arg->name)
1282 _print(state, "%s:", arg->name);
1284 }
1285 }
1286 _print(state, ")->");
1288 break;
1289 case INFIX_TYPE_ENUM:
1290 _print(state, "e:");
1292 break;
1293 case INFIX_TYPE_COMPLEX:
1294 _print(state, "c[");
1296 _print(state, "]");
1297 break;
1298 case INFIX_TYPE_VECTOR:
1299 {
1300 const infix_type * element_type = type->meta.vector_info.element_type;
1301 size_t num_elements = type->meta.vector_info.num_elements;
1302 bool printed_alias = false;
1303
1304 if (element_type->category == INFIX_TYPE_PRIMITIVE) {
1305 if (num_elements == 8 && is_double(element_type)) {
1306 _print(state, "m512d");
1307 printed_alias = true;
1308 }
1309 else if (num_elements == 16 && is_float(element_type)) {
1310 _print(state, "m512");
1311 printed_alias = true;
1312 }
1313 else if (num_elements == 8 && element_type->meta.primitive_id == INFIX_PRIMITIVE_SINT64) {
1314 _print(state, "m512i");
1315 printed_alias = true;
1316 }
1317 else if (num_elements == 4 && is_double(element_type)) {
1318 _print(state, "m256d");
1319 printed_alias = true;
1320 }
1321 else if (num_elements == 8 && is_float(element_type)) {
1322 _print(state, "m256");
1323 printed_alias = true;
1324 }
1325 }
1326
1327 if (!printed_alias) {
1328 _print(state, "v[%zu:", num_elements);
1329 _infix_type_print_signature_recursive(state, element_type);
1330 _print(state, "]");
1331 }
1332 }
1333 break;
1335 switch (type->meta.primitive_id) {
1337 _print(state, "bool");
1338 break;
1340 _print(state, "sint8");
1341 break;
1343 _print(state, "uint8");
1344 break;
1346 _print(state, "sint16");
1347 break;
1349 _print(state, "uint16");
1350 break;
1352 _print(state, "sint32");
1353 break;
1355 _print(state, "uint32");
1356 break;
1358 _print(state, "sint64");
1359 break;
1361 _print(state, "uint64");
1362 break;
1364 _print(state, "sint128");
1365 break;
1367 _print(state, "uint128");
1368 break;
1370 _print(state, "float");
1371 break;
1373 _print(state, "double");
1374 break;
1376 _print(state, "longdouble");
1377 break;
1378 }
1379 break;
1380 default:
1382 break;
1383 }
1384}
1385
1399 if (state->status != INFIX_SUCCESS || !type) {
1400 if (state->status == INFIX_SUCCESS)
1402 return;
1403 }
1404
1405 // This is the key difference from the main printer: we skip the `if (type->name)` check
1406 // and immediately print the underlying structure of the type.
1407 switch (type->category) {
1408 case INFIX_TYPE_STRUCT:
1409 _print(state, "{");
1410 for (size_t i = 0; i < type->meta.aggregate_info.num_members; ++i) {
1411 if (i > 0)
1412 _print(state, ",");
1413 const infix_struct_member * member = &type->meta.aggregate_info.members[i];
1414 if (member->name)
1415 _print(state, "%s:", member->name);
1416 // For nested members, we can use the standard printer, which IS allowed
1417 // to use the `@Name` shorthand for brevity.
1419 }
1420 _print(state, "}");
1421 break;
1422 case INFIX_TYPE_UNION:
1423 _print(state, "<");
1424 for (size_t i = 0; i < type->meta.aggregate_info.num_members; ++i) {
1425 if (i > 0)
1426 _print(state, ",");
1427 const infix_struct_member * member = &type->meta.aggregate_info.members[i];
1428 if (member->name)
1429 _print(state, "%s:", member->name);
1431 }
1432 _print(state, ">");
1433 break;
1434
1435 // For all other types, we replicate the printing logic from the main printer
1436 // to ensure we print the structure, not a potential top-level alias name.
1437 case INFIX_TYPE_VOID:
1438 _print(state, "void");
1439 break;
1440 case INFIX_TYPE_POINTER:
1441 _print(state, "*");
1442 if (type->meta.pointer_info.pointee_type == type || type->meta.pointer_info.pointee_type == nullptr ||
1444 _print(state, "void");
1445 else
1447 break;
1448 case INFIX_TYPE_ARRAY:
1449 _print(state, "[%zu:", type->meta.array_info.num_elements);
1451 _print(state, "]");
1452 break;
1453 case INFIX_TYPE_ENUM:
1454 _print(state, "e:");
1456 break;
1457 case INFIX_TYPE_COMPLEX:
1458 _print(state, "c[");
1460 _print(state, "]");
1461 break;
1463 // This block is now a full copy from the main printer.
1464 switch (type->meta.primitive_id) {
1466 _print(state, "bool");
1467 break;
1469 _print(state, "sint8");
1470 break;
1472 _print(state, "uint8");
1473 break;
1475 _print(state, "sint16");
1476 break;
1478 _print(state, "uint16");
1479 break;
1481 _print(state, "sint32");
1482 break;
1484 _print(state, "uint32");
1485 break;
1487 _print(state, "sint64");
1488 break;
1490 _print(state, "uint64");
1491 break;
1493 _print(state, "sint128");
1494 break;
1496 _print(state, "uint128");
1497 break;
1499 _print(state, "float");
1500 break;
1502 _print(state, "double");
1503 break;
1505 _print(state, "longdouble");
1506 break;
1507 }
1508 break;
1509 // We can safely delegate the remaining complex cases to the main printer, as they
1510 // do not have a top-level `name` field themselves.
1513 case INFIX_TYPE_VECTOR:
1515 break;
1516 default:
1518 break;
1519 }
1520}
1521
1527 size_t buffer_size,
1528 const infix_type * type,
1529 infix_print_dialect_t dialect) {
1530 if (!buffer || buffer_size == 0 || !type || dialect != INFIX_DIALECT_SIGNATURE)
1532
1533 printer_state state = {buffer, buffer_size, INFIX_SUCCESS};
1534 *buffer = '\0';
1535
1537
1538 if (state.remaining > 0)
1539 *state.p = '\0';
1540 else
1541 buffer[buffer_size - 1] = '\0';
1542
1543 return state.status;
1544}
1545
1555 size_t buffer_size,
1556 const infix_type * type,
1557 infix_print_dialect_t dialect) {
1559 if (!buffer || buffer_size == 0 || !type) {
1562 }
1563
1564 printer_state state = {buffer, buffer_size, INFIX_SUCCESS};
1565 *buffer = '\0';
1566
1567 if (dialect == INFIX_DIALECT_SIGNATURE)
1569 else {
1570 // Placeholder for future dialects like C++ name mangling.
1571 _print(&state, "unsupported_dialect");
1573 }
1574
1575 if (state.status == INFIX_SUCCESS) {
1576 if (state.remaining > 0)
1577 *state.p = '\0'; // Null-terminate if there is space.
1578 else {
1579 // Buffer was exactly full. Ensure null termination at the very end.
1580 buffer[buffer_size - 1] = '\0';
1581 return INFIX_ERROR_INVALID_ARGUMENT; // Indicate truncation.
1582 }
1583 }
1584 else if (buffer_size > 0)
1585 // Ensure null termination even on error (e.g., buffer too small).
1586 buffer[buffer_size - 1] = '\0';
1587
1588 return state.status;
1589}
1590
1604 size_t buffer_size,
1605 const char * function_name,
1606 const infix_type * ret_type,
1608 size_t num_args,
1609 size_t num_fixed_args,
1610 infix_print_dialect_t dialect) {
1612 if (!buffer || buffer_size == 0 || !ret_type || (num_args > 0 && !args)) {
1615 }
1616
1617 printer_state state = {buffer, buffer_size, INFIX_SUCCESS};
1618 *buffer = '\0';
1619 (void)function_name; // Not used in the standard signature dialect.
1620
1621 if (dialect == INFIX_DIALECT_SIGNATURE) {
1622 _print(&state, "(");
1623 for (size_t i = 0; i < num_fixed_args; ++i) {
1624 if (i > 0)
1625 _print(&state, ",");
1627 }
1628 if (num_args > num_fixed_args) {
1629 _print(&state, ";");
1630 for (size_t i = num_fixed_args; i < num_args; ++i) {
1631 if (i > num_fixed_args)
1632 _print(&state, ",");
1634 }
1635 }
1636 _print(&state, ")->");
1638 }
1639 else {
1640 _print(&state, "unsupported_dialect");
1642 }
1643
1644 if (state.status == INFIX_SUCCESS) {
1645 if (state.remaining > 0)
1646 *state.p = '\0';
1647 else {
1648 if (buffer_size > 0)
1649 buffer[buffer_size - 1] = '\0';
1650 return INFIX_ERROR_INVALID_ARGUMENT; // Indicate truncation.
1651 }
1652 }
1653 else if (buffer_size > 0)
1654 buffer[buffer_size - 1] = '\0';
1655
1656 return state.status;
1657}
1658
1673c23_nodiscard infix_status infix_registry_print(char * buffer, size_t buffer_size, const infix_registry_t * registry) {
1674 if (!buffer || buffer_size == 0 || !registry)
1676
1677 printer_state state = {buffer, buffer_size, INFIX_SUCCESS};
1678 *state.p = '\0';
1679
1680 // Iterate through all buckets and their chains.
1681 for (size_t i = 0; i < registry->num_buckets; ++i) {
1682 for (const _infix_registry_entry_t * entry = registry->buckets[i]; entry != nullptr; entry = entry->next) {
1683 // Only print fully defined types, not forward declarations.
1684 if (entry->type && !entry->is_forward_declaration) {
1685 char type_body_buffer[1024];
1686
1688 type_body_buffer, sizeof(type_body_buffer), entry->type, INFIX_DIALECT_SIGNATURE) !=
1689 INFIX_SUCCESS) {
1691 goto end_print_loop;
1692 }
1693
1694 _print(&state, "@%s = %s;\n", entry->name, type_body_buffer);
1695 if (state.status != INFIX_SUCCESS)
1696 goto end_print_loop;
1697 }
1698 }
1699 }
1700end_print_loop:;
1701 return state.status;
1702}
infix_registry_t * registry
Definition 008_registry_introspection.c:35
infix_status status
Definition 103_unions.c:66
infix_struct_member * members
Definition 103_unions.c:60
void * args[]
Definition 202_in_structs.c:64
clock_t start
Definition 901_call_overhead.c:50
infix_type * ret_type
Definition 901_call_overhead.c:66
clock_t end
Definition 901_call_overhead.c:50
#define c23_nodiscard
A compatibility macro for the C23 [[nodiscard]] attribute.
Definition compat_c23.h:113
#define INFIX_TLS
Definition error.c:58
infix_error_code_t
Enumerates specific error codes.
Definition infix.h:1324
infix_error_details_t infix_get_last_error(void)
Retrieves detailed information about the last error that occurred on the current thread.
Definition error.c:270
@ INFIX_CODE_SUCCESS
Definition infix.h:1326
@ INFIX_CODE_INVALID_MEMBER_TYPE
Definition infix.h:1347
@ INFIX_CODE_UNEXPECTED_TOKEN
Definition infix.h:1335
@ INFIX_CODE_MISSING_RETURN_TYPE
Definition infix.h:1338
@ INFIX_CODE_UNKNOWN
Definition infix.h:1327
@ INFIX_CODE_RECURSION_DEPTH_EXCEEDED
Definition infix.h:1340
@ INFIX_CODE_UNTERMINATED_AGGREGATE
Definition infix.h:1336
@ INFIX_CODE_INVALID_KEYWORD
Definition infix.h:1337
@ INFIX_CODE_OUT_OF_MEMORY
Definition infix.h:1330
@ INFIX_CATEGORY_ALLOCATION
Definition infix.h:1316
@ INFIX_CATEGORY_GENERAL
Definition infix.h:1315
@ INFIX_CATEGORY_PARSER
Definition infix.h:1317
struct infix_type_t::@0::@1 pointer_info
Metadata for INFIX_TYPE_POINTER.
union infix_type_t::@0 meta
A union containing metadata specific to the type's category.
struct infix_type_t::@0::@7 vector_info
Metadata for INFIX_TYPE_VECTOR.
infix_type * type
Definition infix.h:289
struct infix_type_t::@0::@4 func_ptr_info
Metadata for INFIX_TYPE_REVERSE_TRAMPOLINE.
c23_nodiscard infix_status infix_type_from_signature(infix_type **out_type, infix_arena_t **out_arena, const char *signature, infix_registry_t *registry)
Parses a signature string representing a single data type.
Definition signature.c:1026
size_t num_elements
Definition infix.h:238
size_t size
Definition infix.h:214
size_t alignment
Definition infix.h:215
infix_struct_member * members
Definition infix.h:231
struct infix_type_t::@0::@6 complex_info
Metadata for INFIX_TYPE_COMPLEX.
const char * name
Definition infix.h:212
infix_function_argument * args
Definition infix.h:244
infix_status
Enumerates the possible status codes returned by infix API functions.
Definition infix.h:389
const char * name
Definition infix.h:288
const char * name
Definition infix.h:278
infix_type_category category
Definition infix.h:213
struct infix_type_t::@0::@2 aggregate_info
Metadata for INFIX_TYPE_STRUCT and INFIX_TYPE_UNION.
struct infix_type_t::@0::@3 array_info
Metadata for INFIX_TYPE_ARRAY.
struct infix_type_t * pointee_type
Definition infix.h:226
infix_type * type
Definition infix.h:279
struct infix_type_t * element_type
Definition infix.h:237
struct infix_type_t * return_type
Definition infix.h:243
c23_nodiscard infix_status infix_signature_parse(const char *signature, infix_arena_t **out_arena, infix_type **out_ret_type, infix_function_argument **out_args, size_t *out_num_args, size_t *out_num_fixed_args, infix_registry_t *registry)
Parses a full function signature string into its constituent parts.
Definition signature.c:1091
struct infix_type_t::@0::@5 enum_info
Metadata for INFIX_TYPE_ENUM.
struct infix_type_t * base_type
Definition infix.h:256
size_t num_members
Definition infix.h:232
struct infix_type_t * underlying_type
Definition infix.h:251
struct infix_type_t::@0::@8 named_reference
Metadata for INFIX_TYPE_NAMED_REFERENCE.
size_t num_fixed_args
Definition infix.h:246
infix_primitive_type_id primitive_id
Metadata for INFIX_TYPE_PRIMITIVE.
Definition infix.h:222
size_t num_args
Definition infix.h:245
bool is_arena_allocated
Definition infix.h:216
@ INFIX_ERROR_ALLOCATION_FAILED
Definition infix.h:391
@ INFIX_SUCCESS
Definition infix.h:390
@ INFIX_ERROR_INVALID_ARGUMENT
Definition infix.h:392
c23_nodiscard infix_status infix_type_print(char *buffer, size_t buffer_size, const infix_type *type, infix_print_dialect_t dialect)
Serializes an infix_type object graph back into a signature string.
Definition signature.c:1554
c23_nodiscard infix_status infix_function_print(char *buffer, size_t buffer_size, const char *function_name, const infix_type *ret_type, const infix_function_argument *args, size_t num_args, size_t num_fixed_args, infix_print_dialect_t dialect)
Serializes a function signature's components into a string.
Definition signature.c:1603
infix_print_dialect_t
Specifies the output format for printing types and function signatures.
Definition infix.h:1112
@ INFIX_DIALECT_SIGNATURE
Definition infix.h:1113
void infix_arena_destroy(infix_arena_t *)
Destroys an arena and frees all memory allocated from it.
Definition arena.c:90
#define infix_memcpy
A macro that can be defined to override the default memcpy function.
Definition infix.h:335
c23_nodiscard void * infix_arena_calloc(infix_arena_t *, size_t, size_t, size_t)
Allocates and zero-initializes a block of memory from an arena.
Definition arena.c:198
c23_nodiscard infix_arena_t * infix_arena_create(size_t)
Creates a new memory arena.
Definition arena.c:55
c23_nodiscard infix_status infix_registry_print(char *buffer, size_t buffer_size, const infix_registry_t *registry)
Serializes all defined types within a registry into a single, human-readable string.
Definition signature.c:1673
c23_nodiscard infix_status infix_type_create_packed_struct(infix_arena_t *, infix_type **, size_t, size_t, infix_struct_member *, size_t)
Creates a new packed struct type with a user-specified layout.
Definition types.c:572
c23_nodiscard infix_type * infix_type_create_void(void)
Creates a static descriptor for the void type.
Definition types.c:193
c23_nodiscard infix_status infix_type_create_union(infix_arena_t *, infix_type **, infix_struct_member *, size_t)
Creates a new union type from an array of members.
Definition types.c:442
c23_nodiscard infix_status infix_type_create_enum(infix_arena_t *, infix_type **, infix_type *)
Creates a new enum type with a specified underlying integer type.
Definition types.c:337
c23_nodiscard infix_status infix_type_create_vector(infix_arena_t *, infix_type **, infix_type *, size_t)
Creates a new SIMD vector type.
Definition types.c:403
c23_nodiscard infix_status infix_type_create_complex(infix_arena_t *, infix_type **, infix_type *)
Creates a new _Complex number type.
Definition types.c:372
c23_nodiscard infix_status infix_type_create_array(infix_arena_t *, infix_type **, infix_type *, size_t)
Creates a new fixed-size array type.
Definition types.c:299
c23_nodiscard infix_status infix_type_create_pointer_to(infix_arena_t *, infix_type **, infix_type *)
Creates a new pointer type that points to a specific type.
Definition types.c:268
c23_nodiscard infix_status infix_type_create_struct(infix_arena_t *, infix_type **, infix_struct_member *, size_t)
Creates a new struct type from an array of members, calculating layout automatically.
Definition types.c:490
c23_nodiscard infix_status infix_type_create_named_reference(infix_arena_t *, infix_type **, const char *, infix_aggregate_category_t)
Creates a placeholder for a named type to be resolved by a registry.
Definition types.c:620
c23_nodiscard infix_type * infix_type_create_primitive(infix_primitive_type_id)
Creates a static descriptor for a primitive C type.
Definition types.c:138
infix_struct_member infix_type_create_member(const char *, infix_type *, size_t)
A factory function to create an infix_struct_member.
Definition types.c:202
@ INFIX_PRIMITIVE_UINT16
Definition infix.h:183
@ INFIX_PRIMITIVE_UINT32
Definition infix.h:185
@ INFIX_PRIMITIVE_LONG_DOUBLE
Definition infix.h:193
@ INFIX_PRIMITIVE_FLOAT
Definition infix.h:191
@ INFIX_PRIMITIVE_DOUBLE
Definition infix.h:192
@ INFIX_PRIMITIVE_SINT16
Definition infix.h:184
@ INFIX_PRIMITIVE_SINT64
Definition infix.h:188
@ INFIX_PRIMITIVE_SINT32
Definition infix.h:186
@ INFIX_PRIMITIVE_UINT8
Definition infix.h:181
@ INFIX_PRIMITIVE_UINT128
Definition infix.h:189
@ INFIX_PRIMITIVE_BOOL
Definition infix.h:180
@ INFIX_PRIMITIVE_UINT64
Definition infix.h:187
@ INFIX_PRIMITIVE_SINT128
Definition infix.h:190
@ INFIX_PRIMITIVE_SINT8
Definition infix.h:182
@ INFIX_TYPE_UNION
Definition infix.h:166
@ INFIX_TYPE_PRIMITIVE
Definition infix.h:163
@ INFIX_TYPE_COMPLEX
Definition infix.h:170
@ INFIX_TYPE_ARRAY
Definition infix.h:167
@ INFIX_TYPE_VECTOR
Definition infix.h:171
@ INFIX_TYPE_VOID
Definition infix.h:173
@ INFIX_TYPE_POINTER
Definition infix.h:164
@ INFIX_TYPE_NAMED_REFERENCE
Definition infix.h:172
@ INFIX_TYPE_REVERSE_TRAMPOLINE
Definition infix.h:168
@ INFIX_TYPE_ENUM
Definition infix.h:169
@ INFIX_TYPE_STRUCT
Definition infix.h:165
@ INFIX_AGGREGATE_STRUCT
Definition infix.h:200
Internal data structures, function prototypes, and constants.
void _infix_set_error(infix_error_category_t category, infix_error_code_t code, size_t position)
Sets the thread-local error state with detailed information.
Definition error.c:155
void _infix_type_recalculate_layout(infix_type *type)
Recalculates the layout of a fully resolved type graph.
Definition types.c:780
infix_type * _copy_type_graph_to_arena(infix_arena_t *, const infix_type *)
Performs a deep copy of a type graph into a destination arena.
Definition types.c:971
c23_nodiscard infix_status _infix_resolve_type_graph_inplace(infix_type **type_ptr, infix_registry_t *registry)
Resolves all named type references in a type graph in-place.
Definition type_registry.c:358
static bool is_double(const infix_type *type)
A fast inline check to determine if an infix_type is a double.
Definition infix_internals.h:719
void _infix_clear_error(void)
Clears the thread-local error state.
Definition error.c:257
static bool is_float(const infix_type *type)
A fast inline check to determine if an infix_type is a float.
Definition infix_internals.h:711
static void _print(printer_state *state, const char *fmt,...)
Definition signature.c:1175
static infix_struct_member * parse_aggregate_members(parser_state *state, char end_char, size_t *out_num_members)
Definition signature.c:260
static bool is_function_signature_ahead(const parser_state *state)
Definition signature.c:219
static void _infix_type_print_body_only_recursive(printer_state *state, const infix_type *type)
Definition signature.c:1398
c23_nodiscard infix_status _infix_type_print_body_only(char *buffer, size_t buffer_size, const infix_type *type, infix_print_dialect_t dialect)
An internal-only function to serialize a type's body without its registered name.
Definition signature.c:1526
#define MAX_RECURSION_DEPTH
Definition signature.c:51
static bool parse_size_t(parser_state *state, size_t *out_val)
Definition signature.c:109
c23_nodiscard infix_status _infix_parse_type_internal(infix_type **out_type, infix_arena_t **out_arena, const char *signature)
The internal core of the signature parser.
Definition signature.c:979
static void set_parser_error(parser_state *state, infix_error_code_t code)
Definition signature.c:81
static infix_type * parse_primitive(parser_state *state)
Definition signature.c:470
static infix_status parse_function_signature_details(parser_state *state, infix_type **out_ret_type, infix_function_argument **out_args, size_t *out_num_args, size_t *out_num_fixed_args)
Definition signature.c:812
static bool consume_keyword(parser_state *state, const char *keyword)
Definition signature.c:165
static infix_type * parse_type(parser_state *state)
Definition signature.c:603
static infix_type * parse_packed_struct(parser_state *state)
Definition signature.c:407
static infix_type * parse_aggregate(parser_state *state, char start_char, char end_char)
Definition signature.c:359
static const char * parse_identifier(parser_state *state)
Definition signature.c:130
static void _infix_type_print_signature_recursive(printer_state *state, const infix_type *type)
Definition signature.c:1206
static const char * parse_optional_name_prefix(parser_state *state)
Definition signature.c:188
INFIX_TLS const char * g_infix_last_signature_context
A thread-local pointer to the full signature string being parsed.
Definition error.c:89
static void skip_whitespace(parser_state *state)
Definition signature.c:90
A single entry in the registry's hash table.
Definition infix_internals.h:161
Internal definition of a memory arena.
Definition infix_internals.h:146
Describes a single argument to a C function.
Definition infix.h:287
Internal definition of a named type registry.
Definition infix_internals.h:175
_infix_registry_entry_t ** buckets
Definition infix_internals.h:180
size_t num_buckets
Definition infix_internals.h:178
Describes a single member of a C struct or union.
Definition infix.h:277
A semi-opaque structure that describes a C type.
Definition infix.h:211
Definition signature.c:58
const char * start
Definition signature.c:60
infix_arena_t * arena
Definition signature.c:61
int depth
Definition signature.c:62
const char * p
Definition signature.c:59
Definition signature.c:1161
char * p
Definition signature.c:1162
size_t remaining
Definition signature.c:1163
infix_status status
Definition signature.c:1164