69#define MAX_RECURSION_DEPTH 32
122 while (isspace((
unsigned char)*state->
p))
126 if (*state->
p ==
'#') {
128 while (*state->
p !=
'\n' && *state->
p !=
'\0')
146 const char *
start = state->
p;
149 unsigned long long val = strtoull(
start, &
end, 10);
155 *out_val = (size_t)val;
171 const char *
start = state->
p;
173 if (!isalpha((
unsigned char)*
start) && *
start !=
'_')
176 while (isalnum((
unsigned char)*state->
p) || *state->
p ==
'_' || *state->
p ==
':') {
178 if (*state->
p ==
':' && state->
p[1] !=
':')
180 if (*state->
p ==
':')
184 size_t len = state->
p -
start;
210 size_t len = strlen(keyword);
211 if (strncmp(state->
p, keyword, len) == 0) {
214 if (isalnum((
unsigned char)state->
p[len]) || state->
p[len] ==
'_')
237 const char * p_before = state->
p;
241 if (*state->
p ==
':') {
263 const char * p = state->
p;
270 while (*p !=
'\0' && depth > 0) {
281 while (isspace((
unsigned char)*p) || *p ==
'#') {
283 while (*p !=
'\n' && *p !=
'\0')
290 return (p[0] ==
'-' && p[1] ==
'>');
310 typedef struct member_node {
312 struct member_node * next;
314 member_node *head =
nullptr, *tail =
nullptr;
315 size_t num_members = 0;
318 if (*state->
p != end_char) {
321 const char * p_before_member = state->
p;
324 if (name && (*state->
p ==
',' || *state->
p == end_char)) {
326 state->
p = p_before_member + strlen(name);
346 node->next =
nullptr;
356 if (*state->
p ==
',') {
360 if (*state->
p == end_char) {
365 else if (*state->
p == end_char)
368 if (*state->
p ==
'\0')
375 *out_num_members = num_members;
376 if (num_members == 0)
385 member_node * current = head;
386 for (
size_t i = 0; i < num_members; i++) {
388 current = current->next;
405 size_t alignment = 1;
406 if (*state->
p ==
'!') {
409 if (isdigit((
unsigned char)*state->
p)) {
412 if (*state->
p !=
':') {
420 if (*state->
p !=
'{') {
425 size_t num_members = 0;
430 if (*state->
p !=
'}') {
438 size_t total_size = 0;
439 for (
size_t i = 0; i < num_members; ++i)
440 total_size +=
members[i].type->size;
446 (size_t)(state->
p - state->
start));
461 if (*state->
p !=
'[') {
471 if (*state->
p !=
':') {
484 if (*state->
p !=
']') {
509 size_t num_args = 0, num_fixed = 0;
548 if (*state->
p != start_char) {
554 size_t num_members = 0;
561 if (*state->
p != end_char) {
574 (size_t)(state->
p - state->
start));
665 size_t * out_num_args,
666 size_t * out_num_fixed_args) {
667 if (*state->
p !=
'(') {
674 typedef struct arg_node {
676 struct arg_node * next;
678 arg_node *head =
nullptr, *tail =
nullptr;
681 if (*state->
p !=
')') {
685 if (*state->
p ==
')' || *state->
p ==
';')
698 node->arg.type = arg_type;
699 node->arg.name = name;
700 node->next =
nullptr;
709 if (*state->
p ==
',') {
713 if (*state->
p ==
')' || *state->
p ==
';') {
718 else if (*state->
p !=
')' && *state->
p !=
';') {
726 *out_num_fixed_args = num_args;
728 if (*state->
p ==
';') {
731 if (*state->
p !=
')') {
734 if (*state->
p ==
')')
746 node->arg.type = arg_type;
747 node->arg.name = name;
748 node->next =
nullptr;
757 if (*state->
p ==
',') {
760 if (*state->
p ==
')') {
765 else if (*state->
p !=
')') {
776 if (*state->
p !=
')') {
782 if (state->
p[0] !=
'-' || state->
p[1] !=
'>') {
794 if (num_args > 0 && !
args) {
798 arg_node * current = head;
799 for (
size_t i = 0; i < num_args; i++) {
800 args[i] = current->arg;
801 current = current->next;
804 *out_num_args = num_args;
828 const char * p_before_type = state->
p;
831 if (*state->
p ==
'@') {
849 result_type =
nullptr;
852 else if (*state->
p ==
'*') {
866 result_type =
nullptr;
869 else if (*state->
p ==
'(') {
883 if (*state->
p !=
')') {
885 result_type =
nullptr;
891 else if (*state->
p ==
'[') {
901 if (*state->
p !=
':') {
920 if (*state->
p !=
']') {
930 result_type =
nullptr;
933 else if (*state->
p ==
'!')
935 else if (*state->
p ==
'{')
937 else if (*state->
p ==
'<')
939 else if (*state->
p ==
'e') {
943 if (*state->
p ==
'<') {
948 if (*state->
p !=
':') {
957 if (!underlying_type) {
970 result_type =
nullptr;
973 else if (*state->
p ==
'c' && state->
p[1] ==
'[') {
977 if (*state->
p !=
'[') {
990 if (*state->
p !=
']') {
1000 result_type =
nullptr;
1003 else if (*state->
p ==
'v' && state->
p[1] ==
'[')
1014 state->
p = p_before_type;
1015 if (isalpha((
unsigned char)*state->
p) || *state->
p ==
'_')
1042 const char * signature,
1044 if (!out_type || !out_arena || !signature || *signature ==
'\0') {
1055 parser_state state = {.
p = signature, .start = signature, .arena = *out_arena, .registry = registry, .depth = 0};
1062 if (state.
p[0] !=
'\0') {
1072 *out_arena =
nullptr;
1073 *out_type =
nullptr;
1092 const char * signature,
1108 *out_arena =
nullptr;
1109 *out_type =
nullptr;
1127 size_t * out_num_args,
1128 size_t * out_num_fixed_args,
1132 if (!signature || !out_arena || !out_ret_type || !out_args || !out_num_args || !out_num_fixed_args) {
1143 parser_state state = {.
p = signature, .start = signature, .arena = *out_arena, .registry = registry, .depth = 0};
1152 if (state.
p[0] !=
'\0') {
1166 for (
size_t i = 0; i < *out_num_args; ++i) {
1178 *out_arena =
nullptr;
1203 va_start(
args, fmt);
1207 if (written < 0 || (
size_t)written >= state->
remaining)
1210 state->
p += written;
1342 _print(state,
"longlong");
1345 _print(state,
"ulonglong");
1354 _print(state,
"longdouble");
1375 if (!buffer || buffer_size == 0 || !type) {
1389 _print(&state,
"mangling_not_implemented");
1402 buffer[buffer_size - 1] =
'\0';
1407 else if (buffer_size > 0)
1408 buffer[buffer_size - 1] =
'\0';
1417 const char * function_name,
1421 size_t num_fixed_args,
1424 if (!buffer || buffer_size == 0 || !
ret_type || (num_args > 0 && !
args)) {
1430 (void)function_name;
1434 for (
size_t i = 0; i < num_fixed_args; ++i) {
1439 if (num_args > num_fixed_args) {
1441 for (
size_t i = num_fixed_args; i < num_args; ++i) {
1442 if (i > num_fixed_args)
1451 _print(&state,
"unsupported_dialect");
1459 if (buffer_size > 0)
1460 buffer[buffer_size - 1] =
'\0';
1465 else if (buffer_size > 0)
1466 buffer[buffer_size - 1] =
'\0';
infix_status status
Definition 103_unions.c:74
infix_struct_member * members
Definition 103_unions.c:68
void * args[]
Definition 202_in_structs.c:75
clock_t start
Definition 901_call_overhead.c:58
infix_type * ret_type
Definition 901_call_overhead.c:75
clock_t end
Definition 901_call_overhead.c:58
#define c23_nodiscard
Definition compat_c23.h:93
infix_error_code_t
Specific error codes providing detailed information about a failure.
Definition infix.h:1055
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:87
@ INFIX_CODE_SUCCESS
The operation completed successfully.
Definition infix.h:1057
@ INFIX_CODE_UNEXPECTED_TOKEN
Parser ran into an invalid character at a given position.
Definition infix.h:1066
@ INFIX_CODE_MISSING_RETURN_TYPE
A function signature was missing the -> or a return type.
Definition infix.h:1069
@ INFIX_CODE_UNKNOWN
An unknown or unspecified error occurred. This is a fallback code.
Definition infix.h:1058
@ INFIX_CODE_RECURSION_DEPTH_EXCEEDED
The parser exceeded the max nesting depth (e.g., {{{{...}}}}).
Definition infix.h:1072
@ INFIX_CODE_UNTERMINATED_AGGREGATE
A {...}, <...>, or [...] was not properly closed.
Definition infix.h:1067
@ INFIX_CODE_INVALID_KEYWORD
Parser found an unknown keyword (e.g., "integer" instead of "int").
Definition infix.h:1068
@ INFIX_CODE_OUT_OF_MEMORY
Failure to allocate memory. Likely due to lack of system resources.
Definition infix.h:1061
@ INFIX_CATEGORY_ALLOCATION
An error related to memory allocation.
Definition infix.h:1042
@ INFIX_CATEGORY_GENERAL
A general or miscellaneous error.
Definition infix.h:1041
@ INFIX_CATEGORY_PARSER
An error that occurred while parsing a signature string.
Definition infix.h:1043
c23_nodiscard infix_status infix_type_from_signature(infix_type **out_type, infix_arena_t **out_arena, const char *signature, infix_registry_t *registry)
Implementation of the public infix_type_from_signature API function.
Definition signature.c:1090
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)
Implementation of the public infix_signature_parse API function.
Definition signature.c:1123
infix_status infix_type_print(char *buffer, size_t buffer_size, const infix_type *type, infix_print_dialect_t dialect)
Implementation of the public infix_type_print API function.
Definition signature.c:1370
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)
Implementation of the public infix_function_print API function.
Definition signature.c:1415
infix_print_dialect_t
Specifies the output format for type-to-string serialization functions.
Definition infix.h:814
@ INFIX_DIALECT_SIGNATURE
The standard infix signature language format.
Definition infix.h:815
@ INFIX_DIALECT_ITANIUM_MANGLING
Itanium C++ ABI name mangling (used by GCC/Clang). (Not yet implemented)
Definition infix.h:816
@ INFIX_DIALECT_MSVC_MANGLING
Microsoft C++ ABI name mangling. (Not yet implemented)
Definition infix.h:817
void infix_arena_destroy(infix_arena_t *)
Frees an entire memory arena and all objects allocated within it.
Definition arena.c:68
#define infix_memcpy
A macro for copying memory from a source to a destination pointer.
Definition infix.h:290
c23_nodiscard void * infix_arena_alloc(infix_arena_t *, size_t, size_t)
Allocates a block of memory from the arena with a specific alignment.
Definition arena.c:86
c23_nodiscard infix_arena_t * infix_arena_create(size_t)
Creates and initializes a new memory arena.
Definition arena.c:41
infix_status
An enumeration of all possible success or failure codes from the public API.
Definition infix.h:351
@ INFIX_ERROR_ALLOCATION_FAILED
A memory allocation request failed.
Definition infix.h:353
@ INFIX_SUCCESS
The operation completed successfully.
Definition infix.h:352
@ INFIX_ERROR_INVALID_ARGUMENT
An invalid argument was provided to a function.
Definition infix.h:354
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 infix_type for a packed struct from an arena.
Definition types.c:519
c23_nodiscard infix_type * infix_type_create_void(void)
Creates an infix_type descriptor for the void type.
Definition types.c:153
c23_nodiscard infix_status infix_type_create_union(infix_arena_t *, infix_type **, infix_struct_member *, size_t)
Creates a new infix_type for a union from an arena.
Definition types.c:392
c23_nodiscard infix_status infix_type_create_enum(infix_arena_t *, infix_type **, infix_type *)
Creates a new infix_type for an enum from an arena.
Definition types.c:289
c23_nodiscard infix_status infix_type_create_vector(infix_arena_t *, infix_type **, infix_type *, size_t)
Creates a new infix_type for a SIMD vector from an arena.
Definition types.c:354
c23_nodiscard infix_type * infix_type_create_pointer(void)
Creates an infix_type descriptor for a generic void* pointer.
Definition types.c:145
c23_nodiscard infix_status infix_type_create_complex(infix_arena_t *, infix_type **, infix_type *)
Creates a new infix_type for a _Complex number from an arena.
Definition types.c:324
c23_nodiscard infix_status infix_type_create_array(infix_arena_t *, infix_type **, infix_type *, size_t)
Creates a new infix_type for a fixed-size array from an arena.
Definition types.c:254
c23_nodiscard infix_status infix_type_create_pointer_to(infix_arena_t *, infix_type **, infix_type *)
Creates an infix_type for a pointer to a specific type from an arena.
Definition types.c:230
c23_nodiscard infix_status infix_type_create_struct(infix_arena_t *, infix_type **, infix_struct_member *, size_t)
Creates a new infix_type for a struct from an arena.
Definition types.c:445
c23_nodiscard infix_status infix_type_create_named_reference(infix_arena_t *, infix_type **, const char *, infix_aggregate_category_t)
Creates a new infix_type for a named reference from an arena.
Definition types.c:563
c23_nodiscard infix_type * infix_type_create_primitive(infix_primitive_type_id)
Creates an infix_type descriptor for a primitive C type.
Definition types.c:97
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:161
@ INFIX_PRIMITIVE_UINT16
unsigned short, uint16_t
Definition infix.h:137
@ INFIX_PRIMITIVE_UINT32
unsigned int, uint32_t
Definition infix.h:139
@ INFIX_PRIMITIVE_LONG_DOUBLE
long double
Definition infix.h:147
@ INFIX_PRIMITIVE_FLOAT
float
Definition infix.h:145
@ INFIX_PRIMITIVE_DOUBLE
double
Definition infix.h:146
@ INFIX_PRIMITIVE_SINT16
signed short, int16_t
Definition infix.h:138
@ INFIX_PRIMITIVE_SINT64
signed long long, int64_t
Definition infix.h:142
@ INFIX_PRIMITIVE_SINT32
signed int, int32_t
Definition infix.h:140
@ INFIX_PRIMITIVE_UINT8
unsigned char, uint8_t
Definition infix.h:135
@ INFIX_PRIMITIVE_UINT128
__uint128_t (GCC/Clang specific)
Definition infix.h:143
@ INFIX_PRIMITIVE_BOOL
bool or _Bool
Definition infix.h:134
@ INFIX_PRIMITIVE_UINT64
unsigned long long, uint64_t
Definition infix.h:141
@ INFIX_PRIMITIVE_SINT128
__int128_t (GCC/Clang specific)
Definition infix.h:144
@ INFIX_PRIMITIVE_SINT8
signed char, int8_t
Definition infix.h:136
@ INFIX_TYPE_UNION
A user-defined union (union).
Definition infix.h:118
@ INFIX_TYPE_PRIMITIVE
A built-in type like int, float, double.
Definition infix.h:115
@ INFIX_TYPE_COMPLEX
A _Complex number type.
Definition infix.h:122
@ INFIX_TYPE_ARRAY
A fixed-size array.
Definition infix.h:119
@ INFIX_TYPE_VECTOR
A SIMD vector type.
Definition infix.h:123
@ INFIX_TYPE_VOID
The void type, used for function returns with no value.
Definition infix.h:125
@ INFIX_TYPE_POINTER
A generic void* pointer type.
Definition infix.h:116
@ INFIX_TYPE_NAMED_REFERENCE
A reference to a named type (e.g., struct<Node>).
Definition infix.h:124
@ INFIX_TYPE_REVERSE_TRAMPOLINE
A callback wrapper.
Definition infix.h:120
@ INFIX_TYPE_ENUM
A C-style enumeration, with an underlying integer type.
Definition infix.h:121
@ INFIX_TYPE_STRUCT
A user-defined structure (struct).
Definition infix.h:117
@ INFIX_AGGREGATE_STRUCT
Definition infix.h:151
Declarations for internal-only functions, types, and constants.
c23_nodiscard infix_status _infix_resolve_type_graph(infix_type **, infix_registry_t *)
Walks a type graph, replacing all @Name placeholders with their concrete definitions from a registry.
Definition type_registry.c:398
void _infix_set_error(infix_error_category_t, infix_error_code_t, size_t)
Sets the thread-local error details for a library-internal error.
Definition error.c:44
void _infix_clear_error(void)
Resets the thread-local error state. Called at the start of every public API function.
Definition error.c:76
static void _print(printer_state *state, const char *fmt,...)
Definition signature.c:1199
static infix_type * parse_vector_type(parser_state *)
Definition signature.c:458
static infix_struct_member * parse_aggregate_members(parser_state *state, char end_char, size_t *out_num_members)
Definition signature.c:308
static bool is_function_signature_ahead(const parser_state *state)
Definition signature.c:262
#define MAX_RECURSION_DEPTH
Definition signature.c:69
static infix_status parse_function_signature_details(parser_state *, infix_type **, infix_function_argument **, size_t *, size_t *)
Definition signature.c:662
static infix_type * parse_primitive(parser_state *)
Definition signature.c:590
static bool parse_size_t(parser_state *state, size_t *out_val)
Definition signature.c:145
static infix_type * parse_packed_struct(parser_state *)
Definition signature.c:403
static void set_parser_error(parser_state *state, infix_error_code_t code)
Definition signature.c:106
static bool consume_keyword(parser_state *state, const char *keyword)
Definition signature.c:208
static infix_type * parse_type(parser_state *)
Definition signature.c:819
static infix_type * parse_function_type(parser_state *)
Definition signature.c:506
static const char * parse_identifier(parser_state *state)
Definition signature.c:169
static void _infix_type_print_signature_recursive(printer_state *state, const infix_type *type)
Definition signature.c:1223
static const char * parse_optional_name_prefix(parser_state *state)
Definition signature.c:234
static void skip_whitespace(parser_state *state)
Definition signature.c:119
static infix_type * parse_aggregate(parser_state *, char, char)
Definition signature.c:542
c23_nodiscard infix_status _infix_parse_type_internal(infix_type **out_type, infix_arena_t **out_arena, const char *signature, infix_registry_t *registry)
The core, non-resolving entry point for the signature parser.
Definition signature.c:1040
Definition infix_internals.h:130
Describes a single argument to a function, pairing an optional name with its type.
Definition infix.h:229
infix_type * type
An infix_type describing the argument's type.
Definition infix.h:231
Definition infix_internals.h:158
Describes a single member of an aggregate type (struct or union).
Definition infix.h:219
infix_type * type
An infix_type describing the member's type.
Definition infix.h:221
The central structure for describing any data type in the FFI system.
Definition infix.h:161
struct infix_type_t::@0::@1 pointer_info
For INFIX_TYPE_POINTER.
union infix_type_t::@0 meta
Type-specific metadata.
struct infix_type_t::@0::@7 vector_info
For INFIX_TYPE_VECTOR.
struct infix_type_t::@0::@4 func_ptr_info
For INFIX_TYPE_REVERSE_TRAMPOLINE.
size_t num_elements
The number of elements in the array.
Definition infix.h:183
infix_struct_member * members
Array of members for the aggregate.
Definition infix.h:177
struct infix_type_t::@0::@6 complex_info
For INFIX_TYPE_COMPLEX.
const char * name
Optional name of the aggregate.
Definition infix.h:176
infix_function_argument * args
Array of function arguments (name and type).
Definition infix.h:188
infix_type_category category
The fundamental category of the type.
Definition infix.h:162
struct infix_type_t::@0::@2 aggregate_info
For INFIX_TYPE_STRUCT and INFIX_TYPE_UNION.
struct infix_type_t::@0::@3 array_info
For INFIX_TYPE_ARRAY.
struct infix_type_t * pointee_type
The type this pointer points to.
Definition infix.h:172
struct infix_type_t * element_type
The type of elements in the array.
Definition infix.h:182
struct infix_type_t * return_type
Reverse trampoline return value.
Definition infix.h:187
struct infix_type_t::@0::@5 enum_info
For INFIX_TYPE_ENUM.
struct infix_type_t * base_type
The floating point type of the real and imaginary parts.
Definition infix.h:198
size_t num_members
Number of members in the aggregate.
Definition infix.h:178
struct infix_type_t * underlying_type
The integer type this enum is based on.
Definition infix.h:194
struct infix_type_t::@0::@8 named_reference
For INFIX_TYPE_NAMED_REFERENCE. This is an internal placeholder for a named type like @Point.
size_t num_fixed_args
The number of non-variadic arguments.
Definition infix.h:190
infix_primitive_type_id primitive_id
For INFIX_TYPE_PRIMITIVE.
Definition infix.h:169
size_t num_args
The total number of fixed and variadic arguments.
Definition infix.h:189
bool is_arena_allocated
If true, this type was allocated from an arena and should not be individually freed.
Definition infix.h:165
Definition signature.c:79
const char * start
Definition signature.c:81
infix_registry_t * registry
Definition signature.c:83
infix_arena_t * arena
Definition signature.c:82
int depth
Definition signature.c:84
const char * p
Definition signature.c:80
Definition signature.c:1189
char * p
Definition signature.c:1190
size_t remaining
Definition signature.c:1191
infix_status status
Definition signature.c:1192