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 // Capture the offset from the start of the signature string *before* parsing the type.
592 size_t current_offset = state->p - state->start;
593 infix_type * result_type = nullptr;
594 const char * p_before_type = state->p;
595 if (*state->p == '@') { // Named type reference: `@MyStruct`
596 state->p++;
597 const char * name = parse_identifier(state);
598 if (!name) {
600 state->depth--;
601 return nullptr;
602 }
603 if (infix_type_create_named_reference(state->arena, &result_type, name, INFIX_AGGREGATE_STRUCT) !=
605 result_type = nullptr;
606 }
607 else if (*state->p == '*') { // Pointer type: `*int`
608 state->p++;
609 skip_whitespace(state);
610 infix_type * pointee_type = parse_type(state);
611 if (!pointee_type) {
612 state->depth--;
613 return nullptr;
614 }
615 if (infix_type_create_pointer_to(state->arena, &result_type, pointee_type) != INFIX_SUCCESS)
616 result_type = nullptr;
617 }
618 else if (*state->p == '(') { // Grouped type `(type)` or function pointer `(...) -> type`
619 if (is_function_signature_ahead(state)) {
620 infix_type * ret_type = nullptr;
621 infix_function_argument * args = nullptr;
622 size_t num_args = 0, num_fixed = 0;
623 if (parse_function_signature_details(state, &ret_type, &args, &num_args, &num_fixed) != INFIX_SUCCESS) {
624 state->depth--;
625 return nullptr;
626 }
627 // Manually construct a function pointer type object.
628 // This is represented internally as a pointer-like type with extra metadata.
629 infix_type * func_type = infix_arena_calloc(state->arena, 1, sizeof(infix_type), _Alignof(infix_type));
630 if (!func_type) {
632 INFIX_CATEGORY_ALLOCATION, INFIX_CODE_OUT_OF_MEMORY, (size_t)(state->p - state->start));
633 state->depth--;
634 return nullptr;
635 }
636 func_type->size = sizeof(void *);
637 func_type->alignment = _Alignof(void *);
638 func_type->is_arena_allocated = true;
639 func_type->category = INFIX_TYPE_REVERSE_TRAMPOLINE; // Special category for function types.
641 func_type->meta.func_ptr_info.args = args;
642 func_type->meta.func_ptr_info.num_args = num_args;
643 func_type->meta.func_ptr_info.num_fixed_args = num_fixed;
644 result_type = func_type;
645 }
646 else { // Grouped type: `(type)`
647 state->p++;
648 skip_whitespace(state);
649 result_type = parse_type(state);
650 if (!result_type) {
651 state->depth--;
652 return nullptr;
653 }
654 skip_whitespace(state);
655 if (*state->p != ')') {
657 result_type = nullptr;
658 }
659 else
660 state->p++;
661 }
662 }
663 else if (*state->p == '[') { // Array type: `[size:type]`
664 state->p++;
665 skip_whitespace(state);
666 size_t num_elements = 0;
667 bool is_flexible = false;
668
669 if (*state->p == '?') {
670 // Flexible array member: `[?:type]`
671 is_flexible = true;
672 state->p++;
673 }
674 else if (!parse_size_t(state, &num_elements)) {
675 state->depth--;
676 return nullptr;
677 }
678
679 skip_whitespace(state);
680 if (*state->p != ':') {
682 state->depth--;
683 return nullptr;
684 }
685 state->p++;
686 skip_whitespace(state);
687 infix_type * element_type = parse_type(state);
688 if (!element_type) {
689 state->depth--;
690 return nullptr;
691 }
692 if (element_type->category == INFIX_TYPE_VOID) { // An array of `void` is illegal in C.
694 state->depth--;
695 return nullptr;
696 }
697 skip_whitespace(state);
698 if (*state->p != ']') {
700 state->depth--;
701 return nullptr;
702 }
703 state->p++;
704
705 if (is_flexible) {
706 if (infix_type_create_flexible_array(state->arena, &result_type, element_type) != INFIX_SUCCESS)
707 result_type = nullptr;
708 }
709 else {
710 if (infix_type_create_array(state->arena, &result_type, element_type, num_elements) != INFIX_SUCCESS)
711 result_type = nullptr;
712 }
713 }
714 else if (*state->p == '!') // Packed struct
715 result_type = parse_packed_struct(state);
716 else if (*state->p == '{') // Struct
717 result_type = parse_aggregate(state, '{', '}');
718 else if (*state->p == '<') // Union
719 result_type = parse_aggregate(state, '<', '>');
720 else if (*state->p == 'e' && state->p[1] == ':') { // Enum: `e:type`
721 state->p += 2;
722 skip_whitespace(state);
723 infix_type * underlying_type = parse_type(state);
724 if (!underlying_type || underlying_type->category != INFIX_TYPE_PRIMITIVE) {
726 state->depth--;
727 return nullptr;
728 }
729 if (infix_type_create_enum(state->arena, &result_type, underlying_type) != INFIX_SUCCESS)
730 result_type = nullptr;
731 }
732 else if (*state->p == 'c' && state->p[1] == '[') { // Complex: `c[type]`
733 state->p += 2;
734 skip_whitespace(state);
735 infix_type * base_type = parse_type(state);
736 if (!base_type) {
737 state->depth--;
738 return nullptr;
739 }
740 skip_whitespace(state);
741 if (*state->p != ']') {
743 state->depth--;
744 return nullptr;
745 }
746 state->p++;
747 if (infix_type_create_complex(state->arena, &result_type, base_type) != INFIX_SUCCESS)
748 result_type = nullptr;
749 }
750 else if (*state->p == 'v' && state->p[1] == '[') { // Vector: `v[size:type]`
751 state->p += 2;
752 skip_whitespace(state);
753 size_t num_elements;
754 if (!parse_size_t(state, &num_elements)) {
755 state->depth--;
756 return nullptr;
757 }
758 if (*state->p != ':') {
760 state->depth--;
761 return nullptr;
762 }
763 state->p++;
764 infix_type * element_type = parse_type(state);
765 if (!element_type) {
766 state->depth--;
767 return nullptr;
768 }
769 if (*state->p != ']') {
771 state->depth--;
772 return nullptr;
773 }
774 state->p++;
775 if (infix_type_create_vector(state->arena, &result_type, element_type, num_elements) != INFIX_SUCCESS)
776 result_type = nullptr;
777 }
778 else { // Primitive type or error
779 result_type = parse_primitive(state);
780 if (!result_type) {
781 // If no error was set by a failed `consume_keyword`, set a generic one.
783 state->p = p_before_type;
784 if (isalpha((unsigned char)*state->p) || *state->p == '_')
786 else
788 }
789 }
790 }
791 // Only set source offset for dynamically allocated types (primitives are static singletons).
792 if (result_type && result_type->is_arena_allocated)
793 result_type->source_offset = current_offset;
794 state->depth--;
795 return result_type;
796}
811 infix_type ** out_ret_type,
812 infix_function_argument ** out_args,
813 size_t * out_num_args,
814 size_t * out_num_fixed_args) {
815 if (*state->p != '(') {
818 }
819 state->p++;
820 skip_whitespace(state);
821 // Use a temporary linked list to collect arguments.
822 typedef struct arg_node {
824 struct arg_node * next;
825 } arg_node;
826 arg_node *head = nullptr, *tail = nullptr;
827 size_t num_args = 0;
828 // Parse Fixed Arguments
829 if (*state->p != ')' && *state->p != ';') {
830 while (1) {
831 skip_whitespace(state);
832 if (*state->p == ')' || *state->p == ';')
833 break;
834 const char * name = parse_optional_name_prefix(state);
835 infix_type * arg_type = parse_type(state);
836 if (!arg_type)
838 arg_node * node = infix_arena_calloc(state->arena, 1, sizeof(arg_node), _Alignof(arg_node));
839 if (!node) {
841 INFIX_CATEGORY_ALLOCATION, INFIX_CODE_OUT_OF_MEMORY, (size_t)(state->p - state->start));
843 }
844 node->arg.type = arg_type;
845 node->arg.name = name;
846 node->next = nullptr;
847 if (!head)
848 head = tail = node;
849 else {
850 tail->next = node;
851 tail = node;
852 }
853 num_args++;
854 skip_whitespace(state);
855 if (*state->p == ',') {
856 state->p++;
857 skip_whitespace(state);
858 if (*state->p == ')' || *state->p == ';') { // Trailing comma error.
861 }
862 }
863 else if (*state->p != ')' && *state->p != ';') {
866 }
867 else
868 break;
869 }
870 }
871 *out_num_fixed_args = num_args;
872 // Parse Variadic Arguments
873 if (*state->p == ';') {
874 state->p++;
875 if (*state->p != ')') {
876 while (1) {
877 skip_whitespace(state);
878 if (*state->p == ')')
879 break;
880 const char * name = parse_optional_name_prefix(state);
881 infix_type * arg_type = parse_type(state);
882 if (!arg_type)
884 arg_node * node = infix_arena_calloc(state->arena, 1, sizeof(arg_node), _Alignof(arg_node));
885 if (!node) {
887 INFIX_CATEGORY_ALLOCATION, INFIX_CODE_OUT_OF_MEMORY, (size_t)(state->p - state->start));
889 }
890 node->arg.type = arg_type;
891 node->arg.name = name;
892 node->next = nullptr;
893 if (!head)
894 head = tail = node;
895 else {
896 tail->next = node;
897 tail = node;
898 }
899 num_args++;
900 skip_whitespace(state);
901 if (*state->p == ',') {
902 state->p++;
903 skip_whitespace(state);
904 if (*state->p == ')') { // Trailing comma error.
907 }
908 }
909 else if (*state->p != ')') {
912 }
913 else
914 break;
915 }
916 }
917 }
918 skip_whitespace(state);
919 if (*state->p != ')') {
922 }
923 state->p++;
924 // Parse Return Type
925 skip_whitespace(state);
926 if (state->p[0] != '-' || state->p[1] != '>') {
929 }
930 state->p += 2;
931 *out_ret_type = parse_type(state);
932 if (!*out_ret_type)
934 // Convert linked list of args to a flat array.
935 infix_function_argument * args = (num_args > 0)
936 ? infix_arena_calloc(state->arena, num_args, sizeof(infix_function_argument), _Alignof(infix_function_argument))
937 : nullptr;
938 if (num_args > 0 && !args) {
941 }
942 arg_node * current = head;
943 for (size_t i = 0; i < num_args; i++) {
944 args[i] = current->arg;
945 current = current->next;
946 }
947 *out_args = args;
948 *out_num_args = num_args;
949 return INFIX_SUCCESS;
950}
951// High-Level API Implementation
969 infix_arena_t ** out_arena,
970 const char * signature) {
971 if (!out_type || !out_arena) {
974 }
975 if (!signature || *signature == '\0') {
978 }
979 // The top-level public API is responsible for setting g_infix_last_signature_context.
980 *out_arena = infix_arena_create(4096);
981 if (!*out_arena) {
984 }
985 parser_state state = {.p = signature, .start = signature, .arena = *out_arena, .depth = 0};
986 infix_type * type = parse_type(&state);
987 if (type) {
988 skip_whitespace(&state);
989 // After successfully parsing a type, ensure there is no trailing junk.
990 if (state.p[0] != '\0') {
992 type = nullptr;
993 }
994 }
995 if (!type) {
996 // If parsing failed at any point, clean up the temporary arena.
997 infix_arena_destroy(*out_arena);
998 *out_arena = nullptr;
999 *out_type = nullptr;
1001 }
1002 *out_type = type;
1003 return INFIX_SUCCESS;
1004}
1019 infix_arena_t ** out_arena,
1020 const char * signature,
1023 g_infix_last_signature_context = signature; // Set context for rich error reporting.
1024 // 1. "Parse" stage: Create a raw, unresolved type graph in a temporary arena.
1025 infix_type * raw_type = nullptr;
1026 infix_arena_t * parser_arena = nullptr;
1027 infix_status status = _infix_parse_type_internal(&raw_type, &parser_arena, signature);
1028 if (status != INFIX_SUCCESS)
1029 return status;
1030 // Create the final arena that will be returned to the caller.
1031 *out_arena = infix_arena_create(4096);
1032 if (!*out_arena) {
1033 infix_arena_destroy(parser_arena);
1036 }
1037 // 2. "Copy" stage: Deep copy the raw graph into the final arena.
1038 infix_type * final_type = _copy_type_graph_to_arena(*out_arena, raw_type);
1039 infix_arena_destroy(parser_arena); // The temporary graph is no longer needed.
1040 if (!final_type) {
1041 infix_arena_destroy(*out_arena);
1042 *out_arena = nullptr;
1045 }
1046 // 3. "Resolve" stage: Replace all named references (`@Name`) with concrete types.
1048 if (status != INFIX_SUCCESS) {
1049 infix_arena_destroy(*out_arena);
1050 *out_arena = nullptr;
1051 *out_type = nullptr;
1052 }
1053 else {
1054 // 4. "Layout" stage: Calculate the final size, alignment, and member offsets.
1056 *out_type = final_type;
1057 }
1058 return status;
1059}
1078 infix_arena_t ** out_arena,
1079 infix_type ** out_ret_type,
1080 infix_function_argument ** out_args,
1081 size_t * out_num_args,
1082 size_t * out_num_fixed_args,
1085
1086 //
1087 if (!signature) {
1090 }
1091 if (*signature == '\0') {
1094 }
1095 if (!out_arena || !out_ret_type || !out_args || !out_num_args || !out_num_fixed_args) {
1098 }
1099
1101
1102 // Parse stage
1103 infix_type * raw_func_type = nullptr;
1104 infix_arena_t * parser_arena = nullptr;
1105 infix_status status = _infix_parse_type_internal(&raw_func_type, &parser_arena, signature);
1106 if (status != INFIX_SUCCESS)
1107 return status;
1108
1109 if (raw_func_type->category != INFIX_TYPE_REVERSE_TRAMPOLINE) {
1110 infix_arena_destroy(parser_arena);
1113 }
1114
1115 // Create final arena
1116 *out_arena = infix_arena_create(8192);
1117 if (!*out_arena) {
1118 infix_arena_destroy(parser_arena);
1121 }
1122
1123 // "Copy" stage
1124 infix_type * final_func_type = _copy_type_graph_to_arena(*out_arena, raw_func_type);
1125 infix_arena_destroy(parser_arena);
1126 if (!final_func_type) {
1127 infix_arena_destroy(*out_arena);
1128 *out_arena = nullptr;
1131 }
1132
1133 // Resolve and layout stages
1135 if (status != INFIX_SUCCESS) {
1136 infix_arena_destroy(*out_arena);
1137 *out_arena = nullptr;
1139 }
1140 _infix_type_recalculate_layout(final_func_type);
1141
1142 // Unpack the results for the caller from the final, processed function type object.
1143 *out_ret_type = final_func_type->meta.func_ptr_info.return_type;
1144 *out_args = final_func_type->meta.func_ptr_info.args;
1145 *out_num_args = final_func_type->meta.func_ptr_info.num_args;
1146 *out_num_fixed_args = final_func_type->meta.func_ptr_info.num_fixed_args;
1147 return INFIX_SUCCESS;
1148}
1149
1150// Type Printing Logic
1156typedef struct {
1157 char * p;
1158 size_t remaining;
1169static void _print(printer_state * state, const char * fmt, ...) {
1170 if (state->status != INFIX_SUCCESS)
1171 return;
1172 va_list args;
1173 va_start(args, fmt);
1174 int written = vsnprintf(state->p, state->remaining, fmt, args);
1175 va_end(args);
1176 if (written < 0 || (size_t)written >= state->remaining)
1177 // If snprintf failed or would have overflowed, mark an error.
1179 else {
1180 state->p += written;
1181 state->remaining -= written;
1182 }
1183}
1184// Forward declaration for mutual recursion in printers.
1185static void _infix_type_print_signature_recursive(printer_state * state, const infix_type * type);
1199 if (state->status != INFIX_SUCCESS || !type) {
1200 if (state->status == INFIX_SUCCESS)
1202 return;
1203 }
1204 // If the type has a semantic name, always prefer printing it.
1205 if (type->name) {
1206 _print(state, "@%s", type->name);
1207 return;
1208 }
1209 switch (type->category) {
1210 case INFIX_TYPE_VOID:
1211 _print(state, "void");
1212 break;
1214 // This case should ideally not be hit with a fully resolved type, but we handle it for robustness.
1215 _print(state, "@%s", type->meta.named_reference.name);
1216 break;
1217 case INFIX_TYPE_POINTER:
1218 _print(state, "*");
1219 // Special handling for `void*` or recursive pointers to avoid infinite recursion.
1220 if (type->meta.pointer_info.pointee_type == type || type->meta.pointer_info.pointee_type == nullptr ||
1222 _print(state, "void");
1223 else
1225 break;
1226 case INFIX_TYPE_ARRAY:
1227 if (type->meta.array_info.is_flexible)
1228 _print(state, "[?:");
1229 else
1230 _print(state, "[%zu:", type->meta.array_info.num_elements);
1232 _print(state, "]");
1233 break;
1234 case INFIX_TYPE_STRUCT:
1235 if (type->meta.aggregate_info.is_packed) {
1236 _print(state, "!");
1237 if (type->alignment != 1)
1238 _print(state, "%zu:", type->alignment);
1239 }
1240 _print(state, "{");
1241 for (size_t i = 0; i < type->meta.aggregate_info.num_members; ++i) {
1242 if (i > 0)
1243 _print(state, ",");
1244 const infix_struct_member * member = &type->meta.aggregate_info.members[i];
1245 if (member->name)
1246 _print(state, "%s:", member->name);
1248 if (member->bit_width > 0)
1249 _print(state, ":%u", member->bit_width);
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 // Bitfields in unions are rare but syntactically valid in C.
1263 if (member->bit_width > 0)
1264 _print(state, ":%u", member->bit_width);
1265 }
1266 _print(state, ">");
1267 break;
1269 _print(state, "(");
1270 for (size_t i = 0; i < type->meta.func_ptr_info.num_fixed_args; ++i) {
1271 if (i > 0)
1272 _print(state, ",");
1273 const infix_function_argument * arg = &type->meta.func_ptr_info.args[i];
1274 if (arg->name)
1275 _print(state, "%s:", arg->name);
1277 }
1279 _print(state, ";");
1280 for (size_t i = type->meta.func_ptr_info.num_fixed_args; i < type->meta.func_ptr_info.num_args; ++i) {
1281 if (i > type->meta.func_ptr_info.num_fixed_args)
1282 _print(state, ",");
1283 const infix_function_argument * arg = &type->meta.func_ptr_info.args[i];
1284 if (arg->name)
1285 _print(state, "%s:", arg->name);
1287 }
1288 }
1289 _print(state, ")->");
1291 break;
1292 case INFIX_TYPE_ENUM:
1293 _print(state, "e:");
1295 break;
1296 case INFIX_TYPE_COMPLEX:
1297 _print(state, "c[");
1299 _print(state, "]");
1300 break;
1301 case INFIX_TYPE_VECTOR:
1302 {
1303 const infix_type * element_type = type->meta.vector_info.element_type;
1304 size_t num_elements = type->meta.vector_info.num_elements;
1305 bool printed_alias = false;
1306 if (element_type->category == INFIX_TYPE_PRIMITIVE) {
1307 if (num_elements == 8 && is_double(element_type)) {
1308 _print(state, "m512d");
1309 printed_alias = true;
1310 }
1311 else if (num_elements == 16 && is_float(element_type)) {
1312 _print(state, "m512");
1313 printed_alias = true;
1314 }
1315 else if (num_elements == 8 && element_type->meta.primitive_id == INFIX_PRIMITIVE_SINT64) {
1316 _print(state, "m512i");
1317 printed_alias = true;
1318 }
1319 else if (num_elements == 4 && is_double(element_type)) {
1320 _print(state, "m256d");
1321 printed_alias = true;
1322 }
1323 else if (num_elements == 8 && is_float(element_type)) {
1324 _print(state, "m256");
1325 printed_alias = true;
1326 }
1327 }
1328 if (!printed_alias) {
1329 _print(state, "v[%zu:", num_elements);
1330 _infix_type_print_signature_recursive(state, element_type);
1331 _print(state, "]");
1332 }
1333 }
1334 break;
1336 switch (type->meta.primitive_id) {
1338 _print(state, "bool");
1339 break;
1341 _print(state, "sint8");
1342 break;
1344 _print(state, "uint8");
1345 break;
1347 _print(state, "sint16");
1348 break;
1350 _print(state, "uint16");
1351 break;
1353 _print(state, "sint32");
1354 break;
1356 _print(state, "uint32");
1357 break;
1359 _print(state, "sint64");
1360 break;
1362 _print(state, "uint64");
1363 break;
1365 _print(state, "sint128");
1366 break;
1368 _print(state, "uint128");
1369 break;
1371 _print(state, "float");
1372 break;
1374 _print(state, "double");
1375 break;
1377 _print(state, "longdouble");
1378 break;
1379 }
1380 break;
1381 default:
1383 break;
1384 }
1385}
1399 if (state->status != INFIX_SUCCESS || !type) {
1400 if (state->status == INFIX_SUCCESS)
1402 return;
1403 }
1404 // This is the key difference from the main printer: we skip the `if (type->name)` check
1405 // and immediately print the underlying structure of the type.
1406 switch (type->category) {
1407 case INFIX_TYPE_STRUCT:
1408 if (type->meta.aggregate_info.is_packed) {
1409 _print(state, "!");
1410 if (type->alignment != 1)
1411 _print(state, "%zu:", type->alignment);
1412 }
1413 _print(state, "{");
1414 for (size_t i = 0; i < type->meta.aggregate_info.num_members; ++i) {
1415 if (i > 0)
1416 _print(state, ",");
1417 const infix_struct_member * member = &type->meta.aggregate_info.members[i];
1418 if (member->name)
1419 _print(state, "%s:", member->name);
1420 // For nested members, we can use the standard printer, which IS allowed
1421 // to use the `@Name` shorthand for brevity.
1423 if (member->bit_width > 0)
1424 _print(state, ":%u", member->bit_width);
1425 }
1426 _print(state, "}");
1427 break;
1428 case INFIX_TYPE_UNION:
1429 _print(state, "<");
1430 for (size_t i = 0; i < type->meta.aggregate_info.num_members; ++i) {
1431 if (i > 0)
1432 _print(state, ",");
1433 const infix_struct_member * member = &type->meta.aggregate_info.members[i];
1434 if (member->name)
1435 _print(state, "%s:", member->name);
1437 if (member->bit_width > 0)
1438 _print(state, ":%u", member->bit_width);
1439 }
1440 _print(state, ">");
1441 break;
1442 // For all other types, we replicate the printing logic from the main printer
1443 // to ensure we print the structure, not a potential top-level alias name.
1444 case INFIX_TYPE_VOID:
1445 _print(state, "void");
1446 break;
1447 case INFIX_TYPE_POINTER:
1448 _print(state, "*");
1449 if (type->meta.pointer_info.pointee_type == type || type->meta.pointer_info.pointee_type == nullptr ||
1451 _print(state, "void");
1452 else
1454 break;
1455 case INFIX_TYPE_ARRAY:
1456 if (type->meta.array_info.is_flexible)
1457 _print(state, "[?:");
1458 else
1459 _print(state, "[%zu:", type->meta.array_info.num_elements);
1461 _print(state, "]");
1462 break;
1463 case INFIX_TYPE_ENUM:
1464 _print(state, "e:");
1466 break;
1467 case INFIX_TYPE_COMPLEX:
1468 _print(state, "c[");
1470 _print(state, "]");
1471 break;
1473 // This block is now a full copy from the main printer.
1474 switch (type->meta.primitive_id) {
1476 _print(state, "bool");
1477 break;
1479 _print(state, "sint8");
1480 break;
1482 _print(state, "uint8");
1483 break;
1485 _print(state, "sint16");
1486 break;
1488 _print(state, "uint16");
1489 break;
1491 _print(state, "sint32");
1492 break;
1494 _print(state, "uint32");
1495 break;
1497 _print(state, "sint64");
1498 break;
1500 _print(state, "uint64");
1501 break;
1503 _print(state, "sint128");
1504 break;
1506 _print(state, "uint128");
1507 break;
1509 _print(state, "float");
1510 break;
1512 _print(state, "double");
1513 break;
1515 _print(state, "longdouble");
1516 break;
1517 }
1518 break;
1519 // We can safely delegate the remaining complex cases to the main printer, as they
1520 // do not have a top-level `name` field themselves.
1523 case INFIX_TYPE_VECTOR:
1525 break;
1526 default:
1528 break;
1529 }
1530}
1536 size_t buffer_size,
1537 const infix_type * type,
1538 infix_print_dialect_t dialect) {
1539 if (!buffer || buffer_size == 0 || !type || dialect != INFIX_DIALECT_SIGNATURE)
1541 printer_state state = {buffer, buffer_size, INFIX_SUCCESS};
1542 *buffer = '\0';
1544 if (state.remaining > 0)
1545 *state.p = '\0';
1546 else
1547 buffer[buffer_size - 1] = '\0';
1548 return state.status;
1549}
1559 size_t buffer_size,
1560 const infix_type * type,
1561 infix_print_dialect_t dialect) {
1563 if (!buffer || buffer_size == 0 || !type) {
1566 }
1567 printer_state state = {buffer, buffer_size, INFIX_SUCCESS};
1568 *buffer = '\0';
1569 if (dialect == INFIX_DIALECT_SIGNATURE)
1571 else {
1572 // Placeholder for future dialects like C++ name mangling.
1573 _print(&state, "unsupported_dialect");
1575 }
1576 if (state.status == INFIX_SUCCESS) {
1577 if (state.remaining > 0)
1578 *state.p = '\0'; // Null-terminate if there is space.
1579 else {
1580 // Buffer was exactly full. Ensure null termination at the very end.
1581 buffer[buffer_size - 1] = '\0';
1582 return INFIX_ERROR_INVALID_ARGUMENT; // Indicate truncation.
1583 }
1584 }
1585 else if (buffer_size > 0)
1586 // Ensure null termination even on error (e.g., buffer too small).
1587 buffer[buffer_size - 1] = '\0';
1588 return state.status;
1589}
1603 size_t buffer_size,
1604 const char * function_name,
1605 const infix_type * ret_type,
1607 size_t num_args,
1608 size_t num_fixed_args,
1609 infix_print_dialect_t dialect) {
1611 if (!buffer || buffer_size == 0 || !ret_type || (num_args > 0 && !args)) {
1614 }
1615 printer_state state = {buffer, buffer_size, INFIX_SUCCESS};
1616 *buffer = '\0';
1617 (void)function_name; // Not used in the standard signature dialect.
1618 if (dialect == INFIX_DIALECT_SIGNATURE) {
1619 _print(&state, "(");
1620 for (size_t i = 0; i < num_fixed_args; ++i) {
1621 if (i > 0)
1622 _print(&state, ",");
1624 }
1625 if (num_args > num_fixed_args) {
1626 _print(&state, ";");
1627 for (size_t i = num_fixed_args; i < num_args; ++i) {
1628 if (i > num_fixed_args)
1629 _print(&state, ",");
1631 }
1632 }
1633 _print(&state, ")->");
1635 }
1636 else {
1637 _print(&state, "unsupported_dialect");
1639 }
1640 if (state.status == INFIX_SUCCESS) {
1641 if (state.remaining > 0)
1642 *state.p = '\0';
1643 else {
1644 if (buffer_size > 0)
1645 buffer[buffer_size - 1] = '\0';
1646 return INFIX_ERROR_INVALID_ARGUMENT; // Indicate truncation.
1647 }
1648 }
1649 else if (buffer_size > 0)
1650 buffer[buffer_size - 1] = '\0';
1651 return state.status;
1652}
1667c23_nodiscard infix_status infix_registry_print(char * buffer, size_t buffer_size, const infix_registry_t * registry) {
1668 if (!buffer || buffer_size == 0 || !registry)
1670 printer_state state = {buffer, buffer_size, INFIX_SUCCESS};
1671 *state.p = '\0';
1672 // Iterate through all buckets and their chains.
1673 for (size_t i = 0; i < registry->num_buckets; ++i) {
1674 for (const _infix_registry_entry_t * entry = registry->buckets[i]; entry != nullptr; entry = entry->next) {
1675 // Only print fully defined types, not forward declarations.
1676 if (entry->type && !entry->is_forward_declaration) {
1677 char type_body_buffer[1024];
1679 type_body_buffer, sizeof(type_body_buffer), entry->type, INFIX_DIALECT_SIGNATURE) !=
1680 INFIX_SUCCESS) {
1682 goto end_print_loop;
1683 }
1684 _print(&state, "@%s = %s;\n", entry->name, type_body_buffer);
1685 }
1686 else if (entry->is_forward_declaration) // Explicitly print forward declarations
1687 _print(&state, "@%s;\n", entry->name);
1688 if (state.status != INFIX_SUCCESS)
1689 goto end_print_loop;
1690 }
1691 }
1692end_print_loop:;
1693 return state.status;
1694}
infix_registry_t * registry
Definition 008_registry_introspection.c:31
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:1225
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:279
@ INFIX_CODE_SUCCESS
Definition infix.h:1227
@ INFIX_CODE_INVALID_MEMBER_TYPE
Definition infix.h:1252
@ INFIX_CODE_TYPE_TOO_LARGE
Definition infix.h:1250
@ INFIX_CODE_EMPTY_SIGNATURE
Definition infix.h:1246
@ INFIX_CODE_UNEXPECTED_TOKEN
Definition infix.h:1239
@ INFIX_CODE_MISSING_RETURN_TYPE
Definition infix.h:1242
@ INFIX_CODE_RECURSION_DEPTH_EXCEEDED
Definition infix.h:1244
@ INFIX_CODE_UNTERMINATED_AGGREGATE
Definition infix.h:1240
@ INFIX_CODE_NULL_POINTER
Definition infix.h:1229
@ INFIX_CODE_INVALID_KEYWORD
Definition infix.h:1241
@ INFIX_CODE_OUT_OF_MEMORY
Definition infix.h:1233
@ INFIX_CATEGORY_ALLOCATION
Definition infix.h:1218
@ INFIX_CATEGORY_GENERAL
Definition infix.h:1217
@ INFIX_CATEGORY_PARSER
Definition infix.h:1219
size_t source_offset
Definition infix.h:202
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:215
struct infix_type_t::@0::@7 vector_info
Metadata for INFIX_TYPE_VECTOR.
infix_type * type
Definition infix.h:268
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:1018
size_t num_elements
Definition infix.h:220
size_t size
Definition infix.h:197
size_t alignment
Definition infix.h:198
infix_struct_member * members
Definition infix.h:213
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:226
infix_status
Enumerates the possible status codes returned by infix API functions.
Definition infix.h:354
const char * name
Definition infix.h:267
const char * name
Definition infix.h:255
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:209
infix_type * type
Definition infix.h:256
struct infix_type_t * element_type
Definition infix.h:219
bool is_flexible
Definition infix.h:221
struct infix_type_t * return_type
Definition infix.h:225
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:1077
struct infix_type_t::@0::@5 enum_info
Metadata for INFIX_TYPE_ENUM.
struct infix_type_t * base_type
Definition infix.h:236
uint8_t bit_width
Definition infix.h:258
size_t num_members
Definition infix.h:214
struct infix_type_t * underlying_type
Definition infix.h:232
struct infix_type_t::@0::@8 named_reference
Metadata for INFIX_TYPE_NAMED_REFERENCE.
size_t num_fixed_args
Definition infix.h:228
infix_primitive_type_id primitive_id
Metadata for INFIX_TYPE_PRIMITIVE.
Definition infix.h:206
size_t num_args
Definition infix.h:227
bool is_arena_allocated
Definition infix.h:199
@ INFIX_ERROR_ALLOCATION_FAILED
Definition infix.h:356
@ INFIX_SUCCESS
Definition infix.h:355
@ INFIX_ERROR_INVALID_ARGUMENT
Definition infix.h:357
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:1558
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:1602
infix_print_dialect_t
Specifies the output format for printing types and function signatures.
Definition infix.h:1040
@ INFIX_DIALECT_SIGNATURE
Definition infix.h:1041
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:307
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:1667
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:747
infix_status infix_type_create_flexible_array(infix_arena_t *, infix_type **, infix_type *)
Creates a flexible array member type ([?:type]).
Definition types.c:496
c23_nodiscard infix_type * infix_type_create_void(void)
Creates a static descriptor for the void type.
Definition types.c:186
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:641
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:539
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:603
c23_nodiscard infix_status infix_type_create_complex(infix_arena_t *, infix_type **, infix_type *)
Creates a new _Complex number type.
Definition types.c:573
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:458
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:428
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:205
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:688
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:799
c23_nodiscard infix_type * infix_type_create_primitive(infix_primitive_type_id)
Creates a static descriptor for a primitive C type.
Definition types.c:133
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:194
@ 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:173
void _infix_type_recalculate_layout(infix_type *type)
Recalculates the layout of a fully resolved type graph.
Definition types.c:945
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:1133
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:266
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:1169
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: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:1535
#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:968
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:810
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:1198
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:266
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:254
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:1156
char * p
Definition signature.c:1157
size_t remaining
Definition signature.c:1158
infix_status status
Definition signature.c:1159