infix
A JIT-Powered FFI Library for C
Loading...
Searching...
No Matches
signature.c
Go to the documentation of this file.
1
37#include <ctype.h>
38#include <stdarg.h>
39#include <stdbool.h>
40#include <stdio.h>
41#include <stdlib.h>
42#include <string.h>
47#define MAX_RECURSION_DEPTH 32
53typedef struct {
54 const char * p;
55 const char * start;
57 int depth;
59// Forward Declarations for Mutually Recursive Parser Functions
60static infix_type * parse_type(parser_state * state);
62 infix_type ** out_ret_type,
63 infix_function_argument ** out_args,
64 size_t * out_num_args,
65 size_t * out_num_fixed_args);
66// Parser Helper Functions
74 _infix_set_error(INFIX_CATEGORY_PARSER, code, (size_t)(state->p - state->start));
75}
81static void skip_whitespace(parser_state * state) {
82 while (true) {
83 while (isspace((unsigned char)*state->p))
84 state->p++;
85 if (*state->p == '#') // C-style line comments
86 while (*state->p != '\n' && *state->p != '\0')
87 state->p++;
88 else
89 break;
90 }
91}
99static bool parse_size_t(parser_state * state, size_t * out_val) {
100 const char * start = state->p;
101 char * end;
102 unsigned long long val = strtoull(start, &end, 10);
103 if (end == start) {
105 return false;
106 }
107 *out_val = (size_t)val;
108 state->p = end;
109 return true;
110}
119static const char * parse_identifier(parser_state * state) {
120 skip_whitespace(state);
121 const char * start = state->p;
122 if (!isalpha((unsigned char)*start) && *start != '_')
123 return nullptr;
124 while (isalnum((unsigned char)*state->p) || *state->p == '_' || *state->p == ':') {
125 if (*state->p == ':' && state->p[1] != ':')
126 break; // A single ':' is not part of an identifier.
127 if (*state->p == ':')
128 state->p++; // Consume first ':' of '::'
129 state->p++;
130 }
131 size_t len = state->p - start;
132 if (len == 0)
133 return nullptr;
134 char * name = infix_arena_calloc(state->arena, 1, len + 1, 1);
135 if (!name) {
137 return nullptr;
138 }
139 infix_memcpy((void *)name, start, len);
140 name[len] = '\0';
141 return name;
142}
153static bool consume_keyword(parser_state * state, const char * keyword) {
154 skip_whitespace(state);
155 size_t len = strlen(keyword);
156 if (strncmp(state->p, keyword, len) == 0) {
157 // Ensure it's not a prefix of a longer word (e.g., "int" vs "integer").
158 if (isalnum((unsigned char)state->p[len]) || state->p[len] == '_')
159 return false;
160 state->p += len;
161 skip_whitespace(state);
162 return true;
163 }
164 return false;
165}
175static const char * parse_optional_name_prefix(parser_state * state) {
176 skip_whitespace(state);
177 // Save the current position in case we need to backtrack.
178 const char * p_before = state->p;
179 const char * name = parse_identifier(state);
180 if (name) {
181 skip_whitespace(state);
182 if (*state->p == ':') { // Found "identifier:", so consume the colon and return the name.
183 state->p++;
184 return name;
185 }
186 }
187 // If it wasn't a `name:`, backtrack to the original position.
188 state->p = p_before;
189 return nullptr;
190}
205static bool is_function_signature_ahead(const parser_state * state) {
206 const char * p = state->p;
207 if (*p != '(')
208 return false;
209 p++;
210 // Find the matching ')' by tracking nesting depth.
211 int depth = 1;
212 while (*p != '\0' && depth > 0) {
213 if (*p == '(')
214 depth++;
215 else if (*p == ')')
216 depth--;
217 p++;
218 }
219 if (depth != 0)
220 return false; // Mismatched parentheses.
221 // Skip any whitespace or comments after the ')'
222 while (isspace((unsigned char)*p) || *p == '#') {
223 if (*p == '#')
224 while (*p != '\n' && *p != '\0')
225 p++;
226 else
227 p++;
228 }
229 // Check for the '->' arrow.
230 return (p[0] == '-' && p[1] == '>');
231}
232// Aggregate Parsing Logic
244static infix_struct_member * parse_aggregate_members(parser_state * state, char end_char, size_t * out_num_members) {
245 // Use a temporary linked list to collect members, as the count is unknown in a single pass.
246 typedef struct member_node {
248 struct member_node * next;
249 } member_node;
250 member_node *head = nullptr, *tail = nullptr;
251 size_t num_members = 0;
252 skip_whitespace(state);
253 if (*state->p != end_char) {
254 while (1) {
255 const char * p_before_member = state->p;
256 const char * name = parse_optional_name_prefix(state);
257 // Disallow an empty member definition like `name,` without a type.
258 if (name && (*state->p == ',' || *state->p == end_char)) {
259 state->p = p_before_member + strlen(name); // Position error at end of name
261 return nullptr;
262 }
263 infix_type * member_type = parse_type(state);
264 if (!member_type)
265 return nullptr;
266 // Structs and unions cannot have `void` members.
267 if (member_type->category == INFIX_TYPE_VOID) {
269 return nullptr;
270 }
271
272 // Check for bitfield syntax: "name: type : width"
273 uint8_t bit_width = 0;
274 bool is_bitfield = false;
275 skip_whitespace(state);
276 if (*state->p == ':') {
277 state->p++; // Consume ':'
278 skip_whitespace(state);
279 size_t width_val = 0;
280 if (!parse_size_t(state, &width_val))
281 return nullptr; // Error set by parse_size_t
282 if (width_val > 255) {
284 return nullptr;
285 }
286 bit_width = (uint8_t)width_val;
287 is_bitfield = true;
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 if (is_bitfield)
299 node->m = infix_type_create_bitfield_member(name, member_type, 0, bit_width);
300 else
301 node->m = infix_type_create_member(name, member_type, 0);
302
303 node->next = nullptr;
304
305 if (!head)
306 head = tail = node;
307 else {
308 tail->next = node;
309 tail = node;
310 }
311 num_members++;
312 // Check for next token: ',' or end_char
313 skip_whitespace(state);
314 if (*state->p == ',') {
315 state->p++; // Consume comma.
316 skip_whitespace(state);
317 // A trailing comma like `{int,}` is a syntax error.
318 if (*state->p == end_char) {
320 return nullptr;
321 }
322 }
323 else if (*state->p == end_char)
324 break;
325 else { // Unexpected token (e.g., missing comma).
326 if (*state->p == '\0') {
328 return nullptr;
329 }
331 return nullptr;
332 }
333 }
334 }
335 *out_num_members = num_members;
336 if (num_members == 0)
337 return nullptr;
338 // Convert the temporary linked list to a flat array in the arena.
340 infix_arena_calloc(state->arena, num_members, sizeof(infix_struct_member), _Alignof(infix_struct_member));
341 if (!members) {
343 return nullptr;
344 }
345 member_node * current = head;
346 for (size_t i = 0; i < num_members; i++) {
347 members[i] = current->m;
348 current = current->next;
349 }
350 return members;
351}
360static infix_type * parse_aggregate(parser_state * state, char start_char, char end_char) {
361 if (state->depth >= MAX_RECURSION_DEPTH) {
363 return nullptr;
364 }
365 state->depth++;
366 if (*state->p != start_char) {
368 state->depth--;
369 return nullptr;
370 }
371 state->p++;
372 size_t num_members = 0;
373 infix_struct_member * members = parse_aggregate_members(state, end_char, &num_members);
374 // If member parsing failed, an error is already set. Propagate the failure.
376 state->depth--;
377 return nullptr;
378 }
379 if (*state->p != end_char) {
381 state->depth--;
382 return nullptr;
383 }
384 state->p++;
385 infix_type * agg_type = nullptr;
386 infix_status status = (start_char == '{') ? infix_type_create_struct(state->arena, &agg_type, members, num_members)
387 : infix_type_create_union(state->arena, &agg_type, members, num_members);
388 if (status != INFIX_SUCCESS) {
389 state->depth--;
390 return nullptr;
391 }
392 state->depth--;
393 return agg_type;
394}
402 size_t alignment = 1; // Default alignment for `!{...}` is 1.
403 if (*state->p == '!') {
404 state->p++;
405 if (isdigit((unsigned char)*state->p)) {
406 // This is the `!N:{...}` form with an explicit alignment.
407 if (!parse_size_t(state, &alignment))
408 return nullptr;
409 if (*state->p != ':') {
411 return nullptr;
412 }
413 state->p++;
414 }
415 }
416 skip_whitespace(state);
417 if (*state->p != '{') {
419 return nullptr;
420 }
421 state->p++;
422 size_t num_members = 0;
423 infix_struct_member * members = parse_aggregate_members(state, '}', &num_members);
425 return nullptr;
426 if (*state->p != '}') {
428 return nullptr;
429 }
430 state->p++;
431 infix_type * packed_type = nullptr;
432 // For packed structs, the total size is simply the sum of member sizes without padding.
433 // The user of `infix_type_create_packed_struct` must provide pre-calculated offsets.
434 // Since our parser doesn't know the offsets, we pass a preliminary size. The final
435 // layout pass will fix this if needed, but for packed structs, the user's offsets
436 // are king.
437 size_t total_size = 0;
438 for (size_t i = 0; i < num_members; ++i)
439 total_size += members[i].type->size;
441 infix_type_create_packed_struct(state->arena, &packed_type, total_size, alignment, members, num_members);
442 if (status != INFIX_SUCCESS)
443 return nullptr;
444 return packed_type;
445}
446// Main Parser Logic
458 if (consume_keyword(state, "sint8") || consume_keyword(state, "int8"))
460 if (consume_keyword(state, "uint8"))
462 if (consume_keyword(state, "sint16") || consume_keyword(state, "int16"))
464 if (consume_keyword(state, "uint16"))
466 if (consume_keyword(state, "sint32") || consume_keyword(state, "int32"))
468 if (consume_keyword(state, "uint32"))
470 if (consume_keyword(state, "sint64") || consume_keyword(state, "int64"))
472 if (consume_keyword(state, "uint64"))
474 if (consume_keyword(state, "sint128") || consume_keyword(state, "int128"))
476 if (consume_keyword(state, "uint128"))
478 if (consume_keyword(state, "float32"))
480 if (consume_keyword(state, "float64"))
482 if (consume_keyword(state, "bool"))
484 if (consume_keyword(state, "void"))
485 return infix_type_create_void();
486 // C-style convenience aliases
487 if (consume_keyword(state, "uchar"))
489 if (consume_keyword(state, "char"))
491 if (consume_keyword(state, "ushort"))
493 if (consume_keyword(state, "short"))
495 if (consume_keyword(state, "uint"))
497 if (consume_keyword(state, "int"))
499 if (consume_keyword(state, "ulonglong"))
501 if (consume_keyword(state, "longlong"))
503 // `long` is platform-dependent, so we use `sizeof` to pick the correct size.
504 if (consume_keyword(state, "ulong"))
505 return infix_type_create_primitive(sizeof(unsigned long) == 8 ? INFIX_PRIMITIVE_UINT64
507 if (consume_keyword(state, "long"))
509 if (consume_keyword(state, "double"))
511 if (consume_keyword(state, "float"))
513 if (consume_keyword(state, "longdouble"))
515 if (consume_keyword(state, "size_t"))
517 if (consume_keyword(state, "ssize_t"))
519 // uchar.h types
520 if (consume_keyword(state, "char8_t"))
522 if (consume_keyword(state, "char16_t"))
524 if (consume_keyword(state, "char32_t"))
526 // AVX convenience aliases
527 if (consume_keyword(state, "m256d")) {
528 infix_type * type = nullptr;
531 if (status != INFIX_SUCCESS)
532 return nullptr; // Propagate failure
533 type->alignment = 32; // YMM registers require 32-byte alignment
534 return type;
535 }
536 if (consume_keyword(state, "m256")) {
537 infix_type * type = nullptr;
540 if (status != INFIX_SUCCESS)
541 return nullptr; // Propagate failure
542 type->alignment = 32; // YMM registers require 32-byte alignment
543 return type;
544 }
545 if (consume_keyword(state, "m512d")) {
546 infix_type * type = nullptr;
549 if (status != INFIX_SUCCESS)
550 return nullptr;
551 type->alignment = 64; // ZMM registers have 64-byte alignment
552 return type;
553 }
554 if (consume_keyword(state, "m512")) {
555 infix_type * type = nullptr;
558 if (status != INFIX_SUCCESS)
559 return nullptr;
560 type->alignment = 64;
561 return type;
562 }
563 if (consume_keyword(state, "m512i")) {
564 infix_type * type = nullptr;
567 if (status != INFIX_SUCCESS)
568 return nullptr;
569 type->alignment = 64;
570 return type;
571 }
572 return nullptr;
573}
585 if (state->depth >= MAX_RECURSION_DEPTH) {
587 return nullptr;
588 }
589 state->depth++;
590 skip_whitespace(state);
591 infix_type * result_type = nullptr;
592 const char * p_before_type = state->p;
593 if (*state->p == '@') { // Named type reference: `@MyStruct`
594 state->p++;
595 const char * name = parse_identifier(state);
596 if (!name) {
598 state->depth--;
599 return nullptr;
600 }
601 if (infix_type_create_named_reference(state->arena, &result_type, name, INFIX_AGGREGATE_STRUCT) !=
603 result_type = nullptr;
604 }
605 else if (*state->p == '*') { // Pointer type: `*int`
606 state->p++;
607 skip_whitespace(state);
608 infix_type * pointee_type = parse_type(state);
609 if (!pointee_type) {
610 state->depth--;
611 return nullptr;
612 }
613 if (infix_type_create_pointer_to(state->arena, &result_type, pointee_type) != INFIX_SUCCESS)
614 result_type = nullptr;
615 }
616 else if (*state->p == '(') { // Grouped type `(type)` or function pointer `(...) -> type`
617 if (is_function_signature_ahead(state)) {
618 infix_type * ret_type = nullptr;
619 infix_function_argument * args = nullptr;
620 size_t num_args = 0, num_fixed = 0;
621 if (parse_function_signature_details(state, &ret_type, &args, &num_args, &num_fixed) != INFIX_SUCCESS) {
622 state->depth--;
623 return nullptr;
624 }
625 // Manually construct a function pointer type object.
626 // This is represented internally as a pointer-like type with extra metadata.
627 infix_type * func_type = infix_arena_calloc(state->arena, 1, sizeof(infix_type), _Alignof(infix_type));
628 if (!func_type) {
630 INFIX_CATEGORY_ALLOCATION, INFIX_CODE_OUT_OF_MEMORY, (size_t)(state->p - state->start));
631 state->depth--;
632 return nullptr;
633 }
634 func_type->size = sizeof(void *);
635 func_type->alignment = _Alignof(void *);
636 func_type->is_arena_allocated = true;
637 func_type->category = INFIX_TYPE_REVERSE_TRAMPOLINE; // Special category for function types.
639 func_type->meta.func_ptr_info.args = args;
640 func_type->meta.func_ptr_info.num_args = num_args;
641 func_type->meta.func_ptr_info.num_fixed_args = num_fixed;
642 result_type = func_type;
643 }
644 else { // Grouped type: `(type)`
645 state->p++;
646 skip_whitespace(state);
647 result_type = parse_type(state);
648 if (!result_type) {
649 state->depth--;
650 return nullptr;
651 }
652 skip_whitespace(state);
653 if (*state->p != ')') {
655 result_type = nullptr;
656 }
657 else
658 state->p++;
659 }
660 }
661 else if (*state->p == '[') { // Array type: `[size:type]`
662 state->p++;
663 skip_whitespace(state);
664 size_t num_elements = 0;
665 bool is_flexible = false;
666
667 if (*state->p == '?') {
668 // Flexible array member: `[?:type]`
669 is_flexible = true;
670 state->p++;
671 }
672 else if (!parse_size_t(state, &num_elements)) {
673 state->depth--;
674 return nullptr;
675 }
676
677 skip_whitespace(state);
678 if (*state->p != ':') {
680 state->depth--;
681 return nullptr;
682 }
683 state->p++;
684 skip_whitespace(state);
685 infix_type * element_type = parse_type(state);
686 if (!element_type) {
687 state->depth--;
688 return nullptr;
689 }
690 if (element_type->category == INFIX_TYPE_VOID) { // An array of `void` is illegal in C.
692 state->depth--;
693 return nullptr;
694 }
695 skip_whitespace(state);
696 if (*state->p != ']') {
698 state->depth--;
699 return nullptr;
700 }
701 state->p++;
702
703 if (is_flexible) {
704 if (infix_type_create_flexible_array(state->arena, &result_type, element_type) != INFIX_SUCCESS)
705 result_type = nullptr;
706 }
707 else {
708 if (infix_type_create_array(state->arena, &result_type, element_type, num_elements) != INFIX_SUCCESS)
709 result_type = nullptr;
710 }
711 }
712 else if (*state->p == '!') // Packed struct
713 result_type = parse_packed_struct(state);
714 else if (*state->p == '{') // Struct
715 result_type = parse_aggregate(state, '{', '}');
716 else if (*state->p == '<') // Union
717 result_type = parse_aggregate(state, '<', '>');
718 else if (*state->p == 'e' && state->p[1] == ':') { // Enum: `e:type`
719 state->p += 2;
720 skip_whitespace(state);
721 infix_type * underlying_type = parse_type(state);
722 if (!underlying_type || underlying_type->category != INFIX_TYPE_PRIMITIVE) {
724 state->depth--;
725 return nullptr;
726 }
727 if (infix_type_create_enum(state->arena, &result_type, underlying_type) != INFIX_SUCCESS)
728 result_type = nullptr;
729 }
730 else if (*state->p == 'c' && state->p[1] == '[') { // Complex: `c[type]`
731 state->p += 2;
732 skip_whitespace(state);
733 infix_type * base_type = parse_type(state);
734 if (!base_type) {
735 state->depth--;
736 return nullptr;
737 }
738 skip_whitespace(state);
739 if (*state->p != ']') {
741 state->depth--;
742 return nullptr;
743 }
744 state->p++;
745 if (infix_type_create_complex(state->arena, &result_type, base_type) != INFIX_SUCCESS)
746 result_type = nullptr;
747 }
748 else if (*state->p == 'v' && state->p[1] == '[') { // Vector: `v[size:type]`
749 state->p += 2;
750 skip_whitespace(state);
751 size_t num_elements;
752 if (!parse_size_t(state, &num_elements)) {
753 state->depth--;
754 return nullptr;
755 }
756 if (*state->p != ':') {
758 state->depth--;
759 return nullptr;
760 }
761 state->p++;
762 infix_type * element_type = parse_type(state);
763 if (!element_type) {
764 state->depth--;
765 return nullptr;
766 }
767 if (*state->p != ']') {
769 state->depth--;
770 return nullptr;
771 }
772 state->p++;
773 if (infix_type_create_vector(state->arena, &result_type, element_type, num_elements) != INFIX_SUCCESS)
774 result_type = nullptr;
775 }
776 else { // Primitive type or error
777 result_type = parse_primitive(state);
778 if (!result_type) {
779 // If no error was set by a failed `consume_keyword`, set a generic one.
781 state->p = p_before_type;
782 if (isalpha((unsigned char)*state->p) || *state->p == '_')
784 else
786 }
787 }
788 }
789 state->depth--;
790 return result_type;
791}
806 infix_type ** out_ret_type,
807 infix_function_argument ** out_args,
808 size_t * out_num_args,
809 size_t * out_num_fixed_args) {
810 if (*state->p != '(') {
813 }
814 state->p++;
815 skip_whitespace(state);
816 // Use a temporary linked list to collect arguments.
817 typedef struct arg_node {
819 struct arg_node * next;
820 } arg_node;
821 arg_node *head = nullptr, *tail = nullptr;
822 size_t num_args = 0;
823 // Parse Fixed Arguments
824 if (*state->p != ')' && *state->p != ';') {
825 while (1) {
826 skip_whitespace(state);
827 if (*state->p == ')' || *state->p == ';')
828 break;
829 const char * name = parse_optional_name_prefix(state);
830 infix_type * arg_type = parse_type(state);
831 if (!arg_type)
833 arg_node * node = infix_arena_calloc(state->arena, 1, sizeof(arg_node), _Alignof(arg_node));
834 if (!node) {
836 INFIX_CATEGORY_ALLOCATION, INFIX_CODE_OUT_OF_MEMORY, (size_t)(state->p - state->start));
838 }
839 node->arg.type = arg_type;
840 node->arg.name = name;
841 node->next = nullptr;
842 if (!head)
843 head = tail = node;
844 else {
845 tail->next = node;
846 tail = node;
847 }
848 num_args++;
849 skip_whitespace(state);
850 if (*state->p == ',') {
851 state->p++;
852 skip_whitespace(state);
853 if (*state->p == ')' || *state->p == ';') { // Trailing comma error.
856 }
857 }
858 else if (*state->p != ')' && *state->p != ';') {
861 }
862 else
863 break;
864 }
865 }
866 *out_num_fixed_args = num_args;
867 // Parse Variadic Arguments
868 if (*state->p == ';') {
869 state->p++;
870 if (*state->p != ')') {
871 while (1) {
872 skip_whitespace(state);
873 if (*state->p == ')')
874 break;
875 const char * name = parse_optional_name_prefix(state);
876 infix_type * arg_type = parse_type(state);
877 if (!arg_type)
879 arg_node * node = infix_arena_calloc(state->arena, 1, sizeof(arg_node), _Alignof(arg_node));
880 if (!node) {
882 INFIX_CATEGORY_ALLOCATION, INFIX_CODE_OUT_OF_MEMORY, (size_t)(state->p - state->start));
884 }
885 node->arg.type = arg_type;
886 node->arg.name = name;
887 node->next = nullptr;
888 if (!head)
889 head = tail = node;
890 else {
891 tail->next = node;
892 tail = node;
893 }
894 num_args++;
895 skip_whitespace(state);
896 if (*state->p == ',') {
897 state->p++;
898 skip_whitespace(state);
899 if (*state->p == ')') { // Trailing comma error.
902 }
903 }
904 else if (*state->p != ')') {
907 }
908 else
909 break;
910 }
911 }
912 }
913 skip_whitespace(state);
914 if (*state->p != ')') {
917 }
918 state->p++;
919 // Parse Return Type
920 skip_whitespace(state);
921 if (state->p[0] != '-' || state->p[1] != '>') {
924 }
925 state->p += 2;
926 *out_ret_type = parse_type(state);
927 if (!*out_ret_type)
929 // Convert linked list of args to a flat array.
930 infix_function_argument * args = (num_args > 0)
931 ? infix_arena_calloc(state->arena, num_args, sizeof(infix_function_argument), _Alignof(infix_function_argument))
932 : nullptr;
933 if (num_args > 0 && !args) {
936 }
937 arg_node * current = head;
938 for (size_t i = 0; i < num_args; i++) {
939 args[i] = current->arg;
940 current = current->next;
941 }
942 *out_args = args;
943 *out_num_args = num_args;
944 return INFIX_SUCCESS;
945}
946// High-Level API Implementation
964 infix_arena_t ** out_arena,
965 const char * signature) {
966 if (!out_type || !out_arena || !signature || *signature == '\0') {
969 }
970 // The top-level public API is responsible for setting g_infix_last_signature_context.
971 *out_arena = infix_arena_create(4096);
972 if (!*out_arena) {
975 }
976 parser_state state = {.p = signature, .start = signature, .arena = *out_arena, .depth = 0};
977 infix_type * type = parse_type(&state);
978 if (type) {
979 skip_whitespace(&state);
980 // After successfully parsing a type, ensure there is no trailing junk.
981 if (state.p[0] != '\0') {
983 type = nullptr;
984 }
985 }
986 if (!type) {
987 // If parsing failed at any point, clean up the temporary arena.
988 infix_arena_destroy(*out_arena);
989 *out_arena = nullptr;
990 *out_type = nullptr;
992 }
993 *out_type = type;
994 return INFIX_SUCCESS;
995}
1010 infix_arena_t ** out_arena,
1011 const char * signature,
1014 g_infix_last_signature_context = signature; // Set context for rich error reporting.
1015 // 1. "Parse" stage: Create a raw, unresolved type graph in a temporary arena.
1016 infix_type * raw_type = nullptr;
1017 infix_arena_t * parser_arena = nullptr;
1018 infix_status status = _infix_parse_type_internal(&raw_type, &parser_arena, signature);
1019 if (status != INFIX_SUCCESS)
1020 return status;
1021 // Create the final arena that will be returned to the caller.
1022 *out_arena = infix_arena_create(4096);
1023 if (!*out_arena) {
1024 infix_arena_destroy(parser_arena);
1027 }
1028 // 2. "Copy" stage: Deep copy the raw graph into the final arena.
1029 infix_type * final_type = _copy_type_graph_to_arena(*out_arena, raw_type);
1030 infix_arena_destroy(parser_arena); // The temporary graph is no longer needed.
1031 if (!final_type) {
1032 infix_arena_destroy(*out_arena);
1033 *out_arena = nullptr;
1036 }
1037 // 3. "Resolve" stage: Replace all named references (`@Name`) with concrete types.
1039 if (status != INFIX_SUCCESS) {
1040 infix_arena_destroy(*out_arena);
1041 *out_arena = nullptr;
1042 *out_type = nullptr;
1043 }
1044 else {
1045 // 4. "Layout" stage: Calculate the final size, alignment, and member offsets.
1047 *out_type = final_type;
1048 }
1049 return status;
1050}
1069 infix_arena_t ** out_arena,
1070 infix_type ** out_ret_type,
1071 infix_function_argument ** out_args,
1072 size_t * out_num_args,
1073 size_t * out_num_fixed_args,
1076 if (!signature || !out_arena || !out_ret_type || !out_args || !out_num_args || !out_num_fixed_args) {
1079 }
1081 // 1. "Parse" stage
1082 infix_type * raw_func_type = nullptr;
1083 infix_arena_t * parser_arena = nullptr;
1084 infix_status status = _infix_parse_type_internal(&raw_func_type, &parser_arena, signature);
1085 if (status != INFIX_SUCCESS)
1086 return status;
1087 if (raw_func_type->category != INFIX_TYPE_REVERSE_TRAMPOLINE) {
1088 infix_arena_destroy(parser_arena);
1091 }
1092 // Create final arena
1093 *out_arena = infix_arena_create(8192);
1094 if (!*out_arena) {
1095 infix_arena_destroy(parser_arena);
1098 }
1099 // 2. "Copy" stage
1100 infix_type * final_func_type = _copy_type_graph_to_arena(*out_arena, raw_func_type);
1101 infix_arena_destroy(parser_arena);
1102 if (!final_func_type) {
1103 infix_arena_destroy(*out_arena);
1104 *out_arena = nullptr;
1107 }
1108 // 3. "Resolve" and 4. "Layout" stages
1110 if (status != INFIX_SUCCESS) {
1111 infix_arena_destroy(*out_arena);
1112 *out_arena = nullptr;
1114 }
1115 _infix_type_recalculate_layout(final_func_type);
1116 // Unpack the results for the caller from the final, processed function type object.
1117 *out_ret_type = final_func_type->meta.func_ptr_info.return_type;
1118 *out_args = final_func_type->meta.func_ptr_info.args;
1119 *out_num_args = final_func_type->meta.func_ptr_info.num_args;
1120 *out_num_fixed_args = final_func_type->meta.func_ptr_info.num_fixed_args;
1121 return INFIX_SUCCESS;
1122}
1123// Type Printing Logic
1129typedef struct {
1130 char * p;
1131 size_t remaining;
1142static void _print(printer_state * state, const char * fmt, ...) {
1143 if (state->status != INFIX_SUCCESS)
1144 return;
1145 va_list args;
1146 va_start(args, fmt);
1147 int written = vsnprintf(state->p, state->remaining, fmt, args);
1148 va_end(args);
1149 if (written < 0 || (size_t)written >= state->remaining)
1150 // If snprintf failed or would have overflowed, mark an error.
1152 else {
1153 state->p += written;
1154 state->remaining -= written;
1155 }
1156}
1157// Forward declaration for mutual recursion in printers.
1158static void _infix_type_print_signature_recursive(printer_state * state, const infix_type * type);
1172 if (state->status != INFIX_SUCCESS || !type) {
1173 if (state->status == INFIX_SUCCESS)
1175 return;
1176 }
1177 // If the type has a semantic name, always prefer printing it.
1178 if (type->name) {
1179 _print(state, "@%s", type->name);
1180 return;
1181 }
1182 switch (type->category) {
1183 case INFIX_TYPE_VOID:
1184 _print(state, "void");
1185 break;
1187 // This case should ideally not be hit with a fully resolved type, but we handle it for robustness.
1188 _print(state, "@%s", type->meta.named_reference.name);
1189 break;
1190 case INFIX_TYPE_POINTER:
1191 _print(state, "*");
1192 // Special handling for `void*` or recursive pointers to avoid infinite recursion.
1193 if (type->meta.pointer_info.pointee_type == type || type->meta.pointer_info.pointee_type == nullptr ||
1195 _print(state, "void");
1196 else
1198 break;
1199 case INFIX_TYPE_ARRAY:
1200 if (type->meta.array_info.is_flexible)
1201 _print(state, "[?:");
1202 else
1203 _print(state, "[%zu:", type->meta.array_info.num_elements);
1205 _print(state, "]");
1206 break;
1207 case INFIX_TYPE_STRUCT:
1208 if (type->meta.aggregate_info.is_packed) {
1209 _print(state, "!");
1210 if (type->alignment != 1)
1211 _print(state, "%zu:", type->alignment);
1212 }
1213 _print(state, "{");
1214 for (size_t i = 0; i < type->meta.aggregate_info.num_members; ++i) {
1215 if (i > 0)
1216 _print(state, ",");
1217 const infix_struct_member * member = &type->meta.aggregate_info.members[i];
1218 if (member->name)
1219 _print(state, "%s:", member->name);
1221 if (member->bit_width > 0)
1222 _print(state, ":%u", member->bit_width);
1223 }
1224 _print(state, "}");
1225 break;
1226 case INFIX_TYPE_UNION:
1227 _print(state, "<");
1228 for (size_t i = 0; i < type->meta.aggregate_info.num_members; ++i) {
1229 if (i > 0)
1230 _print(state, ",");
1231 const infix_struct_member * member = &type->meta.aggregate_info.members[i];
1232 if (member->name)
1233 _print(state, "%s:", member->name);
1235 // Bitfields in unions are rare but syntactically valid in C.
1236 if (member->bit_width > 0)
1237 _print(state, ":%u", member->bit_width);
1238 }
1239 _print(state, ">");
1240 break;
1242 _print(state, "(");
1243 for (size_t i = 0; i < type->meta.func_ptr_info.num_fixed_args; ++i) {
1244 if (i > 0)
1245 _print(state, ",");
1246 const infix_function_argument * arg = &type->meta.func_ptr_info.args[i];
1247 if (arg->name)
1248 _print(state, "%s:", arg->name);
1250 }
1252 _print(state, ";");
1253 for (size_t i = type->meta.func_ptr_info.num_fixed_args; i < type->meta.func_ptr_info.num_args; ++i) {
1254 if (i > type->meta.func_ptr_info.num_fixed_args)
1255 _print(state, ",");
1256 const infix_function_argument * arg = &type->meta.func_ptr_info.args[i];
1257 if (arg->name)
1258 _print(state, "%s:", arg->name);
1260 }
1261 }
1262 _print(state, ")->");
1264 break;
1265 case INFIX_TYPE_ENUM:
1266 _print(state, "e:");
1268 break;
1269 case INFIX_TYPE_COMPLEX:
1270 _print(state, "c[");
1272 _print(state, "]");
1273 break;
1274 case INFIX_TYPE_VECTOR:
1275 {
1276 const infix_type * element_type = type->meta.vector_info.element_type;
1277 size_t num_elements = type->meta.vector_info.num_elements;
1278 bool printed_alias = false;
1279 if (element_type->category == INFIX_TYPE_PRIMITIVE) {
1280 if (num_elements == 8 && is_double(element_type)) {
1281 _print(state, "m512d");
1282 printed_alias = true;
1283 }
1284 else if (num_elements == 16 && is_float(element_type)) {
1285 _print(state, "m512");
1286 printed_alias = true;
1287 }
1288 else if (num_elements == 8 && element_type->meta.primitive_id == INFIX_PRIMITIVE_SINT64) {
1289 _print(state, "m512i");
1290 printed_alias = true;
1291 }
1292 else if (num_elements == 4 && is_double(element_type)) {
1293 _print(state, "m256d");
1294 printed_alias = true;
1295 }
1296 else if (num_elements == 8 && is_float(element_type)) {
1297 _print(state, "m256");
1298 printed_alias = true;
1299 }
1300 }
1301 if (!printed_alias) {
1302 _print(state, "v[%zu:", num_elements);
1303 _infix_type_print_signature_recursive(state, element_type);
1304 _print(state, "]");
1305 }
1306 }
1307 break;
1309 switch (type->meta.primitive_id) {
1311 _print(state, "bool");
1312 break;
1314 _print(state, "sint8");
1315 break;
1317 _print(state, "uint8");
1318 break;
1320 _print(state, "sint16");
1321 break;
1323 _print(state, "uint16");
1324 break;
1326 _print(state, "sint32");
1327 break;
1329 _print(state, "uint32");
1330 break;
1332 _print(state, "sint64");
1333 break;
1335 _print(state, "uint64");
1336 break;
1338 _print(state, "sint128");
1339 break;
1341 _print(state, "uint128");
1342 break;
1344 _print(state, "float");
1345 break;
1347 _print(state, "double");
1348 break;
1350 _print(state, "longdouble");
1351 break;
1352 }
1353 break;
1354 default:
1356 break;
1357 }
1358}
1372 if (state->status != INFIX_SUCCESS || !type) {
1373 if (state->status == INFIX_SUCCESS)
1375 return;
1376 }
1377 // This is the key difference from the main printer: we skip the `if (type->name)` check
1378 // and immediately print the underlying structure of the type.
1379 switch (type->category) {
1380 case INFIX_TYPE_STRUCT:
1381 if (type->meta.aggregate_info.is_packed) {
1382 _print(state, "!");
1383 if (type->alignment != 1)
1384 _print(state, "%zu:", type->alignment);
1385 }
1386 _print(state, "{");
1387 for (size_t i = 0; i < type->meta.aggregate_info.num_members; ++i) {
1388 if (i > 0)
1389 _print(state, ",");
1390 const infix_struct_member * member = &type->meta.aggregate_info.members[i];
1391 if (member->name)
1392 _print(state, "%s:", member->name);
1393 // For nested members, we can use the standard printer, which IS allowed
1394 // to use the `@Name` shorthand for brevity.
1396 if (member->bit_width > 0)
1397 _print(state, ":%u", member->bit_width);
1398 }
1399 _print(state, "}");
1400 break;
1401 case INFIX_TYPE_UNION:
1402 _print(state, "<");
1403 for (size_t i = 0; i < type->meta.aggregate_info.num_members; ++i) {
1404 if (i > 0)
1405 _print(state, ",");
1406 const infix_struct_member * member = &type->meta.aggregate_info.members[i];
1407 if (member->name)
1408 _print(state, "%s:", member->name);
1410 if (member->bit_width > 0)
1411 _print(state, ":%u", member->bit_width);
1412 }
1413 _print(state, ">");
1414 break;
1415 // For all other types, we replicate the printing logic from the main printer
1416 // to ensure we print the structure, not a potential top-level alias name.
1417 case INFIX_TYPE_VOID:
1418 _print(state, "void");
1419 break;
1420 case INFIX_TYPE_POINTER:
1421 _print(state, "*");
1422 if (type->meta.pointer_info.pointee_type == type || type->meta.pointer_info.pointee_type == nullptr ||
1424 _print(state, "void");
1425 else
1427 break;
1428 case INFIX_TYPE_ARRAY:
1429 if (type->meta.array_info.is_flexible)
1430 _print(state, "[?:");
1431 else
1432 _print(state, "[%zu:", type->meta.array_info.num_elements);
1434 _print(state, "]");
1435 break;
1436 case INFIX_TYPE_ENUM:
1437 _print(state, "e:");
1439 break;
1440 case INFIX_TYPE_COMPLEX:
1441 _print(state, "c[");
1443 _print(state, "]");
1444 break;
1446 // This block is now a full copy from the main printer.
1447 switch (type->meta.primitive_id) {
1449 _print(state, "bool");
1450 break;
1452 _print(state, "sint8");
1453 break;
1455 _print(state, "uint8");
1456 break;
1458 _print(state, "sint16");
1459 break;
1461 _print(state, "uint16");
1462 break;
1464 _print(state, "sint32");
1465 break;
1467 _print(state, "uint32");
1468 break;
1470 _print(state, "sint64");
1471 break;
1473 _print(state, "uint64");
1474 break;
1476 _print(state, "sint128");
1477 break;
1479 _print(state, "uint128");
1480 break;
1482 _print(state, "float");
1483 break;
1485 _print(state, "double");
1486 break;
1488 _print(state, "longdouble");
1489 break;
1490 }
1491 break;
1492 // We can safely delegate the remaining complex cases to the main printer, as they
1493 // do not have a top-level `name` field themselves.
1496 case INFIX_TYPE_VECTOR:
1498 break;
1499 default:
1501 break;
1502 }
1503}
1509 size_t buffer_size,
1510 const infix_type * type,
1511 infix_print_dialect_t dialect) {
1512 if (!buffer || buffer_size == 0 || !type || dialect != INFIX_DIALECT_SIGNATURE)
1514 printer_state state = {buffer, buffer_size, INFIX_SUCCESS};
1515 *buffer = '\0';
1517 if (state.remaining > 0)
1518 *state.p = '\0';
1519 else
1520 buffer[buffer_size - 1] = '\0';
1521 return state.status;
1522}
1532 size_t buffer_size,
1533 const infix_type * type,
1534 infix_print_dialect_t dialect) {
1536 if (!buffer || buffer_size == 0 || !type) {
1539 }
1540 printer_state state = {buffer, buffer_size, INFIX_SUCCESS};
1541 *buffer = '\0';
1542 if (dialect == INFIX_DIALECT_SIGNATURE)
1544 else {
1545 // Placeholder for future dialects like C++ name mangling.
1546 _print(&state, "unsupported_dialect");
1548 }
1549 if (state.status == INFIX_SUCCESS) {
1550 if (state.remaining > 0)
1551 *state.p = '\0'; // Null-terminate if there is space.
1552 else {
1553 // Buffer was exactly full. Ensure null termination at the very end.
1554 buffer[buffer_size - 1] = '\0';
1555 return INFIX_ERROR_INVALID_ARGUMENT; // Indicate truncation.
1556 }
1557 }
1558 else if (buffer_size > 0)
1559 // Ensure null termination even on error (e.g., buffer too small).
1560 buffer[buffer_size - 1] = '\0';
1561 return state.status;
1562}
1576 size_t buffer_size,
1577 const char * function_name,
1578 const infix_type * ret_type,
1580 size_t num_args,
1581 size_t num_fixed_args,
1582 infix_print_dialect_t dialect) {
1584 if (!buffer || buffer_size == 0 || !ret_type || (num_args > 0 && !args)) {
1587 }
1588 printer_state state = {buffer, buffer_size, INFIX_SUCCESS};
1589 *buffer = '\0';
1590 (void)function_name; // Not used in the standard signature dialect.
1591 if (dialect == INFIX_DIALECT_SIGNATURE) {
1592 _print(&state, "(");
1593 for (size_t i = 0; i < num_fixed_args; ++i) {
1594 if (i > 0)
1595 _print(&state, ",");
1597 }
1598 if (num_args > num_fixed_args) {
1599 _print(&state, ";");
1600 for (size_t i = num_fixed_args; i < num_args; ++i) {
1601 if (i > num_fixed_args)
1602 _print(&state, ",");
1604 }
1605 }
1606 _print(&state, ")->");
1608 }
1609 else {
1610 _print(&state, "unsupported_dialect");
1612 }
1613 if (state.status == INFIX_SUCCESS) {
1614 if (state.remaining > 0)
1615 *state.p = '\0';
1616 else {
1617 if (buffer_size > 0)
1618 buffer[buffer_size - 1] = '\0';
1619 return INFIX_ERROR_INVALID_ARGUMENT; // Indicate truncation.
1620 }
1621 }
1622 else if (buffer_size > 0)
1623 buffer[buffer_size - 1] = '\0';
1624 return state.status;
1625}
1640c23_nodiscard infix_status infix_registry_print(char * buffer, size_t buffer_size, const infix_registry_t * registry) {
1641 if (!buffer || buffer_size == 0 || !registry)
1643 printer_state state = {buffer, buffer_size, INFIX_SUCCESS};
1644 *state.p = '\0';
1645 // Iterate through all buckets and their chains.
1646 for (size_t i = 0; i < registry->num_buckets; ++i) {
1647 for (const _infix_registry_entry_t * entry = registry->buckets[i]; entry != nullptr; entry = entry->next) {
1648 // Only print fully defined types, not forward declarations.
1649 if (entry->type && !entry->is_forward_declaration) {
1650 char type_body_buffer[1024];
1652 type_body_buffer, sizeof(type_body_buffer), entry->type, INFIX_DIALECT_SIGNATURE) !=
1653 INFIX_SUCCESS) {
1655 goto end_print_loop;
1656 }
1657 _print(&state, "@%s = %s;\n", entry->name, type_body_buffer);
1658 if (state.status != INFIX_SUCCESS)
1659 goto end_print_loop;
1660 }
1661 }
1662 }
1663end_print_loop:;
1664 return state.status;
1665}
infix_registry_t * registry
Definition 008_registry_introspection.c:32
infix_status status
Definition 103_unions.c:59
infix_struct_member * members
Definition 103_unions.c:53
void * args[]
Definition 202_in_structs.c:57
clock_t start
Definition 901_call_overhead.c:47
infix_type * ret_type
Definition 901_call_overhead.c:60
clock_t end
Definition 901_call_overhead.c:47
#define c23_nodiscard
A compatibility macro for the C23 [[nodiscard]] attribute.
Definition compat_c23.h:106
#define INFIX_TLS
Definition error.c:68
infix_error_code_t
Enumerates specific error codes.
Definition infix.h:1223
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:271
@ INFIX_CODE_SUCCESS
Definition infix.h:1225
@ INFIX_CODE_INVALID_MEMBER_TYPE
Definition infix.h:1243
@ INFIX_CODE_TYPE_TOO_LARGE
Definition infix.h:1241
@ INFIX_CODE_UNEXPECTED_TOKEN
Definition infix.h:1232
@ INFIX_CODE_MISSING_RETURN_TYPE
Definition infix.h:1235
@ INFIX_CODE_UNKNOWN
Definition infix.h:1226
@ INFIX_CODE_RECURSION_DEPTH_EXCEEDED
Definition infix.h:1237
@ INFIX_CODE_UNTERMINATED_AGGREGATE
Definition infix.h:1233
@ INFIX_CODE_INVALID_KEYWORD
Definition infix.h:1234
@ INFIX_CODE_OUT_OF_MEMORY
Definition infix.h:1228
@ INFIX_CATEGORY_ALLOCATION
Definition infix.h:1216
@ INFIX_CATEGORY_GENERAL
Definition infix.h:1215
@ INFIX_CATEGORY_PARSER
Definition infix.h:1217
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.
bool is_packed
Definition infix.h:213
struct infix_type_t::@0::@7 vector_info
Metadata for INFIX_TYPE_VECTOR.
infix_type * type
Definition infix.h:266
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:1009
size_t num_elements
Definition infix.h:218
size_t size
Definition infix.h:197
size_t alignment
Definition infix.h:198
infix_struct_member * members
Definition infix.h:211
struct infix_type_t::@0::@6 complex_info
Metadata for INFIX_TYPE_COMPLEX.
const char * name
Definition infix.h:195
infix_function_argument * args
Definition infix.h:224
infix_status
Enumerates the possible status codes returned by infix API functions.
Definition infix.h:352
const char * name
Definition infix.h:265
const char * name
Definition infix.h:253
infix_type_category category
Definition infix.h:196
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:207
infix_type * type
Definition infix.h:254
struct infix_type_t * element_type
Definition infix.h:217
bool is_flexible
Definition infix.h:219
struct infix_type_t * return_type
Definition infix.h:223
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:1068
struct infix_type_t::@0::@5 enum_info
Metadata for INFIX_TYPE_ENUM.
struct infix_type_t * base_type
Definition infix.h:234
uint8_t bit_width
Definition infix.h:256
size_t num_members
Definition infix.h:212
struct infix_type_t * underlying_type
Definition infix.h:230
struct infix_type_t::@0::@8 named_reference
Metadata for INFIX_TYPE_NAMED_REFERENCE.
size_t num_fixed_args
Definition infix.h:226
infix_primitive_type_id primitive_id
Metadata for INFIX_TYPE_PRIMITIVE.
Definition infix.h:204
size_t num_args
Definition infix.h:225
bool is_arena_allocated
Definition infix.h:199
@ INFIX_ERROR_ALLOCATION_FAILED
Definition infix.h:354
@ INFIX_SUCCESS
Definition infix.h:353
@ INFIX_ERROR_INVALID_ARGUMENT
Definition infix.h:355
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:1531
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:1575
infix_print_dialect_t
Specifies the output format for printing types and function signatures.
Definition infix.h:1038
@ INFIX_DIALECT_SIGNATURE
Definition infix.h:1039
void infix_arena_destroy(infix_arena_t *)
Destroys an arena and frees all memory allocated from it.
Definition arena.c:83
#define infix_memcpy
A macro that can be defined to override the default memcpy function.
Definition infix.h:305
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:179
c23_nodiscard infix_arena_t * infix_arena_create(size_t)
Creates a new memory arena.
Definition arena.c:52
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:1640
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:744
infix_status infix_type_create_flexible_array(infix_arena_t *, infix_type **, infix_type *)
Creates a flexible array member type ([?:type]).
Definition types.c:493
c23_nodiscard infix_type * infix_type_create_void(void)
Creates a static descriptor for the void type.
Definition types.c:183
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:638
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:536
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:600
c23_nodiscard infix_status infix_type_create_complex(infix_arena_t *, infix_type **, infix_type *)
Creates a new _Complex number type.
Definition types.c:570
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:455
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:425
infix_struct_member infix_type_create_bitfield_member(const char *, infix_type *, size_t, uint8_t)
A factory function to create a bitfield infix_struct_member.
Definition types.c:202
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:685
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:792
c23_nodiscard infix_type * infix_type_create_primitive(infix_primitive_type_id)
Creates a static descriptor for a primitive C type.
Definition types.c:130
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:191
@ INFIX_PRIMITIVE_UINT16
Definition infix.h:168
@ INFIX_PRIMITIVE_UINT32
Definition infix.h:170
@ INFIX_PRIMITIVE_LONG_DOUBLE
Definition infix.h:178
@ INFIX_PRIMITIVE_FLOAT
Definition infix.h:176
@ INFIX_PRIMITIVE_DOUBLE
Definition infix.h:177
@ INFIX_PRIMITIVE_SINT16
Definition infix.h:169
@ INFIX_PRIMITIVE_SINT64
Definition infix.h:173
@ INFIX_PRIMITIVE_SINT32
Definition infix.h:171
@ INFIX_PRIMITIVE_UINT8
Definition infix.h:166
@ INFIX_PRIMITIVE_UINT128
Definition infix.h:174
@ INFIX_PRIMITIVE_BOOL
Definition infix.h:165
@ INFIX_PRIMITIVE_UINT64
Definition infix.h:172
@ INFIX_PRIMITIVE_SINT128
Definition infix.h:175
@ INFIX_PRIMITIVE_SINT8
Definition infix.h:167
@ INFIX_TYPE_UNION
Definition infix.h:152
@ INFIX_TYPE_PRIMITIVE
Definition infix.h:149
@ INFIX_TYPE_COMPLEX
Definition infix.h:156
@ INFIX_TYPE_ARRAY
Definition infix.h:153
@ INFIX_TYPE_VECTOR
Definition infix.h:157
@ INFIX_TYPE_VOID
Definition infix.h:159
@ INFIX_TYPE_POINTER
Definition infix.h:150
@ INFIX_TYPE_NAMED_REFERENCE
Definition infix.h:158
@ INFIX_TYPE_REVERSE_TRAMPOLINE
Definition infix.h:154
@ INFIX_TYPE_ENUM
Definition infix.h:155
@ INFIX_TYPE_STRUCT
Definition infix.h:151
@ INFIX_AGGREGATE_STRUCT
Definition infix.h:184
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:165
void _infix_type_recalculate_layout(infix_type *type)
Recalculates the layout of a fully resolved type graph.
Definition types.c:938
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:1125
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:335
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:743
void _infix_clear_error(void)
Clears the thread-local error state.
Definition error.c:258
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:735
static void _print(printer_state *state, const char *fmt,...)
Definition signature.c:1142
static infix_struct_member * parse_aggregate_members(parser_state *state, char end_char, size_t *out_num_members)
Definition signature.c:244
static bool is_function_signature_ahead(const parser_state *state)
Definition signature.c:205
static void _infix_type_print_body_only_recursive(printer_state *state, const infix_type *type)
Definition signature.c:1371
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:1508
#define MAX_RECURSION_DEPTH
Definition signature.c:47
static bool parse_size_t(parser_state *state, size_t *out_val)
Definition signature.c:99
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:963
static void set_parser_error(parser_state *state, infix_error_code_t code)
Definition signature.c:73
static infix_type * parse_primitive(parser_state *state)
Definition signature.c:457
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:805
static bool consume_keyword(parser_state *state, const char *keyword)
Definition signature.c:153
static infix_type * parse_type(parser_state *state)
Definition signature.c:584
static infix_type * parse_packed_struct(parser_state *state)
Definition signature.c:401
static infix_type * parse_aggregate(parser_state *state, char start_char, char end_char)
Definition signature.c:360
static const char * parse_identifier(parser_state *state)
Definition signature.c:119
static void _infix_type_print_signature_recursive(printer_state *state, const infix_type *type)
Definition signature.c:1171
static const char * parse_optional_name_prefix(parser_state *state)
Definition signature.c:175
INFIX_TLS const char * g_infix_last_signature_context
A thread-local pointer to the full signature string being parsed.
Definition error.c:99
static void skip_whitespace(parser_state *state)
Definition signature.c:81
A single entry in the registry's hash table.
Definition infix_internals.h:152
Internal definition of a memory arena.
Definition infix_internals.h:138
Describes a single argument to a C function.
Definition infix.h:264
Internal definition of a named type registry.
Definition infix_internals.h:165
_infix_registry_entry_t ** buckets
Definition infix_internals.h:170
size_t num_buckets
Definition infix_internals.h:168
Describes a single member of a C struct or union.
Definition infix.h:252
A semi-opaque structure that describes a C type.
Definition infix.h:194
Definition signature.c:53
const char * start
Definition signature.c:55
infix_arena_t * arena
Definition signature.c:56
int depth
Definition signature.c:57
const char * p
Definition signature.c:54
Definition signature.c:1129
char * p
Definition signature.c:1130
size_t remaining
Definition signature.c:1131
infix_status status
Definition signature.c:1132