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
49 infix_type ** out_ret_type,
50 infix_function_argument ** out_args,
51 size_t * out_num_args,
52 size_t * out_num_fixed_args);
53// Parser Helper Functions
64
71 while (true) {
72 while (isspace((unsigned char)*state->p))
73 state->p++;
74 if (*state->p == '#') // C-style line comments
75 while (*state->p != '\n' && *state->p != '\0')
76 state->p++;
77 else
78 break;
79 }
80}
88static bool parse_size_t(parser_state * state, size_t * out_val) {
89 const char * start = state->p;
90 char * end;
91 errno = 0; // Reset errno before call
92 unsigned long long val = strtoull(start, &end, 10);
93
94 // Check for no conversion (end==start) OR overflow (ERANGE)
95 if (end == start || errno == ERANGE) {
96 // Use INTEGER_OVERFLOW code for range errors
98 return false;
99 }
100
101 // Check for truncation if size_t is smaller than unsigned long long (e.g. 32-bit builds)
102 if (val > SIZE_MAX) {
104 return false;
105 }
106 *out_val = (size_t)val;
107 state->p = end;
108 return true;
109}
118static const char * parse_identifier(parser_state * state) {
119 skip_whitespace(state);
120 const char * start = state->p;
121 if (!isalpha((unsigned char)*start) && *start != '_')
122 return nullptr;
123 while (isalnum((unsigned char)*state->p) || *state->p == '_' || *state->p == ':') {
124 if (*state->p == ':' && state->p[1] != ':')
125 break; // A single ':' is not part of an identifier.
126 if (*state->p == ':')
127 state->p++; // Consume first ':' of '::'
128 state->p++;
129 }
130 size_t len = state->p - start;
131 if (len == 0)
132 return nullptr;
133 char * name = infix_arena_calloc(state->arena, 1, len + 1, 1);
134 if (!name) {
136 return nullptr;
137 }
138 infix_memcpy((void *)name, start, len);
139 name[len] = '\0';
140 return name;
141}
152static bool consume_keyword(parser_state * state, const char * keyword) {
153 skip_whitespace(state);
154 size_t len = strlen(keyword);
155 if (strncmp(state->p, keyword, len) == 0) {
156 // Ensure it's not a prefix of a longer word (e.g., "int" vs "integer").
157 if (isalnum((unsigned char)state->p[len]) || state->p[len] == '_')
158 return false;
159 state->p += len;
160 skip_whitespace(state);
161 return true;
162 }
163 return false;
164}
174static const char * parse_optional_name_prefix(parser_state * state) {
175 skip_whitespace(state);
176 // Save the current position in case we need to backtrack.
177 const char * p_before = state->p;
178 const char * name = parse_identifier(state);
179 if (name) {
180 skip_whitespace(state);
181 if (*state->p == ':') { // Found "identifier:", so consume the colon and return the name.
182 state->p++;
183 return name;
184 }
185 }
186 // If it wasn't a `name:`, backtrack to the original position.
187 state->p = p_before;
188 return nullptr;
189}
204static bool is_function_signature_ahead(const parser_state * state) {
205 const char * p = state->p;
206 if (*p != '(')
207 return false;
208 p++;
209 // Find the matching ')' by tracking nesting depth.
210 int depth = 1;
211 while (*p != '\0' && depth > 0) {
212 if (*p == '(')
213 depth++;
214 else if (*p == ')')
215 depth--;
216 p++;
217 }
218 if (depth != 0)
219 return false; // Mismatched parentheses.
220 // Skip any whitespace or comments after the ')'
221 while (isspace((unsigned char)*p) || *p == '#') {
222 if (*p == '#')
223 while (*p != '\n' && *p != '\0')
224 p++;
225 else
226 p++;
227 }
228 // Check for the '->' arrow.
229 return (p[0] == '-' && p[1] == '>');
230}
231// Aggregate Parsing Logic
243static infix_struct_member * parse_aggregate_members(parser_state * state, char end_char, size_t * out_num_members) {
244 // Use a temporary linked list to collect members, as the count is unknown in a single pass.
245 typedef struct member_node {
247 struct member_node * next;
248 } member_node;
249 member_node *head = nullptr, *tail = nullptr;
250 size_t num_members = 0;
251 skip_whitespace(state);
252 if (*state->p != end_char) {
253 while (1) {
254 const char * p_before_member = state->p;
255 const char * name = parse_optional_name_prefix(state);
256 // Disallow an empty member definition like `name,` without a type.
257 if (name && (*state->p == ',' || *state->p == end_char)) {
258 state->p = p_before_member + strlen(name); // Position error at end of name
260 return nullptr;
261 }
262 infix_type * member_type = parse_type(state);
263 if (!member_type)
264 return nullptr;
265 // Structs and unions cannot have `void` members.
266 if (member_type->category == INFIX_TYPE_VOID) {
268 return nullptr;
269 }
270
271 // Check for bitfield syntax: "name: type : width"
272 uint8_t bit_width = 0;
273 bool is_bitfield = false;
274 const char * p_before_colon = state->p;
275 skip_whitespace(state);
276 if (*state->p == ':') {
277 state->p++; // Consume ':'
278 skip_whitespace(state);
279 if (!isdigit((unsigned char)*state->p)) {
280 // Not a bitfield width, backtrack. This handles "name: type" where ':' is part of name prefix.
281 state->p = p_before_colon;
282 }
283 else {
284 size_t width_val = 0;
285 if (!parse_size_t(state, &width_val))
286 return nullptr; // Error set by parse_size_t
287 if (width_val > 255) {
289 return nullptr;
290 }
291 bit_width = (uint8_t)width_val;
292 is_bitfield = true;
293 }
294 }
295
296 member_node * node = infix_arena_calloc(state->arena, 1, sizeof(member_node), _Alignof(member_node));
297 if (!node) {
299 INFIX_CATEGORY_ALLOCATION, INFIX_CODE_OUT_OF_MEMORY, (size_t)(state->p - state->start));
300 return nullptr;
301 }
302 // The member offset is not calculated here; it will be done later
303 // by `infix_type_create_struct` or `_infix_type_recalculate_layout`.
304 if (is_bitfield)
305 node->m = infix_type_create_bitfield_member(name, member_type, 0, bit_width);
306 else
307 node->m = infix_type_create_member(name, member_type, 0);
308
309 node->next = nullptr;
310
311 if (!head)
312 head = tail = node;
313 else {
314 tail->next = node;
315 tail = node;
316 }
317 num_members++;
318 // Check for next token: ',' or end_char
319 skip_whitespace(state);
320 if (*state->p == ',') {
321 state->p++; // Consume comma.
322 skip_whitespace(state);
323 // A trailing comma like `{int,}` is a syntax error.
324 if (*state->p == end_char) {
326 return nullptr;
327 }
328 }
329 else if (*state->p == end_char)
330 break;
331 else { // Unexpected token (e.g., missing comma).
332 if (*state->p == '\0') {
334 return nullptr;
335 }
337 return nullptr;
338 }
339 }
340 }
341 *out_num_members = num_members;
342 if (num_members == 0)
343 return nullptr;
344 // Convert the temporary linked list to a flat array in the arena.
346 infix_arena_calloc(state->arena, num_members, sizeof(infix_struct_member), _Alignof(infix_struct_member));
347 if (!members) {
349 return nullptr;
350 }
351 member_node * current = head;
352 for (size_t i = 0; i < num_members; i++) {
353 members[i] = current->m;
354 current = current->next;
355 }
356 return members;
357}
366static infix_type * parse_aggregate(parser_state * state, char start_char, char end_char) {
367 if (state->depth >= MAX_RECURSION_DEPTH) {
369 return nullptr;
370 }
371 state->depth++;
372 if (*state->p != start_char) {
374 state->depth--;
375 return nullptr;
376 }
377 state->p++;
378 size_t num_members = 0;
379 infix_struct_member * members = parse_aggregate_members(state, end_char, &num_members);
380 // If member parsing failed, an error is already set. Propagate the failure.
382 state->depth--;
383 return nullptr;
384 }
385 if (*state->p != end_char) {
387 state->depth--;
388 return nullptr;
389 }
390 state->p++;
391 infix_type * agg_type = nullptr;
392 infix_status status = (start_char == '{') ? infix_type_create_struct(state->arena, &agg_type, members, num_members)
393 : infix_type_create_union(state->arena, &agg_type, members, num_members);
394 if (status != INFIX_SUCCESS) {
395 state->depth--;
396 return nullptr;
397 }
398 state->depth--;
399 return agg_type;
400}
408 size_t alignment = 1; // Default alignment for `!{...}` is 1.
409 if (*state->p == '!') {
410 state->p++;
411 if (isdigit((unsigned char)*state->p)) {
412 // This is the `!N:{...}` form with an explicit alignment.
413 if (!parse_size_t(state, &alignment))
414 return nullptr;
415 if (*state->p != ':') {
417 return nullptr;
418 }
419 state->p++;
420 }
421 }
422 skip_whitespace(state);
423 if (*state->p != '{') {
425 return nullptr;
426 }
427 state->p++;
428 size_t num_members = 0;
429 infix_struct_member * members = parse_aggregate_members(state, '}', &num_members);
431 return nullptr;
432 if (*state->p != '}') {
434 return nullptr;
435 }
436 state->p++;
437 infix_type * packed_type = nullptr;
438 // For packed structs, the total size is simply the sum of member sizes without padding.
439 // The user of `infix_type_create_packed_struct` must provide pre-calculated offsets.
440 // Since our parser doesn't know the offsets, we pass a preliminary size. The final
441 // layout pass will fix this if needed, but for packed structs, the user's offsets
442 // are king.
443 size_t total_size = 0;
444 for (size_t i = 0; i < num_members; ++i)
445 total_size += members[i].type->size;
447 infix_type_create_packed_struct(state->arena, &packed_type, total_size, alignment, members, num_members);
448 if (status != INFIX_SUCCESS)
449 return nullptr;
450 return packed_type;
451}
460 infix_type * t = infix_arena_calloc(state->arena, 1, sizeof(infix_type), _Alignof(infix_type));
461 if (!t)
462 return nullptr;
463
465 t->is_arena_allocated = true;
466 t->arena = state->arena;
467
468 size_t len = strlen(name) + 1;
469 char * arena_name = infix_arena_alloc(state->arena, len, 1);
470 if (arena_name) {
471 infix_memcpy(arena_name, name, len);
472 t->name = arena_name;
473 }
474 return t;
475}
476// Main Parser Logic
488 if (consume_keyword(state, "sint8") || consume_keyword(state, "int8"))
490 if (consume_keyword(state, "uint8"))
492 if (consume_keyword(state, "sint16") || consume_keyword(state, "int16"))
494 if (consume_keyword(state, "uint16"))
496 if (consume_keyword(state, "sint32") || consume_keyword(state, "int32"))
498 if (consume_keyword(state, "uint32"))
500 if (consume_keyword(state, "sint64") || consume_keyword(state, "int64"))
502 if (consume_keyword(state, "uint64"))
504 if (consume_keyword(state, "sint128") || consume_keyword(state, "int128"))
506 if (consume_keyword(state, "uint128"))
508 if (consume_keyword(state, "float16"))
510 if (consume_keyword(state, "float32"))
512 if (consume_keyword(state, "float64"))
514 if (consume_keyword(state, "bool"))
516 if (consume_keyword(state, "void"))
517 return infix_type_create_void();
518 // C-style convenience aliases
519 if (consume_keyword(state, "uchar"))
521 if (consume_keyword(state, "char"))
523 if (consume_keyword(state, "ushort"))
525 if (consume_keyword(state, "short"))
527 if (consume_keyword(state, "uint"))
529 if (consume_keyword(state, "int"))
531 if (consume_keyword(state, "ulonglong"))
533 if (consume_keyword(state, "longlong"))
535 // `long` is platform-dependent, so we use `sizeof` to pick the correct size.
536 if (consume_keyword(state, "ulong"))
537 return infix_type_create_primitive(sizeof(unsigned long) == 8 ? INFIX_PRIMITIVE_UINT64
539 if (consume_keyword(state, "long"))
541 if (consume_keyword(state, "double"))
543 if (consume_keyword(state, "float"))
545 if (consume_keyword(state, "longdouble"))
547 if (consume_keyword(state, "size_t"))
549 if (consume_keyword(state, "ssize_t"))
551 // Explicit Character Types
552 if (consume_keyword(state, "char8_t"))
553 return _create_named_primitive(state, INFIX_PRIMITIVE_UINT8, "char8_t");
554 if (consume_keyword(state, "char16_t"))
555 return _create_named_primitive(state, INFIX_PRIMITIVE_UINT16, "char16_t");
556 if (consume_keyword(state, "char32_t"))
557 return _create_named_primitive(state, INFIX_PRIMITIVE_UINT32, "char32_t");
558 if (consume_keyword(state, "wchar_t"))
560 state, sizeof(wchar_t) == 2 ? INFIX_PRIMITIVE_UINT16 : INFIX_PRIMITIVE_SINT32, "wchar_t");
561 // AVX convenience aliases
562 if (consume_keyword(state, "m256d")) {
563 infix_type * type = nullptr;
566 if (status != INFIX_SUCCESS)
567 return nullptr; // Propagate failure
568 type->alignment = 32; // YMM registers require 32-byte alignment
569 return type;
570 }
571 if (consume_keyword(state, "m256")) {
572 infix_type * type = nullptr;
575 if (status != INFIX_SUCCESS)
576 return nullptr; // Propagate failure
577 type->alignment = 32; // YMM registers require 32-byte alignment
578 return type;
579 }
580 if (consume_keyword(state, "m512d")) {
581 infix_type * type = nullptr;
584 if (status != INFIX_SUCCESS)
585 return nullptr;
586 type->alignment = 64; // ZMM registers have 64-byte alignment
587 return type;
588 }
589 if (consume_keyword(state, "m512")) {
590 infix_type * type = nullptr;
593 if (status != INFIX_SUCCESS)
594 return nullptr;
595 type->alignment = 64;
596 return type;
597 }
598 if (consume_keyword(state, "m512i")) {
599 infix_type * type = nullptr;
602 if (status != INFIX_SUCCESS)
603 return nullptr;
604 type->alignment = 64;
605 return type;
606 }
607 return nullptr;
608}
620 if (state->depth >= MAX_RECURSION_DEPTH) {
622 return nullptr;
623 }
624 state->depth++;
625 skip_whitespace(state);
626 // Capture the offset from the start of the signature string *before* parsing the type.
627 size_t current_offset = state->p - state->start;
628 infix_type * result_type = nullptr;
629 const char * p_before_type = state->p;
630 if (*state->p == '@') { // Named type reference: `@MyStruct`
631 state->p++;
632 const char * name = parse_identifier(state);
633 if (!name) {
635 state->depth--;
636 return nullptr;
637 }
638 if (infix_type_create_named_reference(state->arena, &result_type, name, INFIX_AGGREGATE_STRUCT) !=
640 result_type = nullptr;
641 }
642 else if (*state->p == '*') { // Pointer type: `*int`
643 state->p++;
644 skip_whitespace(state);
645 infix_type * pointee_type = parse_type(state);
646 if (!pointee_type) {
647 state->depth--;
648 return nullptr;
649 }
650 if (infix_type_create_pointer_to(state->arena, &result_type, pointee_type) != INFIX_SUCCESS)
651 result_type = nullptr;
652 }
653 else if (*state->p == '(') { // Grouped type `(type)` or function pointer `(...) -> type`
654 if (is_function_signature_ahead(state)) {
655 infix_type * ret_type = nullptr;
656 infix_function_argument * args = nullptr;
657 size_t num_args = 0, num_fixed = 0;
658 if (parse_function_signature_details(state, &ret_type, &args, &num_args, &num_fixed) != INFIX_SUCCESS) {
659 state->depth--;
660 return nullptr;
661 }
662 // Manually construct a function pointer type object.
663 // This is represented internally as a pointer-like type with extra metadata.
664 infix_type * func_type = infix_arena_calloc(state->arena, 1, sizeof(infix_type), _Alignof(infix_type));
665 if (!func_type) {
667 INFIX_CATEGORY_ALLOCATION, INFIX_CODE_OUT_OF_MEMORY, (size_t)(state->p - state->start));
668 state->depth--;
669 return nullptr;
670 }
671 func_type->size = sizeof(void *);
672 func_type->alignment = _Alignof(void *);
673 func_type->is_arena_allocated = true;
674 func_type->category = INFIX_TYPE_REVERSE_TRAMPOLINE; // Special category for function types.
676 func_type->meta.func_ptr_info.args = args;
677 func_type->meta.func_ptr_info.num_args = num_args;
678 func_type->meta.func_ptr_info.num_fixed_args = num_fixed;
679 result_type = func_type;
680 }
681 else { // Grouped type: `(type)`
682 state->p++;
683 skip_whitespace(state);
684 result_type = parse_type(state);
685 if (!result_type) {
686 state->depth--;
687 return nullptr;
688 }
689 skip_whitespace(state);
690 if (*state->p != ')') {
692 result_type = nullptr;
693 }
694 else
695 state->p++;
696 }
697 }
698 else if (*state->p == '[') { // Array type: `[size:type]`
699 state->p++;
700 skip_whitespace(state);
701 size_t num_elements = 0;
702 bool is_flexible = false;
703
704 if (*state->p == '?') {
705 // Flexible array member: `[?:type]`
706 is_flexible = true;
707 state->p++;
708 }
709 else if (!parse_size_t(state, &num_elements)) {
710 state->depth--;
711 return nullptr;
712 }
713
714 skip_whitespace(state);
715 if (*state->p != ':') {
717 state->depth--;
718 return nullptr;
719 }
720 state->p++;
721 skip_whitespace(state);
722 infix_type * element_type = parse_type(state);
723 if (!element_type) {
724 state->depth--;
725 return nullptr;
726 }
727 if (element_type->category == INFIX_TYPE_VOID) { // An array of `void` is illegal in C.
729 state->depth--;
730 return nullptr;
731 }
732 skip_whitespace(state);
733 if (*state->p != ']') {
735 state->depth--;
736 return nullptr;
737 }
738 state->p++;
739
740 if (is_flexible) {
741 if (infix_type_create_flexible_array(state->arena, &result_type, element_type) != INFIX_SUCCESS)
742 result_type = nullptr;
743 }
744 else {
745 if (infix_type_create_array(state->arena, &result_type, element_type, num_elements) != INFIX_SUCCESS)
746 result_type = nullptr;
747 }
748 }
749 else if (*state->p == '!') // Packed struct
750 result_type = parse_packed_struct(state);
751 else if (*state->p == '{') // Struct
752 result_type = parse_aggregate(state, '{', '}');
753 else if (*state->p == '<') // Union
754 result_type = parse_aggregate(state, '<', '>');
755 else if (*state->p == 'e' && state->p[1] == ':') { // Enum: `e:type`
756 state->p += 2;
757 skip_whitespace(state);
758 infix_type * underlying_type = parse_type(state);
759 if (!underlying_type || underlying_type->category != INFIX_TYPE_PRIMITIVE) {
761 state->depth--;
762 return nullptr;
763 }
764 if (infix_type_create_enum(state->arena, &result_type, underlying_type) != INFIX_SUCCESS)
765 result_type = nullptr;
766 }
767 else if (*state->p == 'c' && state->p[1] == '[') { // Complex: `c[type]`
768 state->p += 2;
769 skip_whitespace(state);
770 infix_type * base_type = parse_type(state);
771 if (!base_type) {
772 state->depth--;
773 return nullptr;
774 }
775 skip_whitespace(state);
776 if (*state->p != ']') {
778 state->depth--;
779 return nullptr;
780 }
781 state->p++;
782 if (infix_type_create_complex(state->arena, &result_type, base_type) != INFIX_SUCCESS)
783 result_type = nullptr;
784 }
785 else if (*state->p == 'v' && state->p[1] == '[') { // Vector: `v[size:type]`
786 state->p += 2;
787 skip_whitespace(state);
788 size_t num_elements;
789 if (!parse_size_t(state, &num_elements)) {
790 state->depth--;
791 return nullptr;
792 }
793 if (*state->p != ':') {
795 state->depth--;
796 return nullptr;
797 }
798 state->p++;
799 infix_type * element_type = parse_type(state);
800 if (!element_type) {
801 state->depth--;
802 return nullptr;
803 }
804 if (*state->p != ']') {
806 state->depth--;
807 return nullptr;
808 }
809 state->p++;
810 if (infix_type_create_vector(state->arena, &result_type, element_type, num_elements) != INFIX_SUCCESS)
811 result_type = nullptr;
812 }
813 else { // Primitive type or error
814 result_type = parse_primitive(state);
815 if (!result_type) {
816 // If no error was set by a failed `consume_keyword`, set a generic one.
818 state->p = p_before_type;
819 if (isalpha((unsigned char)*state->p) || *state->p == '_')
821 else
823 }
824 }
825 }
826 // Only set source offset for dynamically allocated types (primitives are static singletons).
827 if (result_type && result_type->is_arena_allocated)
828 result_type->source_offset = current_offset;
829 state->depth--;
830 return result_type;
831}
846 infix_type ** out_ret_type,
847 infix_function_argument ** out_args,
848 size_t * out_num_args,
849 size_t * out_num_fixed_args) {
850 if (*state->p != '(') {
853 }
854 state->p++;
855 skip_whitespace(state);
856 // Use a temporary linked list to collect arguments.
857 typedef struct arg_node {
859 struct arg_node * next;
860 } arg_node;
861 arg_node *head = nullptr, *tail = nullptr;
862 size_t num_args = 0;
863 // Parse Fixed Arguments
864 if (*state->p != ')' && *state->p != ';') {
865 while (1) {
866 skip_whitespace(state);
867 if (*state->p == ')' || *state->p == ';')
868 break;
869 const char * name = parse_optional_name_prefix(state);
870 infix_type * arg_type = parse_type(state);
871 if (!arg_type)
873 arg_node * node = infix_arena_calloc(state->arena, 1, sizeof(arg_node), _Alignof(arg_node));
874 if (!node) {
876 INFIX_CATEGORY_ALLOCATION, INFIX_CODE_OUT_OF_MEMORY, (size_t)(state->p - state->start));
878 }
879 node->arg.type = arg_type;
880 node->arg.name = name;
881 node->next = nullptr;
882 if (!head)
883 head = tail = node;
884 else {
885 tail->next = node;
886 tail = node;
887 }
888 num_args++;
889 skip_whitespace(state);
890 if (*state->p == ',') {
891 state->p++;
892 skip_whitespace(state);
893 if (*state->p == ')' || *state->p == ';') { // Trailing comma error.
896 }
897 }
898 else if (*state->p != ')' && *state->p != ';') {
901 }
902 else
903 break;
904 }
905 }
906 *out_num_fixed_args = num_args;
907 // Parse Variadic Arguments
908 if (*state->p == ';') {
909 state->p++;
910 if (*state->p != ')') {
911 while (1) {
912 skip_whitespace(state);
913 if (*state->p == ')')
914 break;
915 const char * name = parse_optional_name_prefix(state);
916 infix_type * arg_type = parse_type(state);
917 if (!arg_type)
919 arg_node * node = infix_arena_calloc(state->arena, 1, sizeof(arg_node), _Alignof(arg_node));
920 if (!node) {
922 INFIX_CATEGORY_ALLOCATION, INFIX_CODE_OUT_OF_MEMORY, (size_t)(state->p - state->start));
924 }
925 node->arg.type = arg_type;
926 node->arg.name = name;
927 node->next = nullptr;
928 if (!head)
929 head = tail = node;
930 else {
931 tail->next = node;
932 tail = node;
933 }
934 num_args++;
935 skip_whitespace(state);
936 if (*state->p == ',') {
937 state->p++;
938 skip_whitespace(state);
939 if (*state->p == ')') { // Trailing comma error.
942 }
943 }
944 else if (*state->p != ')') {
947 }
948 else
949 break;
950 }
951 }
952 }
953 skip_whitespace(state);
954 if (*state->p != ')') {
957 }
958 state->p++;
959 // Parse Return Type
960 skip_whitespace(state);
961 if (state->p[0] != '-' || state->p[1] != '>') {
964 }
965 state->p += 2;
966 *out_ret_type = parse_type(state);
967 if (!*out_ret_type)
969 // Convert linked list of args to a flat array.
970 infix_function_argument * args = (num_args > 0)
971 ? infix_arena_calloc(state->arena, num_args, sizeof(infix_function_argument), _Alignof(infix_function_argument))
972 : nullptr;
973 if (num_args > 0 && !args) {
976 }
977 arg_node * current = head;
978 for (size_t i = 0; i < num_args; i++) {
979 args[i] = current->arg;
980 current = current->next;
981 }
982 *out_args = args;
983 *out_num_args = num_args;
984 return INFIX_SUCCESS;
985}
986// High-Level API Implementation
1004 infix_arena_t ** out_arena,
1005 const char * signature) {
1006 if (!out_type || !out_arena) {
1009 }
1010 if (!signature || *signature == '\0') {
1013 }
1014 // The top-level public API is responsible for setting g_infix_last_signature_context.
1015 *out_arena = infix_arena_create(4096);
1016 if (!*out_arena) {
1019 }
1020 parser_state state = {.p = signature, .start = signature, .arena = *out_arena, .depth = 0};
1021 infix_type * type = parse_type(&state);
1022 if (type) {
1023 skip_whitespace(&state);
1024 // After successfully parsing a type, ensure there is no trailing junk.
1025 if (state.p[0] != '\0') {
1027 type = nullptr;
1028 }
1029 }
1030 if (!type) {
1031 // If parsing failed at any point, clean up the temporary arena.
1032 infix_arena_destroy(*out_arena);
1033 *out_arena = nullptr;
1034 *out_type = nullptr;
1036 }
1037 *out_type = type;
1038 return INFIX_SUCCESS;
1039}
1054 infix_arena_t ** out_arena,
1055 const char * signature,
1058 g_infix_last_signature_context = signature; // Set context for rich error reporting.
1059 // "Parse" stage: Create a raw, unresolved type graph in a temporary arena.
1060 infix_type * raw_type = nullptr;
1061 infix_arena_t * parser_arena = nullptr;
1062 infix_status status = _infix_parse_type_internal(&raw_type, &parser_arena, signature);
1063 if (status != INFIX_SUCCESS)
1064 return status;
1065 // Create the final arena that will be returned to the caller.
1066 *out_arena = infix_arena_create(4096);
1067 if (!*out_arena) {
1068 infix_arena_destroy(parser_arena);
1071 }
1072 // "Copy" stage: Deep copy the raw graph into the final arena.
1073 infix_type * final_type = _copy_type_graph_to_arena(*out_arena, raw_type);
1074 infix_arena_destroy(parser_arena); // The temporary graph is no longer needed.
1075 if (!final_type) {
1076 infix_arena_destroy(*out_arena);
1077 *out_arena = nullptr;
1080 }
1081 // "Resolve" stage: Replace all named references (`@Name`) with concrete types.
1083 if (status != INFIX_SUCCESS) {
1084 infix_arena_destroy(*out_arena);
1085 *out_arena = nullptr;
1086 *out_type = nullptr;
1087 }
1088 else {
1089 // "Layout" stage: Calculate the final size, alignment, and member offsets.
1091 *out_type = final_type;
1092 }
1093 return status;
1094}
1113 infix_arena_t ** out_arena,
1114 infix_type ** out_ret_type,
1115 infix_function_argument ** out_args,
1116 size_t * out_num_args,
1117 size_t * out_num_fixed_args,
1120
1121 //
1122 if (!signature) {
1125 }
1126 if (*signature == '\0') {
1129 }
1130 if (!out_arena || !out_ret_type || !out_args || !out_num_args || !out_num_fixed_args) {
1133 }
1134
1136
1137 // Parse stage
1138 infix_type * raw_func_type = nullptr;
1139 infix_arena_t * parser_arena = nullptr;
1140 infix_status status = _infix_parse_type_internal(&raw_func_type, &parser_arena, signature);
1141 if (status != INFIX_SUCCESS)
1142 return status;
1143
1144 if (raw_func_type->category != INFIX_TYPE_REVERSE_TRAMPOLINE) {
1145 infix_arena_destroy(parser_arena);
1148 }
1149
1150 // Create final arena
1151 *out_arena = infix_arena_create(8192);
1152 if (!*out_arena) {
1153 infix_arena_destroy(parser_arena);
1156 }
1157
1158 // "Copy" stage
1159 infix_type * final_func_type = _copy_type_graph_to_arena(*out_arena, raw_func_type);
1160 infix_arena_destroy(parser_arena);
1161 if (!final_func_type) {
1162 infix_arena_destroy(*out_arena);
1163 *out_arena = nullptr;
1166 }
1167
1168 // Resolve and layout stages
1170 if (status != INFIX_SUCCESS) {
1171 infix_arena_destroy(*out_arena);
1172 *out_arena = nullptr;
1174 }
1175 _infix_type_recalculate_layout(final_func_type);
1176
1177 // Unpack the results for the caller from the final, processed function type object.
1178 *out_ret_type = final_func_type->meta.func_ptr_info.return_type;
1179 *out_args = final_func_type->meta.func_ptr_info.args;
1180 *out_num_args = final_func_type->meta.func_ptr_info.num_args;
1181 *out_num_fixed_args = final_func_type->meta.func_ptr_info.num_fixed_args;
1182 return INFIX_SUCCESS;
1183}
1184
1185// Type Printing Logic
1191typedef struct {
1192 char * p;
1193 size_t remaining;
1195 // Itanium mangling state
1196 const void * itanium_subs[64];
1198 // MSVC mangling state
1199 const infix_type * msvc_types[10];
1210static void _print(printer_state * state, const char * fmt, ...) {
1211 if (state->status != INFIX_SUCCESS)
1212 return;
1213 va_list args;
1214 va_start(args, fmt);
1215 int written = vsnprintf(state->p, state->remaining, fmt, args);
1216 va_end(args);
1217 if (written < 0 || (size_t)written >= state->remaining)
1218 // If snprintf failed or would have overflowed, mark an error.
1220 else {
1221 state->p += written;
1222 state->remaining -= written;
1223 }
1224}
1225// Forward declaration for mutual recursion in printers.
1226static void _infix_type_print_signature_recursive(printer_state * state, const infix_type * type);
1227static void _infix_type_print_itanium_recursive(printer_state * state, const infix_type * type);
1228static void _infix_type_print_msvc_recursive(printer_state * state, const infix_type * type);
1229
1230// Itanium Mangling Helpers
1231static bool _find_itanium_sub(printer_state * state, const void * component, size_t * index) {
1232 for (size_t i = 0; i < state->itanium_sub_count; i++) {
1233 if (state->itanium_subs[i] == component) {
1234 *index = i;
1235 return true;
1236 }
1237 }
1238 return false;
1239}
1240
1241static void _add_itanium_sub(printer_state * state, const void * component) {
1242 if (state->itanium_sub_count < 64)
1243 state->itanium_subs[state->itanium_sub_count++] = component;
1244}
1245
1246static void _print_itanium_sub(printer_state * state, size_t index) {
1247 if (index == 0) {
1248 _print(state, "S_");
1249 }
1250 else {
1251 index--; // S0_ is index 1
1252 _print(state, "S");
1253 if (index == 0) {
1254 _print(state, "0");
1255 }
1256 else {
1257 char buf[16];
1258 int pos = 0;
1259 size_t val = index;
1260 while (val > 0) {
1261 int digit = val % 36;
1262 buf[pos++] = (digit < 10) ? (char)('0' + digit) : (char)('A' + digit - 10);
1263 val /= 36;
1264 }
1265 while (pos > 0)
1266 _print(state, "%c", buf[--pos]);
1267 }
1268 _print(state, "_");
1269 }
1270}
1271
1285 if (state->status != INFIX_SUCCESS || !type) {
1286 if (state->status == INFIX_SUCCESS)
1288 return;
1289 }
1290 // If the type has a semantic name, always prefer printing it.
1291 if (type->name) {
1292 // Only prepend '@' if it is an aggregate or named reference.
1293 // Primitives like WChar or aliases like size_t should not get '@'.
1294 if (type->category == INFIX_TYPE_PRIMITIVE || type->category == INFIX_TYPE_VOID)
1295 _print(state, "%s", type->name);
1296 else
1297 _print(state, "@%s", type->name);
1298 return;
1299 }
1300 switch (type->category) {
1301 case INFIX_TYPE_VOID:
1302 _print(state, "void");
1303 break;
1305 // This case should ideally not be hit with a fully resolved type, but we handle it for robustness.
1306 _print(state, "@%s", type->meta.named_reference.name);
1307 break;
1308 case INFIX_TYPE_POINTER:
1309 _print(state, "*");
1310 // Special handling for `void*` or recursive pointers to avoid infinite recursion.
1311 if (type->meta.pointer_info.pointee_type == type || type->meta.pointer_info.pointee_type == nullptr ||
1313 _print(state, "void");
1314 else
1316 break;
1317 case INFIX_TYPE_ARRAY:
1318 if (type->meta.array_info.is_flexible)
1319 _print(state, "[?:");
1320 else
1321 _print(state, "[%zu:", type->meta.array_info.num_elements);
1323 _print(state, "]");
1324 break;
1325 case INFIX_TYPE_STRUCT:
1326 if (type->meta.aggregate_info.is_packed) {
1327 _print(state, "!");
1328 if (type->alignment != 1)
1329 _print(state, "%zu:", type->alignment);
1330 }
1331 _print(state, "{");
1332 for (size_t i = 0; i < type->meta.aggregate_info.num_members; ++i) {
1333 if (i > 0)
1334 _print(state, ",");
1335 const infix_struct_member * member = &type->meta.aggregate_info.members[i];
1336 if (member->name)
1337 _print(state, "%s:", member->name);
1339 if (member->bit_width > 0)
1340 _print(state, ":%u", member->bit_width);
1341 }
1342 _print(state, "}");
1343 break;
1344 case INFIX_TYPE_UNION:
1345 _print(state, "<");
1346 for (size_t i = 0; i < type->meta.aggregate_info.num_members; ++i) {
1347 if (i > 0)
1348 _print(state, ",");
1349 const infix_struct_member * member = &type->meta.aggregate_info.members[i];
1350 if (member->name)
1351 _print(state, "%s:", member->name);
1353 // Bitfields in unions are rare but syntactically valid in C.
1354 if (member->bit_width > 0)
1355 _print(state, ":%u", member->bit_width);
1356 }
1357 _print(state, ">");
1358 break;
1360 _print(state, "(");
1361 for (size_t i = 0; i < type->meta.func_ptr_info.num_fixed_args; ++i) {
1362 if (i > 0)
1363 _print(state, ",");
1364 const infix_function_argument * arg = &type->meta.func_ptr_info.args[i];
1365 if (arg->name)
1366 _print(state, "%s:", arg->name);
1368 }
1370 _print(state, ";");
1371 for (size_t i = type->meta.func_ptr_info.num_fixed_args; i < type->meta.func_ptr_info.num_args; ++i) {
1372 if (i > type->meta.func_ptr_info.num_fixed_args)
1373 _print(state, ",");
1374 const infix_function_argument * arg = &type->meta.func_ptr_info.args[i];
1375 if (arg->name)
1376 _print(state, "%s:", arg->name);
1378 }
1379 }
1380 _print(state, ")->");
1382 break;
1383 case INFIX_TYPE_ENUM:
1384 _print(state, "e:");
1386 break;
1387 case INFIX_TYPE_COMPLEX:
1388 _print(state, "c[");
1390 _print(state, "]");
1391 break;
1392 case INFIX_TYPE_VECTOR:
1393 {
1394 const infix_type * element_type = type->meta.vector_info.element_type;
1395 size_t num_elements = type->meta.vector_info.num_elements;
1396 bool printed_alias = false;
1397 if (element_type->category == INFIX_TYPE_PRIMITIVE) {
1398 if (num_elements == 8 && is_double(element_type)) {
1399 _print(state, "m512d");
1400 printed_alias = true;
1401 }
1402 else if (num_elements == 16 && is_float(element_type)) {
1403 _print(state, "m512");
1404 printed_alias = true;
1405 }
1406 else if (num_elements == 8 && element_type->meta.primitive_id == INFIX_PRIMITIVE_SINT64) {
1407 _print(state, "m512i");
1408 printed_alias = true;
1409 }
1410 else if (num_elements == 4 && is_double(element_type)) {
1411 _print(state, "m256d");
1412 printed_alias = true;
1413 }
1414 else if (num_elements == 8 && is_float(element_type)) {
1415 _print(state, "m256");
1416 printed_alias = true;
1417 }
1418 }
1419 if (!printed_alias) {
1420 _print(state, "v[%zu:", num_elements);
1421 _infix_type_print_signature_recursive(state, element_type);
1422 _print(state, "]");
1423 }
1424 }
1425 break;
1427 switch (type->meta.primitive_id) {
1429 _print(state, "bool");
1430 break;
1432 _print(state, "sint8");
1433 break;
1435 _print(state, "uint8");
1436 break;
1438 _print(state, "sint16");
1439 break;
1441 _print(state, "uint16");
1442 break;
1444 _print(state, "sint32");
1445 break;
1447 _print(state, "uint32");
1448 break;
1450 _print(state, "sint64");
1451 break;
1453 _print(state, "uint64");
1454 break;
1456 _print(state, "sint128");
1457 break;
1459 _print(state, "uint128");
1460 break;
1462 _print(state, "float16");
1463 break;
1465 _print(state, "float");
1466 break;
1468 _print(state, "double");
1469 break;
1471 _print(state, "longdouble");
1472 break;
1473 }
1474 break;
1475 default:
1477 break;
1478 }
1479}
1487 if (state->status != INFIX_SUCCESS || !type) {
1488 if (state->status == INFIX_SUCCESS)
1490 return;
1491 }
1492
1493 // These built-in types must ALWAYS use ABI codes, ignoring any name aliases.
1494 if (type->category == INFIX_TYPE_VOID) {
1495 _print(state, "v");
1496 return;
1497 }
1498
1499 if (type->category == INFIX_TYPE_PRIMITIVE) {
1500 switch (type->meta.primitive_id) {
1502 _print(state, "b");
1503 return;
1504 case INFIX_PRIMITIVE_SINT8: // signed char
1505 _print(state, "a");
1506 return;
1507 case INFIX_PRIMITIVE_UINT8: // unsigned char
1508 _print(state, "h");
1509 return;
1510 case INFIX_PRIMITIVE_SINT16: // short
1511 _print(state, "s");
1512 return;
1513 case INFIX_PRIMITIVE_UINT16: // unsigned short
1514 _print(state, "t");
1515 return;
1516 case INFIX_PRIMITIVE_SINT32: // int
1517 _print(state, "i");
1518 return;
1519 case INFIX_PRIMITIVE_UINT32: // unsigned int
1520 _print(state, "j");
1521 return;
1522 case INFIX_PRIMITIVE_SINT64: // long long
1523 _print(state, "x");
1524 return;
1525 case INFIX_PRIMITIVE_UINT64: // unsigned long long
1526 _print(state, "y");
1527 return;
1528 case INFIX_PRIMITIVE_SINT128: // __int128
1529 _print(state, "n");
1530 return;
1531 case INFIX_PRIMITIVE_UINT128: // unsigned __int128
1532 _print(state, "o");
1533 return;
1534 case INFIX_PRIMITIVE_FLOAT16: // half-precision float (IEEE 754)
1535 _print(state, "Dh");
1536 return;
1538 _print(state, "f");
1539 return;
1541 _print(state, "d");
1542 return;
1544 _print(state, "e");
1545 return;
1546 }
1547 }
1548
1549 // Substitutions. Check if this complex type (Pointer/Struct) was already seen.
1550 size_t sub_index;
1551 bool is_builtin = (type->category == INFIX_TYPE_VOID || type->category == INFIX_TYPE_PRIMITIVE);
1552
1553 if (!is_builtin && _find_itanium_sub(state, type, &sub_index)) {
1554 _print_itanium_sub(state, sub_index);
1555 return;
1556 }
1557
1558 // Complex types
1559 switch (type->category) {
1560 case INFIX_TYPE_POINTER:
1561 _print(state, "P");
1563 _add_itanium_sub(state, type);
1564 break;
1566 {
1567 const char * name = type->meta.named_reference.name;
1568 size_t len = strlen(name);
1569 _print(state, "%zu%s", len, name);
1570 _add_itanium_sub(state, type);
1571 }
1572 break;
1573 case INFIX_TYPE_STRUCT:
1574 case INFIX_TYPE_UNION:
1575 if (type->name) {
1576 // Check for namespaced type (e.g. "Namespace::Class")
1577 // Itanium mangling for namespaces is N...E
1578 const char * p = type->name;
1579 int parts = 0;
1580 // Count parts
1581 while (*p) {
1582 if (p[0] == ':' && p[1] == ':') {
1583 parts++;
1584 p += 2;
1585 }
1586 else {
1587 p++;
1588 }
1589 }
1590 parts++; // Last part
1591
1592 if (parts > 1) {
1593 _print(state, "N");
1594 p = type->name;
1595 while (*p) {
1596 const char * end = strstr(p, "::");
1597 size_t part_len = end ? (size_t)(end - p) : strlen(p);
1598 _print(state, "%zu", part_len);
1599 // Print part_len chars
1600 for (size_t i = 0; i < part_len; i++)
1601 _print(state, "%c", p[i]);
1602 if (end)
1603 p = end + 2;
1604 else
1605 break;
1606 }
1607 _print(state, "E");
1608 }
1609 else {
1610 // Simple name
1611 size_t len = strlen(type->name);
1612 _print(state, "%zu%s", len, type->name);
1613 }
1614 _add_itanium_sub(state, type);
1615 }
1616 else {
1617 // Mangling for anonymous structs isn't standardized.
1618 // Emitting 'void' as a safe placeholder for "unknown type".
1619 _print(state, "v");
1620 }
1621 break;
1622 case INFIX_TYPE_COMPLEX:
1623 _print(state, "C");
1625 _add_itanium_sub(state, type);
1626 break;
1627 case INFIX_TYPE_VECTOR:
1628 _print(state, "Dv%zu_", type->size / type->meta.vector_info.element_type->size);
1630 _add_itanium_sub(state, type);
1631 break;
1632 default:
1633 // Fallback for types that don't map cleanly to Itanium mangling
1634 _print(state, "v");
1635 break;
1636 }
1637}
1645 if (state->status != INFIX_SUCCESS || !type) {
1646 if (state->status == INFIX_SUCCESS)
1648 return;
1649 }
1650
1651 // Built-in types: Use MSVC ABI codes immediately.
1652 if (type->category == INFIX_TYPE_VOID) {
1653 _print(state, "X");
1654 return;
1655 }
1656
1657 if (type->category == INFIX_TYPE_PRIMITIVE) {
1658 switch (type->meta.primitive_id) {
1660 _print(state, "_N");
1661 return;
1663 _print(state, "C");
1664 return;
1666 _print(state, "E");
1667 return;
1669 _print(state, "F");
1670 return;
1672 _print(state, "G");
1673 return;
1675 _print(state, "H");
1676 return;
1678 _print(state, "I");
1679 return;
1681 _print(state, "_J");
1682 return;
1684 _print(state, "_K");
1685 return;
1687 _print(state, "_L");
1688 return;
1690 _print(state, "_M");
1691 return;
1693 _print(state, "_T");
1694 return;
1696 _print(state, "M");
1697 return;
1699 _print(state, "N");
1700 return;
1702 _print(state, "O");
1703 return;
1704 }
1705 }
1706
1707 // Check for type back-references (0-9)
1708 // MSVC only back-references complex types or pointers to them.
1709 bool can_backref = (type->category == INFIX_TYPE_POINTER || type->category == INFIX_TYPE_STRUCT ||
1710 type->category == INFIX_TYPE_UNION || type->category == INFIX_TYPE_ENUM);
1711
1712 if (can_backref) {
1713 for (size_t i = 0; i < state->msvc_type_count; i++) {
1714 if (state->msvc_types[i] == type) {
1715 _print(state, "%zu", i);
1716 return;
1717 }
1718 }
1719 }
1720
1721 // Handle named types (Struct/Union/Enum or aliases)
1722 if (type->name) {
1723 // MSVC encoding:
1724 // U = Struct
1725 // T = Union
1726 // W = Enum
1727 char prefix = 'U';
1728 if (type->category == INFIX_TYPE_UNION)
1729 prefix = 'T';
1730 else if (type->category == INFIX_TYPE_ENUM)
1731 prefix = 'W';
1732
1733 // Check for namespaces (e.g. "Namespace::Class")
1734 // MSVC format: <Prefix><Name>@<Namespace>@@
1735 // Reverse order of namespaces!
1736 if (strstr(type->name, "::")) {
1737 _print(state, "%c", prefix);
1738
1739 // We need to split and reverse. Since we can't allocate easily here,
1740 // we'll scan the string multiple times or use recursion.
1741 // Let's use a simple stack-based approach for small depth.
1742 const char * parts[MAX_RECURSION_DEPTH];
1743 size_t lens[MAX_RECURSION_DEPTH];
1744 int count = 0;
1745
1746 const char * p = type->name;
1747 while (*p && count < MAX_RECURSION_DEPTH) {
1748 parts[count] = p;
1749 const char * end = strstr(p, "::");
1750 if (end) {
1751 lens[count] = end - p;
1752 p = end + 2;
1753 }
1754 else {
1755 lens[count] = strlen(p);
1756 p += lens[count];
1757 }
1758 count++;
1759 }
1760
1761 // Print in reverse order
1762 for (int i = count - 1; i >= 0; i--) {
1763 for (size_t j = 0; j < lens[i]; j++)
1764 _print(state, "%c", parts[i][j]);
1765 _print(state, "@");
1766 }
1767 _print(state, "@"); // Terminator
1768 }
1769 else {
1770 _print(state, "%c%s@@", prefix, type->name);
1771 }
1772
1773 if (can_backref && state->msvc_type_count < 10)
1774 state->msvc_types[state->msvc_type_count++] = type;
1775 return;
1776 }
1777
1778 switch (type->category) {
1779 case INFIX_TYPE_POINTER:
1780 // Standard MSVC pointer encoding for x64:
1781 // P = Pointer
1782 // E = __ptr64
1783 // A = const/volatile qualifiers (A = none)
1784 // Then the pointee type.
1785 _print(state, "PEA");
1787 if (can_backref && state->msvc_type_count < 10)
1788 state->msvc_types[state->msvc_type_count++] = type;
1789 break;
1790 case INFIX_TYPE_REVERSE_TRAMPOLINE: // Function Pointer
1791 // P6 = Pointer to Function
1792 // A = __cdecl
1793 _print(state, "P6A");
1794 // Return type
1796 // Arguments
1797 if (type->meta.func_ptr_info.num_args == 0)
1798 _print(state, "X");
1799 else
1800 for (size_t i = 0; i < type->meta.func_ptr_info.num_args; ++i)
1802 _print(state, "@Z");
1803 if (can_backref && state->msvc_type_count < 10)
1804 state->msvc_types[state->msvc_type_count++] = type;
1805 break;
1806 case INFIX_TYPE_COMPLEX:
1807 // MSVC doesn't have a built-in complex type, it uses structs.
1808 _print(state, "U_Complex@@");
1809 if (can_backref && state->msvc_type_count < 10)
1810 state->msvc_types[state->msvc_type_count++] = type;
1811 break;
1812 case INFIX_TYPE_VECTOR:
1813 _print(state, "T__m%zu@@", type->size * 8);
1814 if (can_backref && state->msvc_type_count < 10)
1815 state->msvc_types[state->msvc_type_count++] = type;
1816 break;
1818 // Unresolved references, treat as Struct for mangling purposes.
1819 _print(state, "U%s@@", type->meta.named_reference.name);
1820 if (can_backref && state->msvc_type_count < 10)
1821 state->msvc_types[state->msvc_type_count++] = type;
1822 break;
1823 default:
1824 _print(state, "X");
1825 break;
1826 }
1827}
1841 if (state->status != INFIX_SUCCESS || !type) {
1842 if (state->status == INFIX_SUCCESS)
1844 return;
1845 }
1846 // This is the key difference from the main printer: we skip the `if (type->name)` check
1847 // and immediately print the underlying structure of the type.
1848 switch (type->category) {
1849 case INFIX_TYPE_STRUCT:
1850 if (type->meta.aggregate_info.is_packed) {
1851 _print(state, "!");
1852 if (type->alignment != 1)
1853 _print(state, "%zu:", type->alignment);
1854 }
1855 _print(state, "{");
1856 for (size_t i = 0; i < type->meta.aggregate_info.num_members; ++i) {
1857 if (i > 0)
1858 _print(state, ",");
1859 const infix_struct_member * member = &type->meta.aggregate_info.members[i];
1860 if (member->name)
1861 _print(state, "%s:", member->name);
1862 // For nested members, we can use the standard printer, which IS allowed
1863 // to use the `@Name` shorthand for brevity.
1865 if (member->bit_width > 0)
1866 _print(state, ":%u", member->bit_width);
1867 }
1868 _print(state, "}");
1869 break;
1870 case INFIX_TYPE_UNION:
1871 _print(state, "<");
1872 for (size_t i = 0; i < type->meta.aggregate_info.num_members; ++i) {
1873 if (i > 0)
1874 _print(state, ",");
1875 const infix_struct_member * member = &type->meta.aggregate_info.members[i];
1876 if (member->name)
1877 _print(state, "%s:", member->name);
1879 if (member->bit_width > 0)
1880 _print(state, ":%u", member->bit_width);
1881 }
1882 _print(state, ">");
1883 break;
1884 // For all other types, we replicate the printing logic from the main printer
1885 // to ensure we print the structure, not a potential top-level alias name.
1886 case INFIX_TYPE_VOID:
1887 _print(state, "void");
1888 break;
1889 case INFIX_TYPE_POINTER:
1890 _print(state, "*");
1891 if (type->meta.pointer_info.pointee_type == type || type->meta.pointer_info.pointee_type == nullptr ||
1893 _print(state, "void");
1894 else
1896 break;
1897 case INFIX_TYPE_ARRAY:
1898 if (type->meta.array_info.is_flexible)
1899 _print(state, "[?:");
1900 else
1901 _print(state, "[%zu:", type->meta.array_info.num_elements);
1903 _print(state, "]");
1904 break;
1905 case INFIX_TYPE_ENUM:
1906 _print(state, "e:");
1908 break;
1909 case INFIX_TYPE_COMPLEX:
1910 _print(state, "c[");
1912 _print(state, "]");
1913 break;
1915 // This block is now a full copy from the main printer.
1916 switch (type->meta.primitive_id) {
1918 _print(state, "bool");
1919 break;
1921 _print(state, "sint8");
1922 break;
1924 _print(state, "uint8");
1925 break;
1927 _print(state, "sint16");
1928 break;
1930 _print(state, "uint16");
1931 break;
1933 _print(state, "sint32");
1934 break;
1936 _print(state, "uint32");
1937 break;
1939 _print(state, "sint64");
1940 break;
1942 _print(state, "uint64");
1943 break;
1945 _print(state, "sint128");
1946 break;
1948 _print(state, "uint128");
1949 break;
1951 _print(state, "float16");
1952 break;
1954 _print(state, "float");
1955 break;
1957 _print(state, "double");
1958 break;
1960 _print(state, "longdouble");
1961 break;
1962 }
1963 break;
1964 // We can safely delegate the remaining complex cases to the main printer, as they
1965 // do not have a top-level `name` field themselves.
1968 case INFIX_TYPE_VECTOR:
1970 break;
1971 default:
1973 break;
1974 }
1975}
1981 size_t buffer_size,
1982 const infix_type * type,
1983 infix_print_dialect_t dialect) {
1984 if (!buffer || buffer_size == 0 || !type || dialect != INFIX_DIALECT_SIGNATURE)
1986 printer_state state = {buffer, buffer_size, INFIX_SUCCESS, {0}, 0, {0}, 0};
1987 *buffer = '\0';
1989 if (state.remaining > 0)
1990 *state.p = '\0';
1991 else
1992 buffer[buffer_size - 1] = '\0';
1993 return state.status;
1994}
2004 size_t buffer_size,
2005 const infix_type * type,
2006 infix_print_dialect_t dialect) {
2008 if (!buffer || buffer_size == 0 || !type) {
2011 }
2012 printer_state state = {buffer, buffer_size, INFIX_SUCCESS, {0}, 0, {0}, 0};
2013 *buffer = '\0';
2014 if (dialect == INFIX_DIALECT_SIGNATURE)
2016 else if (dialect == INFIX_DIALECT_ITANIUM_MANGLING)
2018 else if (dialect == INFIX_DIALECT_MSVC_MANGLING)
2020 else {
2021 _print(&state, "unsupported_dialect");
2023 }
2024 if (state.status == INFIX_SUCCESS) {
2025 if (state.remaining > 0)
2026 *state.p = '\0'; // Null-terminate if there is space.
2027 else {
2028 // Buffer was exactly full. Ensure null termination at the very end.
2029 buffer[buffer_size - 1] = '\0';
2030 return INFIX_ERROR_INVALID_ARGUMENT; // Indicate truncation.
2031 }
2032 }
2033 else if (buffer_size > 0)
2034 // Ensure null termination even on error (e.g., buffer too small).
2035 buffer[buffer_size - 1] = '\0';
2036 return state.status;
2037}
2051 size_t buffer_size,
2052 const char * function_name,
2053 const infix_type * ret_type,
2055 size_t num_args,
2056 size_t num_fixed_args,
2057 infix_print_dialect_t dialect) {
2059 if (!buffer || buffer_size == 0 || !ret_type || (num_args > 0 && !args)) {
2062 }
2063 printer_state state = {buffer, buffer_size, INFIX_SUCCESS, {0}, 0, {0}, 0};
2064 *buffer = '\0';
2065 if (dialect == INFIX_DIALECT_SIGNATURE) {
2066 (void)function_name; // Unused
2067 _print(&state, "(");
2068 for (size_t i = 0; i < num_fixed_args; ++i) {
2069 if (i > 0)
2070 _print(&state, ",");
2072 }
2073 if (num_args > num_fixed_args) {
2074 _print(&state, ";");
2075 for (size_t i = num_fixed_args; i < num_args; ++i) {
2076 if (i > num_fixed_args)
2077 _print(&state, ",");
2079 }
2080 }
2081 _print(&state, ")->");
2083 }
2084 else if (dialect == INFIX_DIALECT_ITANIUM_MANGLING) {
2085 // _Z <name_len> <name> <ret_type?> <args...>
2086 // Note: Itanium mangling usually omits return type for standard functions unless it's a template or special
2087 // case. We omit it here for simplicity to match extern "C" -> C++ linking expectations for simple functions.
2088 _print(&state, "_Z");
2089 if (function_name) {
2090 // Check for namespace in function name (e.g., "MyNS::my_func")
2091 const char * p = function_name;
2092 int parts = 0;
2093 while (*p)
2094 if (p[0] == ':' && p[1] == ':') {
2095 parts++;
2096 p += 2;
2097 }
2098 else
2099 p++;
2100 parts++;
2101
2102 if (parts > 1) {
2103 _print(&state, "N");
2104 p = function_name;
2105 while (*p) {
2106 const char * end = strstr(p, "::");
2107 size_t part_len = end ? (size_t)(end - p) : strlen(p);
2108 _print(&state, "%zu", part_len);
2109 for (size_t i = 0; i < part_len; i++)
2110 _print(&state, "%c", p[i]);
2111 if (end)
2112 p = end + 2;
2113 else
2114 break;
2115 }
2116 _print(&state, "E");
2117 }
2118 else {
2119 size_t name_len = strlen(function_name);
2120 _print(&state, "%zu%s", name_len, function_name);
2121 }
2122 }
2123 else
2124 _print(&state, "4func"); // Default name if NULL
2125
2126 if (num_args == 0)
2127 _print(&state, "v"); // void (no args)
2128 else
2129 for (size_t i = 0; i < num_args; ++i)
2131 }
2132 else if (dialect == INFIX_DIALECT_MSVC_MANGLING) {
2133 // MSVC: ?<name>@@YA<ret><args...>@Z
2134 _print(&state, "?");
2135 if (function_name) {
2136 // MSVC namespace handling: reverse order
2137 if (strstr(function_name, "::")) {
2138 const char * parts[MAX_RECURSION_DEPTH];
2139 size_t lens[MAX_RECURSION_DEPTH];
2140 int count = 0;
2141 const char * p = function_name;
2142 while (*p && count < MAX_RECURSION_DEPTH) {
2143 parts[count] = p;
2144 const char * end = strstr(p, "::");
2145 if (end) {
2146 lens[count] = end - p;
2147 p = end + 2;
2148 }
2149 else {
2150 lens[count] = strlen(p);
2151 p += lens[count];
2152 }
2153 count++;
2154 }
2155 // Print in reverse order
2156 for (int i = count - 1; i >= 0; i--) {
2157 for (size_t j = 0; j < lens[i]; j++)
2158 _print(&state, "%c", parts[i][j]);
2159 _print(&state, "@");
2160 }
2161 }
2162 else {
2163 _print(&state, "%s@", function_name);
2164 }
2165 }
2166 else {
2167 _print(&state, "func@");
2168 }
2169 _print(&state, "@YA"); // __cdecl (default)
2171
2172 if (num_args == 0)
2173 _print(&state, "X"); // void argument list
2174 else
2175 for (size_t i = 0; i < num_args; ++i)
2176 _infix_type_print_msvc_recursive(&state, args[i].type);
2177 _print(&state, "@Z");
2178 }
2179 else {
2180 _print(&state, "unsupported_dialect");
2182 }
2183 if (state.status == INFIX_SUCCESS) {
2184 if (state.remaining > 0)
2185 *state.p = '\0';
2186 else {
2187 if (buffer_size > 0)
2188 buffer[buffer_size - 1] = '\0';
2189 return INFIX_ERROR_INVALID_ARGUMENT; // Indicate truncation.
2190 }
2191 }
2192 else if (buffer_size > 0)
2193 buffer[buffer_size - 1] = '\0';
2194 return state.status;
2195}
2210c23_nodiscard infix_status infix_registry_print(char * buffer, size_t buffer_size, const infix_registry_t * registry) {
2211 if (!buffer || buffer_size == 0 || !registry)
2213 printer_state state = {buffer, buffer_size, INFIX_SUCCESS, {0}, 0, {0}, 0};
2214 *state.p = '\0';
2215 // Iterate through all buckets and their chains.
2216 for (size_t i = 0; i < registry->num_buckets; ++i) {
2217 for (const _infix_registry_entry_t * entry = registry->buckets[i]; entry != nullptr; entry = entry->next) {
2218 // Only print fully defined types, not forward declarations.
2219 if (entry->type && !entry->is_forward_declaration) {
2220 char type_body_buffer[1024];
2222 type_body_buffer, sizeof(type_body_buffer), entry->type, INFIX_DIALECT_SIGNATURE) !=
2223 INFIX_SUCCESS) {
2225 goto end_print_loop;
2226 }
2227 _print(&state, "@%s = %s;\n", entry->name, type_body_buffer);
2228 }
2229 else if (entry->is_forward_declaration) // Explicitly print forward declarations
2230 _print(&state, "@%s;\n", entry->name);
2231 if (state.status != INFIX_SUCCESS)
2232 goto end_print_loop;
2233 }
2234 }
2235end_print_loop:;
2236 return state.status;
2237}
infix_registry_t * registry
Definition 008_registry_introspection.c:33
infix_status status
Definition 103_unions.c:61
infix_struct_member * members
Definition 103_unions.c:55
void * args[]
Definition 202_in_structs.c:59
clock_t start
Definition 901_call_overhead.c:48
infix_type * ret_type
Definition 901_call_overhead.c:61
clock_t end
Definition 901_call_overhead.c:48
char * p
Definition 904_registry_benchmark.c:25
#define c23_nodiscard
Internal alias for the public INFIX_NODISCARD macro.
Definition compat_c23.h:92
#define INFIX_TLS
Definition error.c:68
INFIX_API 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:281
infix_error_code_t
Enumerates specific error codes.
Definition infix.h:1360
@ INFIX_CODE_SUCCESS
Definition infix.h:1362
@ INFIX_CODE_INVALID_MEMBER_TYPE
Definition infix.h:1388
@ INFIX_CODE_INTEGER_OVERFLOW
Definition infix.h:1379
@ INFIX_CODE_TYPE_TOO_LARGE
Definition infix.h:1386
@ INFIX_CODE_EMPTY_SIGNATURE
Definition infix.h:1382
@ INFIX_CODE_UNEXPECTED_TOKEN
Definition infix.h:1375
@ INFIX_CODE_MISSING_RETURN_TYPE
Definition infix.h:1378
@ INFIX_CODE_RECURSION_DEPTH_EXCEEDED
Definition infix.h:1380
@ INFIX_CODE_UNTERMINATED_AGGREGATE
Definition infix.h:1376
@ INFIX_CODE_NULL_POINTER
Definition infix.h:1364
@ INFIX_CODE_INVALID_KEYWORD
Definition infix.h:1377
@ INFIX_CODE_OUT_OF_MEMORY
Definition infix.h:1369
@ INFIX_CATEGORY_ALLOCATION
Definition infix.h:1353
@ INFIX_CATEGORY_GENERAL
Definition infix.h:1352
@ INFIX_CATEGORY_PARSER
Definition infix.h:1354
size_t source_offset
Definition infix.h:282
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:295
struct infix_type_t::@0::@7 vector_info
Metadata for INFIX_TYPE_VECTOR.
infix_type * type
Definition infix.h:348
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:1112
struct infix_type_t::@0::@4 func_ptr_info
Metadata for INFIX_TYPE_REVERSE_TRAMPOLINE.
size_t num_elements
Definition infix.h:300
infix_arena_t * arena
Definition infix.h:281
size_t size
Definition infix.h:277
size_t alignment
Definition infix.h:278
infix_struct_member * members
Definition infix.h:293
struct infix_type_t::@0::@6 complex_info
Metadata for INFIX_TYPE_COMPLEX.
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:1053
const char * name
Definition infix.h:275
infix_function_argument * args
Definition infix.h:306
infix_status
Enumerates the possible status codes returned by infix API functions.
Definition infix.h:434
const char * name
Definition infix.h:347
const char * name
Definition infix.h:335
infix_type_category category
Definition infix.h:276
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:289
infix_type * type
Definition infix.h:336
struct infix_type_t * element_type
Definition infix.h:299
bool is_flexible
Definition infix.h:301
struct infix_type_t * return_type
Definition infix.h:305
struct infix_type_t::@0::@5 enum_info
Metadata for INFIX_TYPE_ENUM.
struct infix_type_t * base_type
Definition infix.h:316
uint8_t bit_width
Definition infix.h:338
size_t num_members
Definition infix.h:294
struct infix_type_t * underlying_type
Definition infix.h:312
struct infix_type_t::@0::@8 named_reference
Metadata for INFIX_TYPE_NAMED_REFERENCE.
size_t num_fixed_args
Definition infix.h:308
infix_primitive_type_id primitive_id
Metadata for INFIX_TYPE_PRIMITIVE.
Definition infix.h:286
size_t num_args
Definition infix.h:307
bool is_arena_allocated
Definition infix.h:279
@ INFIX_ERROR_ALLOCATION_FAILED
Definition infix.h:436
@ INFIX_SUCCESS
Definition infix.h:435
@ INFIX_ERROR_INVALID_ARGUMENT
Definition infix.h:437
INFIX_API 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:2050
INFIX_API 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:2003
infix_print_dialect_t
Specifies the output format for printing types and function signatures.
Definition infix.h:1175
@ INFIX_DIALECT_SIGNATURE
Definition infix.h:1176
@ INFIX_DIALECT_ITANIUM_MANGLING
Definition infix.h:1177
@ INFIX_DIALECT_MSVC_MANGLING
Definition infix.h:1178
INFIX_API INFIX_NODISCARD void * infix_arena_alloc(infix_arena_t *, size_t, size_t)
Allocates a block of memory from an arena.
Definition arena.c:117
#define infix_memcpy
A macro that can be defined to override the default memcpy function.
Definition infix.h:387
INFIX_API INFIX_NODISCARD infix_arena_t * infix_arena_create(size_t)
Creates a new memory arena.
Definition arena.c:52
INFIX_API INFIX_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:188
INFIX_API void infix_arena_destroy(infix_arena_t *)
Destroys an arena and frees all memory allocated from it.
Definition arena.c:83
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:2210
INFIX_API INFIX_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:393
INFIX_API 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:208
INFIX_API INFIX_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:719
INFIX_API INFIX_NODISCARD infix_status infix_type_create_complex(infix_arena_t *, infix_type **, infix_type *)
Creates a new _Complex number type.
Definition types.c:542
infix_primitive_type_id
Enumerates the supported primitive C types.
Definition infix.h:243
INFIX_API INFIX_NODISCARD infix_type * infix_type_create_void(void)
Creates a static descriptor for the void type.
Definition types.c:200
INFIX_API INFIX_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:612
INFIX_API 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:219
INFIX_API INFIX_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:777
INFIX_API INFIX_NODISCARD infix_type * infix_type_create_primitive(infix_primitive_type_id)
Creates a static descriptor for a primitive C type.
Definition types.c:144
INFIX_API INFIX_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:573
INFIX_API INFIX_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:660
INFIX_API INFIX_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:507
INFIX_API infix_status infix_type_create_flexible_array(infix_arena_t *, infix_type **, infix_type *)
Creates a flexible array member type ([?:type]).
Definition types.c:463
INFIX_API INFIX_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:424
@ INFIX_PRIMITIVE_UINT16
Definition infix.h:247
@ INFIX_PRIMITIVE_UINT32
Definition infix.h:249
@ INFIX_PRIMITIVE_LONG_DOUBLE
Definition infix.h:258
@ INFIX_PRIMITIVE_FLOAT
Definition infix.h:256
@ INFIX_PRIMITIVE_DOUBLE
Definition infix.h:257
@ INFIX_PRIMITIVE_SINT16
Definition infix.h:248
@ INFIX_PRIMITIVE_SINT64
Definition infix.h:252
@ INFIX_PRIMITIVE_SINT32
Definition infix.h:250
@ INFIX_PRIMITIVE_UINT8
Definition infix.h:245
@ INFIX_PRIMITIVE_UINT128
Definition infix.h:253
@ INFIX_PRIMITIVE_BOOL
Definition infix.h:244
@ INFIX_PRIMITIVE_UINT64
Definition infix.h:251
@ INFIX_PRIMITIVE_FLOAT16
Definition infix.h:255
@ INFIX_PRIMITIVE_SINT128
Definition infix.h:254
@ INFIX_PRIMITIVE_SINT8
Definition infix.h:246
@ INFIX_TYPE_UNION
Definition infix.h:231
@ INFIX_TYPE_PRIMITIVE
Definition infix.h:228
@ INFIX_TYPE_COMPLEX
Definition infix.h:235
@ INFIX_TYPE_ARRAY
Definition infix.h:232
@ INFIX_TYPE_VECTOR
Definition infix.h:236
@ INFIX_TYPE_VOID
Definition infix.h:238
@ INFIX_TYPE_POINTER
Definition infix.h:229
@ INFIX_TYPE_NAMED_REFERENCE
Definition infix.h:237
@ INFIX_TYPE_REVERSE_TRAMPOLINE
Definition infix.h:233
@ INFIX_TYPE_ENUM
Definition infix.h:234
@ INFIX_TYPE_STRUCT
Definition infix.h:230
@ INFIX_AGGREGATE_STRUCT
Definition infix.h:264
#define INFIX_API
Symbol visibility macro.
Definition infix.h:114
#define INFIX_INTERNAL
When compiling with -fvisibility=hidden, we use this to explicitly mark internal-but-shared functions...
Definition infix_config.h:220
Internal data structures, function prototypes, and constants.
INFIX_INTERNAL 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:428
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:791
INFIX_INTERNAL 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:1112
INFIX_INTERNAL void _infix_type_recalculate_layout(infix_type *type)
Recalculates the layout of a fully resolved type graph.
Definition types.c:924
INFIX_INTERNAL void _infix_clear_error(void)
Clears the thread-local error state.
Definition error.c:268
static bool is_float(const infix_type *type)
A fast inline check to determine if an infix_type is a float (32-bit).
Definition infix_internals.h:783
INFIX_INTERNAL 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:175
static void _print(printer_state *state, const char *fmt,...)
Definition signature.c:1210
static void _add_itanium_sub(printer_state *state, const void *component)
Definition signature.c:1241
static infix_struct_member * parse_aggregate_members(parser_state *state, char end_char, size_t *out_num_members)
Definition signature.c:243
static bool is_function_signature_ahead(const parser_state *state)
Definition signature.c:204
static void _infix_type_print_body_only_recursive(printer_state *state, const infix_type *type)
Definition signature.c:1840
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:1980
INFIX_INTERNAL infix_type * parse_primitive(parser_state *state)
Definition signature.c:487
#define MAX_RECURSION_DEPTH
Definition signature.c:47
static bool _find_itanium_sub(printer_state *state, const void *component, size_t *index)
Definition signature.c:1231
INFIX_INTERNAL void skip_whitespace(parser_state *state)
Definition signature.c:70
static bool parse_size_t(parser_state *state, size_t *out_val)
Definition signature.c:88
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:1003
static void _print_itanium_sub(printer_state *state, size_t index)
Definition signature.c:1246
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:845
INFIX_INTERNAL void _infix_set_parser_error(parser_state *state, infix_error_code_t code)
Definition signature.c:60
static infix_type * _create_named_primitive(parser_state *state, infix_primitive_type_id id, const char *name)
Definition signature.c:459
static bool consume_keyword(parser_state *state, const char *keyword)
Definition signature.c:152
static infix_type * parse_packed_struct(parser_state *state)
Definition signature.c:407
static infix_type * parse_aggregate(parser_state *state, char start_char, char end_char)
Definition signature.c:366
static const char * parse_identifier(parser_state *state)
Definition signature.c:118
INFIX_INTERNAL infix_type * parse_type(parser_state *state)
Definition signature.c:619
static void _infix_type_print_itanium_recursive(printer_state *state, const infix_type *type)
Definition signature.c:1486
static void _infix_type_print_signature_recursive(printer_state *state, const infix_type *type)
Definition signature.c:1284
static const char * parse_optional_name_prefix(parser_state *state)
Definition signature.c:174
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 _infix_type_print_msvc_recursive(printer_state *state, const infix_type *type)
Definition signature.c:1644
A single entry in the registry's hash table.
Definition infix_internals.h:174
Internal definition of a memory arena.
Definition infix_internals.h:143
Describes a single argument to a C function.
Definition infix.h:346
Internal definition of a named type registry.
Definition infix_internals.h:188
_infix_registry_entry_t ** buckets
Definition infix_internals.h:193
size_t num_buckets
Definition infix_internals.h:191
Describes a single member of a C struct or union.
Definition infix.h:334
A semi-opaque structure that describes a C type.
Definition infix.h:274
Holds the complete state of the recursive descent parser during a single parse operation.
Definition infix_internals.h:199
const char * start
Definition infix_internals.h:201
infix_arena_t * arena
Definition infix_internals.h:202
int depth
Definition infix_internals.h:203
const char * p
Definition infix_internals.h:200
Definition signature.c:1191
char * p
Definition signature.c:1192
size_t remaining
Definition signature.c:1193
infix_status status
Definition signature.c:1194
const void * itanium_subs[64]
Definition signature.c:1196
size_t msvc_type_count
Definition signature.c:1200
const infix_type * msvc_types[10]
Definition signature.c:1199
size_t itanium_sub_count
Definition signature.c:1197