From f09d759b0528f7337f5a8944593fc73c8297182b Mon Sep 17 00:00:00 2001 From: Abdelrahman Date: Sun, 7 Sep 2025 06:09:43 +0100 Subject: [PATCH] Start working on codegen implementation in C --- Makefile | 7 +- ccodegen/datatypes.c | 120 ++++ ccodegen/datatypes.h | 236 +++++++ ccodegen/dbl_list.c | 1526 +++++++++++++++++++++++++++++++++++++++++ ccodegen/dbl_list.h | 222 ++++++ ccodegen/main.c | 7 + ccodegen/type_enums.h | 84 +++ 7 files changed, 2200 insertions(+), 2 deletions(-) create mode 100644 ccodegen/datatypes.c create mode 100644 ccodegen/datatypes.h create mode 100644 ccodegen/dbl_list.c create mode 100644 ccodegen/dbl_list.h create mode 100644 ccodegen/main.c create mode 100644 ccodegen/type_enums.h diff --git a/Makefile b/Makefile index 10168e9..d40ccee 100644 --- a/Makefile +++ b/Makefile @@ -43,9 +43,9 @@ ifeq ($(CC),gcc) export ASAN_OPTIONS=verify_asan_link_order=0 endif -.PHONY: help full prng testing uuid core primitives all clean builddir build-test run-test codegen install build-lib +.PHONY: help full prng testing uuid core primitives all clean builddir build-test run-test codegen install build-lib ccodegen -all: clean builddir codegen run-c-test full run-cc-test +all: clean builddir codegen run-c-test full run-cc-test ccodegen help: @echo "Available build variables:" @@ -126,3 +126,6 @@ build-lib: builddir $(CC) -c $(CSTD) $(CFLAGS) $(LIBFLAGS) $(LIB_SRC) -o $(OBJ_OUT) $(AR) r $(LIB_OUT) $(OBJ_OUT) @rm $(OBJ_OUT) + +ccodegen: + $(CC) $(CSTD) $(CFLAGS) $(LIBFLAGS) -Isrc/core src/core/wapp_core.c ccodegen/*.c -o ccgen diff --git a/ccodegen/datatypes.c b/ccodegen/datatypes.c new file mode 100644 index 0000000..0aa5579 --- /dev/null +++ b/ccodegen/datatypes.c @@ -0,0 +1,120 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#include "datatypes.h" +#include "type_enums.h" +#include "wapp_core.h" + +#define ERR_MSG "Not enough capacity in dst buffer" + +internal inline void ctype_to_string(Str8 *dst, CType ctype); +internal inline void cqualifier_to_string(Str8 *dst, CQualifier cqualifier); +internal inline void cpointertype_to_string(Str8 *dst, CPointerType cpointertype); +internal inline void cpointer_to_string(Str8 *dst, const CPointer *cpointer); +internal inline void cenumval_to_string(Str8 *dst, const CEnumVal *cenumval); +internal inline void cmacro_to_string(Str8 *dst, const CMacro *cmacro); + +void cobject_to_string(Str8 *dst, const CObject *object) { + wapp_debug_assert(dst != NULL object != NULL, "`allocator`, `dst` and `object` should not be NULL"); + + if (object->kind >= COUNT_COBJECTKIND) { + return; + } + + switch (object->kind) { + case COBJECT_CTYPE: + ctype_to_string(dst, object->object.c_type); + break; + case COBJECT_CQUALIFIER: + cqualifier_to_string(dst, object->object.c_qualifier); + break; + case COBJECT_CPOINTERTYPE: + cpointertype_to_string(dst, object->object.c_pointertype); + break; + case COBJECT_CPOINTER: + cpointer_to_string(dst, &(object->object.c_pointer)); + break; + case COBJECT_CENUMVAL: + cenumval_to_string(dst, &(object->object.c_enumval)); + break; + case COBJECT_CENUM: + break; + case COBJECT_CMACRO: + cmacro_to_string(dst, &(object->object.c_macro)); + break; + case COBJECT_CSTRUCT: + break; + case COBJECT_CUSERTYPE: + break; + case COBJECT_CDATATYPE: + break; + case COBJECT_CARG: + break; + case COBJECT_CFUNC: + break; + case COBJECT_CINCULDE: + break; + case COBJECT_CHEADER: + break; + case COBJECT_CSOURCE: + break; + default: + break; + } +} + +internal inline void ctype_to_string(Str8 *dst, CType ctype) { + wapp_runtime_assert(ctypes[ctype].size <= dst->capacity, ERR_MSG); + wapp_str8_copy_str8_capped(dst, &ctypes[ctype]); +} + +internal inline void cqualifier_to_string(Str8 *dst, CQualifier cqualifier) { + wapp_runtime_assert(cqualifiers[cqualifier].size <= dst->capacity, ERR_MSG); + wapp_str8_copy_str8_capped(dst, &cqualifiers[cqualifier]); +} + +internal inline void cpointertype_to_string(Str8 *dst, CPointerType cpointertype) { + wapp_runtime_assert(cpointertypes[cpointertype].size <= dst->capacity, ERR_MSG); + wapp_str8_copy_str8_capped(dst, &cpointertypes[cpointertype]); +} + +internal inline void cpointer_to_string(Str8 *dst, const CPointer *cpointer) { + wapp_debug_assert(dst != NULL && cpointer != NULL, "`dst` and `cpointer` should not be NULL"); + + u64 total_size = cpointertypes[cpointer->type].size + cqualifiers[cpointer->qualifier].size; + wapp_runtime_assert(total_size <= dst->capacity, ERR_MSG); + wapp_str8_format(dst, + WAPP_STR8_SPEC WAPP_STR8_SPEC, + wapp_str8_varg(cpointertypes[cpointer->type]), + wapp_str8_varg(cqualifiers[cpointer->qualifier])); +} + +internal inline void cenumval_to_string(Str8 *dst, const CEnumVal *cenumval) { + wapp_debug_assert(dst != NULL && cenumval != NULL, "`dst` and `cenumval` should not be NULL"); + + Str8 tmp = wapp_str8_buf(32); + u64 tmp_size = 0; + if (cenumval->value != NULL) { + wapp_str8_format(&tmp, " = %d", *(cenumval->value)); + tmp_size = tmp.size; + } + + u64 total_size = cenumval->name.size + tmp_size; + wapp_runtime_assert(total_size <= dst->capacity, ERR_MSG); + wapp_str8_format(dst, + WAPP_STR8_SPEC WAPP_STR8_SPEC, + wapp_str8_varg(cenumval->name), + wapp_str8_varg(tmp)); +} + +internal inline void cmacro_to_string(Str8 *dst, const CMacro *cmacro) { + wapp_debug_assert(dst != NULL && cenumval != NULL, "`dst` and `cmacro` should not be NULL"); + + Str8 def = wapp_str8_lit("#define "); + u64 total_size = def.size + cmacro->name.size + cmacro->value.size + 1; // Add 1 for newline + wapp_runtime_assert(total_size <= dst->capacity, ERR_MSG); + wapp_str8_format(dst, + WAPP_STR8_SPEC WAPP_STR8_SPEC " " WAPP_STR8_SPEC "\n", + wapp_str8_varg(def), + wapp_str8_varg(cmacro->name), + wapp_str8_varg(cmacro->value)); +} diff --git a/ccodegen/datatypes.h b/ccodegen/datatypes.h new file mode 100644 index 0000000..4dc2533 --- /dev/null +++ b/ccodegen/datatypes.h @@ -0,0 +1,236 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#ifndef DATATYPES_H +#define DATATYPES_H + +#include "wapp_core.h" +#include "dbl_list.h" +#include "type_enums.h" + +#define CENUM(NAME, VALUES, TYPEDEF) ((CEnum){ .name = (NAME), .values = (VALUES), .add_typedef = (TYPEDEF) }) +#define CSTRUCT(NAME, ARGS, TYPEDEF_NAME_PTR) ((CStruct){ .name = (NAME), .args = (ARGS), .typedef_name = (TYPEDEF_NAME_PTR) }) + +#define CUSERTYPE_ENUM(ENUM) ((CUserType){ .kind = CUSERTYPE_CENUM, .type.c_enum = ENUM }) +#define CUSERTYPE_STRUCT(STRUCT) ((CUserType){ .kind = CUSERTYPE_CSTRUCT, .type.c_struct = STRUCT }) + +#define CDATATYPE_CTYPE(VALUE) ((CDataType){ .kind = CDATATYPE_CTYPE, .type.c_type = (VALUE) }) +#define CDATATYPE_USERTYPE(USERTYPE) ((CDataType){ .kind = CDATATYPE_CUSERTYPE, .type.c_usertype = (USERTYPE) }) +#define CDATATYPE_STR(STR) ((CDataType){ .kind = CDATATYPE_STR, .type.str = (STR) }) + +#define CHEADERINCLUDE_STR(NAME) ((CHeaderInclude){ .kind = C_HEADER_INCLUDE_STR, .header.name = (NAME) }) +#define CHEADERINCLUDE_CHEADER(CHEADER) ((CHeaderInclude){ .kind = C_HEADER_INCLUDE_HEADER, .header.header = (CHEADER) }) + +#define COBJECT_TYPE(VALUE) \ + ((CObject){ .kind = COBJECT_CTYPE, .object.c_type = (VALUE) }) +#define COBJECT_QUALIFIER(VALUE) \ + ((CObject){ .kind = COBJECT_CQUALIFIER, .object.c_qualifier = (VALUE) }) +#define COBJECT_POINTERTYPE(VALUE) \ + ((CObject){ .kind = COBJECT_CPOINTERTYPE, .object.c_pointertype = (VALUE) }) +#define COBJECT_POINTER(CPOINTER) \ + ((CObject){ .kind = COBJECT_CPOINTER, .object.c_pointer = (CPOINTER) }) +#define COBJECT_ENUMVAL(CENUMVAL) \ + ((CObject){ .kind = COBJECT_CENUMVAL, .object.c_enumval = (CENUMVAL) }) +#define COBJECT_ENUM(ENUM) \ + ((CObject){ .kind = COBJECT_CENUM, .object.c_enum = (ENUM) }) +#define COBJECT_MACRO(CMACRO) \ + ((CObject){ .kind = COBJECT_CMACRO, .object.c_macro = (CMACRO) }) +#define COBJECT_STRUCT(STRUCT) \ + ((CObject){ .kind = COBJECT_CSTRUCT, .object.c_struct = STRUCT }) +#define COBJECT_USERTYPE(USERTYPE) \ + ((CObject){ .kind = COBJECT_CUSERTYPE, .object.c_usertype = (USERTYPE) }) +#define COBJECT_DATATYPE(DATATYPE) \ + ((CObject){ .kind = COBJECT_CDATATYPE, .object.c_datatype = (DATATYPE) }) +#define COBJECT_ARG(CARG) \ + ((CObject){ .kind = COBJECT_CARG, .object.c_arg = (CARG) }) +#define COBJECT_FUNC(CFUNC) \ + ((CObject){ .kind = COBJECT_CFUNC, .object.c_func = (CFUNC) }) +#define COBJECT_INCULDE(CINCLUDE) \ + ((CObject){ .kind = COBJECT_CINCULDE, .object.c_include = (CINCLUDE) }) +#define COBJECT_HEADER(CHEADER) \ + ((CObject){ .kind = COBJECT_CHEADER, .object.c_header = (CHEADER) }) +#define COBJECT_SOURCE(CSOURCE) \ + ((CObject){ .kind = COBJECT_CSOURCE, .object.c_source = (CSOURCE) }) + +typedef enum { + CUSERTYPE_CENUM, + CUSERTYPE_CSTRUCT, + + COUNT_CUSERTYPEKIND, +} CUserTypeKind; + +typedef enum { + CDATATYPE_CTYPE, + CDATATYPE_CUSERTYPE, + CDATATYPE_STR, + + COUNT_CDATATYPEKIND, +} CDataTypeKind; + +typedef enum { + CFILE_EXT_H, + CFILE_EXT_C, + + COUNT_CFILE_EXT, +} CFileExtension; + +typedef enum { + C_HEADER_INCLUDE_STR, + C_HEADER_INCLUDE_HEADER, + + COUNT_CHEADERINCLUDEKIND, +} CHeaderIncludeKind; + +typedef enum { + COBJECT_CTYPE, + COBJECT_CQUALIFIER, + COBJECT_CPOINTERTYPE, + COBJECT_CPOINTER, + COBJECT_CENUMVAL, + COBJECT_CENUM, + COBJECT_CMACRO, + COBJECT_CSTRUCT, + COBJECT_CUSERTYPE, + COBJECT_CDATATYPE, + COBJECT_CARG, + COBJECT_CFUNC, + COBJECT_CINCULDE, + COBJECT_CHEADER, + COBJECT_CSOURCE, + + COUNT_COBJECTKIND, +} CObjectKind; + +typedef struct cpointer CPointer; +typedef struct cenumval CEnumVal; +typedef struct cenum CEnum; +typedef struct cmacro CMacro; +typedef struct cstruct CStruct; +typedef struct cusertype CUserType; +typedef struct cdatatype CDataType; +typedef struct carg CArg; +typedef struct cfunc CFunc; +typedef struct cheader_include CHeaderInclude; +typedef struct cinclude CInclude; +typedef struct cheader CHeader; +typedef struct csource CSource; +typedef struct cobject CObject; + +struct cpointer { + CPointerType type; + CQualifier qualifier; +}; + +struct cenumval { + Str8 name; + i32 *value; +}; + +struct cenum { + Str8 name; + CEnumValList values; + b32 add_typedef; +}; + +struct cmacro { + Str8 name; + Str8 value; +}; + +struct cstruct { + Str8 name; + CArgList args; + Str8 *typedef_name; +}; + +struct cusertype { + CUserTypeKind kind; + union { + CEnum c_enum; + CStruct c_struct; + } type; +}; + +struct cdatatype { + CDataTypeKind kind; + union { + CType c_type; + CUserType c_usertype; + Str8 str; + } type; +}; + +struct carg { + Str8 name; + CDataType type; + CPointer pointer; + CQualifier qualifier; + b32 is_array; +}; + +struct cfunc { + Str8 name; + CDataType ret_type; + CArgList args; + Str8 body; + CPointer pointer; + CQualifierList qualifiers; +}; + +#define CFILE_ARGS \ + Str8 name; \ + CFileExtension extension; \ + CIncludeList includes; \ + CUserTypeList types; \ + CFuncList funcs; \ + CStructList decl_types; \ + CMacroList macros; \ + CMacroList c_macros; \ + CMacroList cpp_macros \ + +struct cheader { + CFILE_ARGS; +}; + +struct csource { + CFILE_ARGS; + CFuncList internal_funcs; +}; + +struct cheader_include { + CHeaderIncludeKind kind; + union { + Str8 name; + CHeader header; + } header; +}; + +struct cinclude { + CHeaderInclude header; + b32 is_local; + b32 same_dir; +}; + +struct cobject { + CObjectKind kind; + union { + CType c_type; + CQualifier c_qualifier; + CPointerType c_pointertype; + CPointer c_pointer; + CEnumVal c_enumval; + CEnum c_enum; + CMacro c_macro; + CStruct c_struct; + CUserType c_usertype; + CDataType c_datatype; + CArg c_arg; + CFunc c_func; + CInclude c_include; + CHeader c_header; + CSource c_source; + } object; +}; + +void cobject_to_string(Str8 *dst, const CObject *object); + +#endif // !DATATYPES_H diff --git a/ccodegen/dbl_list.c b/ccodegen/dbl_list.c new file mode 100644 index 0000000..d479933 --- /dev/null +++ b/ccodegen/dbl_list.c @@ -0,0 +1,1526 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#include "./dbl_list.h" +#include "wapp_core.h" +#include + +internal CEnumValList cenumval_node_to_list(CEnumValNode *node); +internal CArgList carg_node_to_list(CArgNode *node); +internal CQualifierList cqualifier_node_to_list(CQualifierNode *node); +internal CIncludeList cinclude_node_to_list(CIncludeNode *node); +internal CUserTypeList cusertype_node_to_list(CUserTypeNode *node); +internal CFuncList cfunc_node_to_list(CFuncNode *node); +internal CStructList cstruct_node_to_list(CStructNode *node); +internal CMacroList cmacro_node_to_list(CMacroNode *node); + +CEnumValNode *wapp_cenumval_list_get(const CEnumValList *list, u64 index) { + wapp_runtime_assert(index < list->node_count, "`index` is out of bounds"); + + CEnumValNode *output = NULL; + CEnumValNode *current = list->first; + for (u64 i = 1; i <= index; ++i) { + current = current->next; + } + + output = current; + + return output; +} + +void wapp_cenumval_list_push_front(CEnumValList *list, CEnumValNode *node) { + wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL"); + + CEnumValList node_list = cenumval_node_to_list(node); + + if (list->node_count == 0) { + *list = node_list; + return; + } + + list->node_count += node_list.node_count; + + CEnumValNode *first = list->first; + if (first) { + first->prev = node_list.last; + } + + list->first = node_list.first; + node_list.last->next = first; +} + +void wapp_cenumval_list_push_back(CEnumValList *list, CEnumValNode *node) { + wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL"); + + CEnumValList node_list = cenumval_node_to_list(node); + + if (list->node_count == 0) { + *list = node_list; + return; + } + + list->node_count += node_list.node_count; + + CEnumValNode *last = list->last; + if (last) { + last->next = node_list.first; + } + + list->last = node_list.last; + node_list.first->prev = last; +} + +void wapp_cenumval_list_insert(CEnumValList *list, CEnumValNode *node, u64 index) { + wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL"); + + if (index == 0) { + wapp_cenumval_list_push_front(list, node); + return; + } else if (index == list->node_count) { + wapp_cenumval_list_push_back(list, node); + return; + } + + CEnumValNode *dst_node = wapp_cenumval_list_get(list, index); + if (!dst_node) { + return; + } + + CEnumValList node_list = cenumval_node_to_list(node); + + list->node_count += node_list.node_count; + + CEnumValNode *prev = dst_node->prev; + + dst_node->prev = node_list.last; + prev->next = node_list.first; + + node_list.first->prev = prev; + node_list.last->next = dst_node; +} + +CEnumValNode *wapp_cenumval_list_pop_front(CEnumValList *list) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + CEnumValNode *output = NULL; + + if (list->node_count == 0) { + goto RETURN_CENUMVAL_LIST_POP_FRONT; + } + + output = list->first; + + if (list->node_count == 1) { + *list = (CEnumValList){0}; + goto RETURN_CENUMVAL_LIST_POP_FRONT; + } + + --(list->node_count); + list->first = output->next; + + output->prev = output->next = NULL; + +RETURN_CENUMVAL_LIST_POP_FRONT: + return output; +} + +CEnumValNode *wapp_cenumval_list_pop_back(CEnumValList *list) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + CEnumValNode *output = NULL; + + if (list->node_count == 0) { + goto RETURN_CENUMVAL_LIST_POP_BACK; + } + + output = list->last; + + if (list->node_count == 1) { + *list = (CEnumValList){0}; + goto RETURN_CENUMVAL_LIST_POP_BACK; + } + + --(list->node_count); + list->last = output->prev; + + output->prev = output->next = NULL; + +RETURN_CENUMVAL_LIST_POP_BACK: + return output; +} + +CEnumValNode *wapp_cenumval_list_remove(CEnumValList *list, u64 index) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + CEnumValNode *output = NULL; + + if (index == 0) { + output = wapp_cenumval_list_pop_front(list); + goto RETURN_CENUMVAL_LIST_REMOVE; + } else if (index == list->node_count) { + output = wapp_cenumval_list_pop_back(list); + goto RETURN_CENUMVAL_LIST_REMOVE; + } + + output = wapp_cenumval_list_get(list, index); + if (!output) { + goto RETURN_CENUMVAL_LIST_REMOVE; + } + + output->prev->next = output->next; + output->next->prev = output->prev; + + --(list->node_count); + + output->prev = output->next = NULL; + +RETURN_CENUMVAL_LIST_REMOVE: + return output; +} + +void wapp_cenumval_list_empty(CEnumValList *list) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + u64 count = list->node_count; + for (u64 i = 0; i < count; ++i) { + wapp_cenumval_list_pop_back(list); + } +} + +CArgNode *wapp_carg_list_get(const CArgList *list, u64 index) { + wapp_runtime_assert(index < list->node_count, "`index` is out of bounds"); + + CArgNode *output = NULL; + CArgNode *current = list->first; + for (u64 i = 1; i <= index; ++i) { + current = current->next; + } + + output = current; + + return output; +} + +void wapp_carg_list_push_front(CArgList *list, CArgNode *node) { + wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL"); + + CArgList node_list = carg_node_to_list(node); + + if (list->node_count == 0) { + *list = node_list; + return; + } + + list->node_count += node_list.node_count; + + CArgNode *first = list->first; + if (first) { + first->prev = node_list.last; + } + + list->first = node_list.first; + node_list.last->next = first; +} + +void wapp_carg_list_push_back(CArgList *list, CArgNode *node) { + wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL"); + + CArgList node_list = carg_node_to_list(node); + + if (list->node_count == 0) { + *list = node_list; + return; + } + + list->node_count += node_list.node_count; + + CArgNode *last = list->last; + if (last) { + last->next = node_list.first; + } + + list->last = node_list.last; + node_list.first->prev = last; +} + +void wapp_carg_list_insert(CArgList *list, CArgNode *node, u64 index) { + wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL"); + + if (index == 0) { + wapp_carg_list_push_front(list, node); + return; + } else if (index == list->node_count) { + wapp_carg_list_push_back(list, node); + return; + } + + CArgNode *dst_node = wapp_carg_list_get(list, index); + if (!dst_node) { + return; + } + + CArgList node_list = carg_node_to_list(node); + + list->node_count += node_list.node_count; + + CArgNode *prev = dst_node->prev; + + dst_node->prev = node_list.last; + prev->next = node_list.first; + + node_list.first->prev = prev; + node_list.last->next = dst_node; +} + +CArgNode *wapp_carg_list_pop_front(CArgList *list) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + CArgNode *output = NULL; + + if (list->node_count == 0) { + goto RETURN_CARG_LIST_POP_FRONT; + } + + output = list->first; + + if (list->node_count == 1) { + *list = (CArgList){0}; + goto RETURN_CARG_LIST_POP_FRONT; + } + + --(list->node_count); + list->first = output->next; + + output->prev = output->next = NULL; + +RETURN_CARG_LIST_POP_FRONT: + return output; +} + +CArgNode *wapp_carg_list_pop_back(CArgList *list) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + CArgNode *output = NULL; + + if (list->node_count == 0) { + goto RETURN_CARG_LIST_POP_BACK; + } + + output = list->last; + + if (list->node_count == 1) { + *list = (CArgList){0}; + goto RETURN_CARG_LIST_POP_BACK; + } + + --(list->node_count); + list->last = output->prev; + + output->prev = output->next = NULL; + +RETURN_CARG_LIST_POP_BACK: + return output; +} + +CArgNode *wapp_carg_list_remove(CArgList *list, u64 index) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + CArgNode *output = NULL; + + if (index == 0) { + output = wapp_carg_list_pop_front(list); + goto RETURN_CARG_LIST_REMOVE; + } else if (index == list->node_count) { + output = wapp_carg_list_pop_back(list); + goto RETURN_CARG_LIST_REMOVE; + } + + output = wapp_carg_list_get(list, index); + if (!output) { + goto RETURN_CARG_LIST_REMOVE; + } + + output->prev->next = output->next; + output->next->prev = output->prev; + + --(list->node_count); + + output->prev = output->next = NULL; + +RETURN_CARG_LIST_REMOVE: + return output; +} + +void wapp_carg_list_empty(CArgList *list) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + u64 count = list->node_count; + for (u64 i = 0; i < count; ++i) { + wapp_carg_list_pop_back(list); + } +} + +CQualifierNode *wapp_cqualifier_list_get(const CQualifierList *list, u64 index) { + wapp_runtime_assert(index < list->node_count, "`index` is out of bounds"); + + CQualifierNode *output = NULL; + CQualifierNode *current = list->first; + for (u64 i = 1; i <= index; ++i) { + current = current->next; + } + + output = current; + + return output; +} + +void wapp_cqualifier_list_push_front(CQualifierList *list, CQualifierNode *node) { + wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL"); + + CQualifierList node_list = cqualifier_node_to_list(node); + + if (list->node_count == 0) { + *list = node_list; + return; + } + + list->node_count += node_list.node_count; + + CQualifierNode *first = list->first; + if (first) { + first->prev = node_list.last; + } + + list->first = node_list.first; + node_list.last->next = first; +} + +void wapp_cqualifier_list_push_back(CQualifierList *list, CQualifierNode *node) { + wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL"); + + CQualifierList node_list = cqualifier_node_to_list(node); + + if (list->node_count == 0) { + *list = node_list; + return; + } + + list->node_count += node_list.node_count; + + CQualifierNode *last = list->last; + if (last) { + last->next = node_list.first; + } + + list->last = node_list.last; + node_list.first->prev = last; +} + +void wapp_cqualifier_list_insert(CQualifierList *list, CQualifierNode *node, u64 index) { + wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL"); + + if (index == 0) { + wapp_cqualifier_list_push_front(list, node); + return; + } else if (index == list->node_count) { + wapp_cqualifier_list_push_back(list, node); + return; + } + + CQualifierNode *dst_node = wapp_cqualifier_list_get(list, index); + if (!dst_node) { + return; + } + + CQualifierList node_list = cqualifier_node_to_list(node); + + list->node_count += node_list.node_count; + + CQualifierNode *prev = dst_node->prev; + + dst_node->prev = node_list.last; + prev->next = node_list.first; + + node_list.first->prev = prev; + node_list.last->next = dst_node; +} + +CQualifierNode *wapp_cqualifier_list_pop_front(CQualifierList *list) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + CQualifierNode *output = NULL; + + if (list->node_count == 0) { + goto RETURN_CQUALIFIER_LIST_POP_FRONT; + } + + output = list->first; + + if (list->node_count == 1) { + *list = (CQualifierList){0}; + goto RETURN_CQUALIFIER_LIST_POP_FRONT; + } + + --(list->node_count); + list->first = output->next; + + output->prev = output->next = NULL; + +RETURN_CQUALIFIER_LIST_POP_FRONT: + return output; +} + +CQualifierNode *wapp_cqualifier_list_pop_back(CQualifierList *list) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + CQualifierNode *output = NULL; + + if (list->node_count == 0) { + goto RETURN_CQUALIFIER_LIST_POP_BACK; + } + + output = list->last; + + if (list->node_count == 1) { + *list = (CQualifierList){0}; + goto RETURN_CQUALIFIER_LIST_POP_BACK; + } + + --(list->node_count); + list->last = output->prev; + + output->prev = output->next = NULL; + +RETURN_CQUALIFIER_LIST_POP_BACK: + return output; +} + +CQualifierNode *wapp_cqualifier_list_remove(CQualifierList *list, u64 index) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + CQualifierNode *output = NULL; + + if (index == 0) { + output = wapp_cqualifier_list_pop_front(list); + goto RETURN_CQUALIFIER_LIST_REMOVE; + } else if (index == list->node_count) { + output = wapp_cqualifier_list_pop_back(list); + goto RETURN_CQUALIFIER_LIST_REMOVE; + } + + output = wapp_cqualifier_list_get(list, index); + if (!output) { + goto RETURN_CQUALIFIER_LIST_REMOVE; + } + + output->prev->next = output->next; + output->next->prev = output->prev; + + --(list->node_count); + + output->prev = output->next = NULL; + +RETURN_CQUALIFIER_LIST_REMOVE: + return output; +} + +void wapp_cqualifier_list_empty(CQualifierList *list) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + u64 count = list->node_count; + for (u64 i = 0; i < count; ++i) { + wapp_cqualifier_list_pop_back(list); + } +} + +CIncludeNode *wapp_cinclude_list_get(const CIncludeList *list, u64 index) { + wapp_runtime_assert(index < list->node_count, "`index` is out of bounds"); + + CIncludeNode *output = NULL; + CIncludeNode *current = list->first; + for (u64 i = 1; i <= index; ++i) { + current = current->next; + } + + output = current; + + return output; +} + +void wapp_cinclude_list_push_front(CIncludeList *list, CIncludeNode *node) { + wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL"); + + CIncludeList node_list = cinclude_node_to_list(node); + + if (list->node_count == 0) { + *list = node_list; + return; + } + + list->node_count += node_list.node_count; + + CIncludeNode *first = list->first; + if (first) { + first->prev = node_list.last; + } + + list->first = node_list.first; + node_list.last->next = first; +} + +void wapp_cinclude_list_push_back(CIncludeList *list, CIncludeNode *node) { + wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL"); + + CIncludeList node_list = cinclude_node_to_list(node); + + if (list->node_count == 0) { + *list = node_list; + return; + } + + list->node_count += node_list.node_count; + + CIncludeNode *last = list->last; + if (last) { + last->next = node_list.first; + } + + list->last = node_list.last; + node_list.first->prev = last; +} + +void wapp_cinclude_list_insert(CIncludeList *list, CIncludeNode *node, u64 index) { + wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL"); + + if (index == 0) { + wapp_cinclude_list_push_front(list, node); + return; + } else if (index == list->node_count) { + wapp_cinclude_list_push_back(list, node); + return; + } + + CIncludeNode *dst_node = wapp_cinclude_list_get(list, index); + if (!dst_node) { + return; + } + + CIncludeList node_list = cinclude_node_to_list(node); + + list->node_count += node_list.node_count; + + CIncludeNode *prev = dst_node->prev; + + dst_node->prev = node_list.last; + prev->next = node_list.first; + + node_list.first->prev = prev; + node_list.last->next = dst_node; +} + +CIncludeNode *wapp_cinclude_list_pop_front(CIncludeList *list) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + CIncludeNode *output = NULL; + + if (list->node_count == 0) { + goto RETURN_CINCLUDE_LIST_POP_FRONT; + } + + output = list->first; + + if (list->node_count == 1) { + *list = (CIncludeList){0}; + goto RETURN_CINCLUDE_LIST_POP_FRONT; + } + + --(list->node_count); + list->first = output->next; + + output->prev = output->next = NULL; + +RETURN_CINCLUDE_LIST_POP_FRONT: + return output; +} + +CIncludeNode *wapp_cinclude_list_pop_back(CIncludeList *list) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + CIncludeNode *output = NULL; + + if (list->node_count == 0) { + goto RETURN_CINCLUDE_LIST_POP_BACK; + } + + output = list->last; + + if (list->node_count == 1) { + *list = (CIncludeList){0}; + goto RETURN_CINCLUDE_LIST_POP_BACK; + } + + --(list->node_count); + list->last = output->prev; + + output->prev = output->next = NULL; + +RETURN_CINCLUDE_LIST_POP_BACK: + return output; +} + +CIncludeNode *wapp_cinclude_list_remove(CIncludeList *list, u64 index) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + CIncludeNode *output = NULL; + + if (index == 0) { + output = wapp_cinclude_list_pop_front(list); + goto RETURN_CINCLUDE_LIST_REMOVE; + } else if (index == list->node_count) { + output = wapp_cinclude_list_pop_back(list); + goto RETURN_CINCLUDE_LIST_REMOVE; + } + + output = wapp_cinclude_list_get(list, index); + if (!output) { + goto RETURN_CINCLUDE_LIST_REMOVE; + } + + output->prev->next = output->next; + output->next->prev = output->prev; + + --(list->node_count); + + output->prev = output->next = NULL; + +RETURN_CINCLUDE_LIST_REMOVE: + return output; +} + +void wapp_cinclude_list_empty(CIncludeList *list) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + u64 count = list->node_count; + for (u64 i = 0; i < count; ++i) { + wapp_cinclude_list_pop_back(list); + } +} + +CUserTypeNode *wapp_cusertype_list_get(const CUserTypeList *list, u64 index) { + wapp_runtime_assert(index < list->node_count, "`index` is out of bounds"); + + CUserTypeNode *output = NULL; + CUserTypeNode *current = list->first; + for (u64 i = 1; i <= index; ++i) { + current = current->next; + } + + output = current; + + return output; +} + +void wapp_cusertype_list_push_front(CUserTypeList *list, CUserTypeNode *node) { + wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL"); + + CUserTypeList node_list = cusertype_node_to_list(node); + + if (list->node_count == 0) { + *list = node_list; + return; + } + + list->node_count += node_list.node_count; + + CUserTypeNode *first = list->first; + if (first) { + first->prev = node_list.last; + } + + list->first = node_list.first; + node_list.last->next = first; +} + +void wapp_cusertype_list_push_back(CUserTypeList *list, CUserTypeNode *node) { + wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL"); + + CUserTypeList node_list = cusertype_node_to_list(node); + + if (list->node_count == 0) { + *list = node_list; + return; + } + + list->node_count += node_list.node_count; + + CUserTypeNode *last = list->last; + if (last) { + last->next = node_list.first; + } + + list->last = node_list.last; + node_list.first->prev = last; +} + +void wapp_cusertype_list_insert(CUserTypeList *list, CUserTypeNode *node, u64 index) { + wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL"); + + if (index == 0) { + wapp_cusertype_list_push_front(list, node); + return; + } else if (index == list->node_count) { + wapp_cusertype_list_push_back(list, node); + return; + } + + CUserTypeNode *dst_node = wapp_cusertype_list_get(list, index); + if (!dst_node) { + return; + } + + CUserTypeList node_list = cusertype_node_to_list(node); + + list->node_count += node_list.node_count; + + CUserTypeNode *prev = dst_node->prev; + + dst_node->prev = node_list.last; + prev->next = node_list.first; + + node_list.first->prev = prev; + node_list.last->next = dst_node; +} + +CUserTypeNode *wapp_cusertype_list_pop_front(CUserTypeList *list) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + CUserTypeNode *output = NULL; + + if (list->node_count == 0) { + goto RETURN_CUSERTYPE_LIST_POP_FRONT; + } + + output = list->first; + + if (list->node_count == 1) { + *list = (CUserTypeList){0}; + goto RETURN_CUSERTYPE_LIST_POP_FRONT; + } + + --(list->node_count); + list->first = output->next; + + output->prev = output->next = NULL; + +RETURN_CUSERTYPE_LIST_POP_FRONT: + return output; +} + +CUserTypeNode *wapp_cusertype_list_pop_back(CUserTypeList *list) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + CUserTypeNode *output = NULL; + + if (list->node_count == 0) { + goto RETURN_CUSERTYPE_LIST_POP_BACK; + } + + output = list->last; + + if (list->node_count == 1) { + *list = (CUserTypeList){0}; + goto RETURN_CUSERTYPE_LIST_POP_BACK; + } + + --(list->node_count); + list->last = output->prev; + + output->prev = output->next = NULL; + +RETURN_CUSERTYPE_LIST_POP_BACK: + return output; +} + +CUserTypeNode *wapp_cusertype_list_remove(CUserTypeList *list, u64 index) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + CUserTypeNode *output = NULL; + + if (index == 0) { + output = wapp_cusertype_list_pop_front(list); + goto RETURN_CUSERTYPE_LIST_REMOVE; + } else if (index == list->node_count) { + output = wapp_cusertype_list_pop_back(list); + goto RETURN_CUSERTYPE_LIST_REMOVE; + } + + output = wapp_cusertype_list_get(list, index); + if (!output) { + goto RETURN_CUSERTYPE_LIST_REMOVE; + } + + output->prev->next = output->next; + output->next->prev = output->prev; + + --(list->node_count); + + output->prev = output->next = NULL; + +RETURN_CUSERTYPE_LIST_REMOVE: + return output; +} + +void wapp_cusertype_list_empty(CUserTypeList *list) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + u64 count = list->node_count; + for (u64 i = 0; i < count; ++i) { + wapp_cusertype_list_pop_back(list); + } +} + +CFuncNode *wapp_cfunc_list_get(const CFuncList *list, u64 index) { + wapp_runtime_assert(index < list->node_count, "`index` is out of bounds"); + + CFuncNode *output = NULL; + CFuncNode *current = list->first; + for (u64 i = 1; i <= index; ++i) { + current = current->next; + } + + output = current; + + return output; +} + +void wapp_cfunc_list_push_front(CFuncList *list, CFuncNode *node) { + wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL"); + + CFuncList node_list = cfunc_node_to_list(node); + + if (list->node_count == 0) { + *list = node_list; + return; + } + + list->node_count += node_list.node_count; + + CFuncNode *first = list->first; + if (first) { + first->prev = node_list.last; + } + + list->first = node_list.first; + node_list.last->next = first; +} + +void wapp_cfunc_list_push_back(CFuncList *list, CFuncNode *node) { + wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL"); + + CFuncList node_list = cfunc_node_to_list(node); + + if (list->node_count == 0) { + *list = node_list; + return; + } + + list->node_count += node_list.node_count; + + CFuncNode *last = list->last; + if (last) { + last->next = node_list.first; + } + + list->last = node_list.last; + node_list.first->prev = last; +} + +void wapp_cfunc_list_insert(CFuncList *list, CFuncNode *node, u64 index) { + wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL"); + + if (index == 0) { + wapp_cfunc_list_push_front(list, node); + return; + } else if (index == list->node_count) { + wapp_cfunc_list_push_back(list, node); + return; + } + + CFuncNode *dst_node = wapp_cfunc_list_get(list, index); + if (!dst_node) { + return; + } + + CFuncList node_list = cfunc_node_to_list(node); + + list->node_count += node_list.node_count; + + CFuncNode *prev = dst_node->prev; + + dst_node->prev = node_list.last; + prev->next = node_list.first; + + node_list.first->prev = prev; + node_list.last->next = dst_node; +} + +CFuncNode *wapp_cfunc_list_pop_front(CFuncList *list) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + CFuncNode *output = NULL; + + if (list->node_count == 0) { + goto RETURN_CFUNC_LIST_POP_FRONT; + } + + output = list->first; + + if (list->node_count == 1) { + *list = (CFuncList){0}; + goto RETURN_CFUNC_LIST_POP_FRONT; + } + + --(list->node_count); + list->first = output->next; + + output->prev = output->next = NULL; + +RETURN_CFUNC_LIST_POP_FRONT: + return output; +} + +CFuncNode *wapp_cfunc_list_pop_back(CFuncList *list) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + CFuncNode *output = NULL; + + if (list->node_count == 0) { + goto RETURN_CFUNC_LIST_POP_BACK; + } + + output = list->last; + + if (list->node_count == 1) { + *list = (CFuncList){0}; + goto RETURN_CFUNC_LIST_POP_BACK; + } + + --(list->node_count); + list->last = output->prev; + + output->prev = output->next = NULL; + +RETURN_CFUNC_LIST_POP_BACK: + return output; +} + +CFuncNode *wapp_cfunc_list_remove(CFuncList *list, u64 index) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + CFuncNode *output = NULL; + + if (index == 0) { + output = wapp_cfunc_list_pop_front(list); + goto RETURN_CFUNC_LIST_REMOVE; + } else if (index == list->node_count) { + output = wapp_cfunc_list_pop_back(list); + goto RETURN_CFUNC_LIST_REMOVE; + } + + output = wapp_cfunc_list_get(list, index); + if (!output) { + goto RETURN_CFUNC_LIST_REMOVE; + } + + output->prev->next = output->next; + output->next->prev = output->prev; + + --(list->node_count); + + output->prev = output->next = NULL; + +RETURN_CFUNC_LIST_REMOVE: + return output; +} + +void wapp_cfunc_list_empty(CFuncList *list) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + u64 count = list->node_count; + for (u64 i = 0; i < count; ++i) { + wapp_cfunc_list_pop_back(list); + } +} + +CStructNode *wapp_cstruct_list_get(const CStructList *list, u64 index) { + wapp_runtime_assert(index < list->node_count, "`index` is out of bounds"); + + CStructNode *output = NULL; + CStructNode *current = list->first; + for (u64 i = 1; i <= index; ++i) { + current = current->next; + } + + output = current; + + return output; +} + +void wapp_cstruct_list_push_front(CStructList *list, CStructNode *node) { + wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL"); + + CStructList node_list = cstruct_node_to_list(node); + + if (list->node_count == 0) { + *list = node_list; + return; + } + + list->node_count += node_list.node_count; + + CStructNode *first = list->first; + if (first) { + first->prev = node_list.last; + } + + list->first = node_list.first; + node_list.last->next = first; +} + +void wapp_cstruct_list_push_back(CStructList *list, CStructNode *node) { + wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL"); + + CStructList node_list = cstruct_node_to_list(node); + + if (list->node_count == 0) { + *list = node_list; + return; + } + + list->node_count += node_list.node_count; + + CStructNode *last = list->last; + if (last) { + last->next = node_list.first; + } + + list->last = node_list.last; + node_list.first->prev = last; +} + +void wapp_cstruct_list_insert(CStructList *list, CStructNode *node, u64 index) { + wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL"); + + if (index == 0) { + wapp_cstruct_list_push_front(list, node); + return; + } else if (index == list->node_count) { + wapp_cstruct_list_push_back(list, node); + return; + } + + CStructNode *dst_node = wapp_cstruct_list_get(list, index); + if (!dst_node) { + return; + } + + CStructList node_list = cstruct_node_to_list(node); + + list->node_count += node_list.node_count; + + CStructNode *prev = dst_node->prev; + + dst_node->prev = node_list.last; + prev->next = node_list.first; + + node_list.first->prev = prev; + node_list.last->next = dst_node; +} + +CStructNode *wapp_cstruct_list_pop_front(CStructList *list) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + CStructNode *output = NULL; + + if (list->node_count == 0) { + goto RETURN_CSTRUCT_LIST_POP_FRONT; + } + + output = list->first; + + if (list->node_count == 1) { + *list = (CStructList){0}; + goto RETURN_CSTRUCT_LIST_POP_FRONT; + } + + --(list->node_count); + list->first = output->next; + + output->prev = output->next = NULL; + +RETURN_CSTRUCT_LIST_POP_FRONT: + return output; +} + +CStructNode *wapp_cstruct_list_pop_back(CStructList *list) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + CStructNode *output = NULL; + + if (list->node_count == 0) { + goto RETURN_CSTRUCT_LIST_POP_BACK; + } + + output = list->last; + + if (list->node_count == 1) { + *list = (CStructList){0}; + goto RETURN_CSTRUCT_LIST_POP_BACK; + } + + --(list->node_count); + list->last = output->prev; + + output->prev = output->next = NULL; + +RETURN_CSTRUCT_LIST_POP_BACK: + return output; +} + +CStructNode *wapp_cstruct_list_remove(CStructList *list, u64 index) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + CStructNode *output = NULL; + + if (index == 0) { + output = wapp_cstruct_list_pop_front(list); + goto RETURN_CSTRUCT_LIST_REMOVE; + } else if (index == list->node_count) { + output = wapp_cstruct_list_pop_back(list); + goto RETURN_CSTRUCT_LIST_REMOVE; + } + + output = wapp_cstruct_list_get(list, index); + if (!output) { + goto RETURN_CSTRUCT_LIST_REMOVE; + } + + output->prev->next = output->next; + output->next->prev = output->prev; + + --(list->node_count); + + output->prev = output->next = NULL; + +RETURN_CSTRUCT_LIST_REMOVE: + return output; +} + +void wapp_cstruct_list_empty(CStructList *list) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + u64 count = list->node_count; + for (u64 i = 0; i < count; ++i) { + wapp_cstruct_list_pop_back(list); + } +} + +CMacroNode *wapp_cmacro_list_get(const CMacroList *list, u64 index) { + wapp_runtime_assert(index < list->node_count, "`index` is out of bounds"); + + CMacroNode *output = NULL; + CMacroNode *current = list->first; + for (u64 i = 1; i <= index; ++i) { + current = current->next; + } + + output = current; + + return output; +} + +void wapp_cmacro_list_push_front(CMacroList *list, CMacroNode *node) { + wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL"); + + CMacroList node_list = cmacro_node_to_list(node); + + if (list->node_count == 0) { + *list = node_list; + return; + } + + list->node_count += node_list.node_count; + + CMacroNode *first = list->first; + if (first) { + first->prev = node_list.last; + } + + list->first = node_list.first; + node_list.last->next = first; +} + +void wapp_cmacro_list_push_back(CMacroList *list, CMacroNode *node) { + wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL"); + + CMacroList node_list = cmacro_node_to_list(node); + + if (list->node_count == 0) { + *list = node_list; + return; + } + + list->node_count += node_list.node_count; + + CMacroNode *last = list->last; + if (last) { + last->next = node_list.first; + } + + list->last = node_list.last; + node_list.first->prev = last; +} + +void wapp_cmacro_list_insert(CMacroList *list, CMacroNode *node, u64 index) { + wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL"); + + if (index == 0) { + wapp_cmacro_list_push_front(list, node); + return; + } else if (index == list->node_count) { + wapp_cmacro_list_push_back(list, node); + return; + } + + CMacroNode *dst_node = wapp_cmacro_list_get(list, index); + if (!dst_node) { + return; + } + + CMacroList node_list = cmacro_node_to_list(node); + + list->node_count += node_list.node_count; + + CMacroNode *prev = dst_node->prev; + + dst_node->prev = node_list.last; + prev->next = node_list.first; + + node_list.first->prev = prev; + node_list.last->next = dst_node; +} + +CMacroNode *wapp_cmacro_list_pop_front(CMacroList *list) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + CMacroNode *output = NULL; + + if (list->node_count == 0) { + goto RETURN_CMACRO_LIST_POP_FRONT; + } + + output = list->first; + + if (list->node_count == 1) { + *list = (CMacroList){0}; + goto RETURN_CMACRO_LIST_POP_FRONT; + } + + --(list->node_count); + list->first = output->next; + + output->prev = output->next = NULL; + +RETURN_CMACRO_LIST_POP_FRONT: + return output; +} + +CMacroNode *wapp_cmacro_list_pop_back(CMacroList *list) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + CMacroNode *output = NULL; + + if (list->node_count == 0) { + goto RETURN_CMACRO_LIST_POP_BACK; + } + + output = list->last; + + if (list->node_count == 1) { + *list = (CMacroList){0}; + goto RETURN_CMACRO_LIST_POP_BACK; + } + + --(list->node_count); + list->last = output->prev; + + output->prev = output->next = NULL; + +RETURN_CMACRO_LIST_POP_BACK: + return output; +} + +CMacroNode *wapp_cmacro_list_remove(CMacroList *list, u64 index) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + CMacroNode *output = NULL; + + if (index == 0) { + output = wapp_cmacro_list_pop_front(list); + goto RETURN_CMACRO_LIST_REMOVE; + } else if (index == list->node_count) { + output = wapp_cmacro_list_pop_back(list); + goto RETURN_CMACRO_LIST_REMOVE; + } + + output = wapp_cmacro_list_get(list, index); + if (!output) { + goto RETURN_CMACRO_LIST_REMOVE; + } + + output->prev->next = output->next; + output->next->prev = output->prev; + + --(list->node_count); + + output->prev = output->next = NULL; + +RETURN_CMACRO_LIST_REMOVE: + return output; +} + +void wapp_cmacro_list_empty(CMacroList *list) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + u64 count = list->node_count; + for (u64 i = 0; i < count; ++i) { + wapp_cmacro_list_pop_back(list); + } +} + +internal CEnumValList cenumval_node_to_list(CEnumValNode *node) { + CEnumValList output = {.first = node, .last = node, .node_count = 1}; + + while (output.first->prev != NULL) { + output.first = output.first->prev; + ++(output.node_count); + } + + while (output.last->next != NULL) { + output.last = output.last->next; + ++(output.node_count); + } + + return output; +} + +internal CArgList carg_node_to_list(CArgNode *node) { + CArgList output = {.first = node, .last = node, .node_count = 1}; + + while (output.first->prev != NULL) { + output.first = output.first->prev; + ++(output.node_count); + } + + while (output.last->next != NULL) { + output.last = output.last->next; + ++(output.node_count); + } + + return output; +} + +internal CQualifierList cqualifier_node_to_list(CQualifierNode *node) { + CQualifierList output = {.first = node, .last = node, .node_count = 1}; + + while (output.first->prev != NULL) { + output.first = output.first->prev; + ++(output.node_count); + } + + while (output.last->next != NULL) { + output.last = output.last->next; + ++(output.node_count); + } + + return output; +} + +internal CIncludeList cinclude_node_to_list(CIncludeNode *node) { + CIncludeList output = {.first = node, .last = node, .node_count = 1}; + + while (output.first->prev != NULL) { + output.first = output.first->prev; + ++(output.node_count); + } + + while (output.last->next != NULL) { + output.last = output.last->next; + ++(output.node_count); + } + + return output; +} + +internal CUserTypeList cusertype_node_to_list(CUserTypeNode *node) { + CUserTypeList output = {.first = node, .last = node, .node_count = 1}; + + while (output.first->prev != NULL) { + output.first = output.first->prev; + ++(output.node_count); + } + + while (output.last->next != NULL) { + output.last = output.last->next; + ++(output.node_count); + } + + return output; +} + +internal CFuncList cfunc_node_to_list(CFuncNode *node) { + CFuncList output = {.first = node, .last = node, .node_count = 1}; + + while (output.first->prev != NULL) { + output.first = output.first->prev; + ++(output.node_count); + } + + while (output.last->next != NULL) { + output.last = output.last->next; + ++(output.node_count); + } + + return output; +} + +internal CStructList cstruct_node_to_list(CStructNode *node) { + CStructList output = {.first = node, .last = node, .node_count = 1}; + + while (output.first->prev != NULL) { + output.first = output.first->prev; + ++(output.node_count); + } + + while (output.last->next != NULL) { + output.last = output.last->next; + ++(output.node_count); + } + + return output; +} + +internal CMacroList cmacro_node_to_list(CMacroNode *node) { + CMacroList output = {.first = node, .last = node, .node_count = 1}; + + while (output.first->prev != NULL) { + output.first = output.first->prev; + ++(output.node_count); + } + + while (output.last->next != NULL) { + output.last = output.last->next; + ++(output.node_count); + } + + return output; +} diff --git a/ccodegen/dbl_list.h b/ccodegen/dbl_list.h new file mode 100644 index 0000000..2d2c299 --- /dev/null +++ b/ccodegen/dbl_list.h @@ -0,0 +1,222 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#ifndef CCGEN_DBL_LIST_H +#define CCGEN_DBL_LIST_H + +#include "wapp_core.h" +#include "type_enums.h" + +#ifdef WAPP_PLATFORM_CPP +BEGIN_C_LINKAGE +#endif // !WAPP_PLATFORM_CPP + +#ifdef WAPP_PLATFORM_CPP +#define wapp_cenumval_list_node(ITEM_PTR) CEnumValNode{ITEM_PTR, nullptr, nullptr} +#define wapp_carg_list_node(ITEM_PTR) CArgNode{ITEM_PTR, nullptr, nullptr} +#define wapp_cqualifier_list_node(ITEM_PTR) CQualifierNode{ITEM_PTR, nullptr, nullptr} +#define wapp_cinclude_list_node(ITEM_PTR) CIncludeNode{ITEM_PTR, nullptr, nullptr} +#define wapp_cusertype_list_node(ITEM_PTR) CUserTypeNode{ITEM_PTR, nullptr, nullptr} +#define wapp_cfunc_list_node(ITEM_PTR) CFuncNode{ITEM_PTR, nullptr, nullptr} +#define wapp_cstruct_list_node(ITEM_PTR) CStructNode{ITEM_PTR, nullptr, nullptr} +#define wapp_cmacro_list_node(ITEM_PTR) CMacroNode{ITEM_PTR, nullptr, nullptr} +#else +#define wapp_cenumval_list_node(ITEM_PTR) ((CEnumValNode){.item = ITEM_PTR}) +#define wapp_carg_list_node(ITEM_PTR) ((CArgNode){.item = ITEM_PTR}) +#define wapp_cqualifier_list_node(ITEM_PTR) ((CQualifierNode){.item = ITEM_PTR}) +#define wapp_cinclude_list_node(ITEM_PTR) ((CIncludeNode){.item = ITEM_PTR}) +#define wapp_cusertype_list_node(ITEM_PTR) ((CUserTypeNode){.item = ITEM_PTR}) +#define wapp_cfunc_list_node(ITEM_PTR) ((CFuncNode){.item = ITEM_PTR}) +#define wapp_cstruct_list_node(ITEM_PTR) ((CStructNode){.item = ITEM_PTR}) +#define wapp_cmacro_list_node(ITEM_PTR) ((CMacroNode){.item = ITEM_PTR}) +#endif // !WAPP_PLATFORM_CPP + +typedef struct cenumval CEnumVal; +typedef struct carg CArg; +typedef struct cinclude CInclude; +typedef struct cusertype CUserType; +typedef struct cfunc CFunc; +typedef struct cstruct CStruct; +typedef struct cmacro CMacro; + +typedef struct CEnumValNode CEnumValNode; +struct CEnumValNode { + CEnumVal *item; + CEnumValNode *prev; + CEnumValNode *next; +}; + +typedef struct CEnumValList CEnumValList; +struct CEnumValList { + CEnumValNode *first; + CEnumValNode *last; + u64 node_count; +}; + +typedef struct CArgNode CArgNode; +struct CArgNode { + CArg *item; + CArgNode *prev; + CArgNode *next; +}; + +typedef struct CArgList CArgList; +struct CArgList { + CArgNode *first; + CArgNode *last; + u64 node_count; +}; + +typedef struct CQualifierNode CQualifierNode; +struct CQualifierNode { + CQualifier *item; + CQualifierNode *prev; + CQualifierNode *next; +}; + +typedef struct CQualifierList CQualifierList; +struct CQualifierList { + CQualifierNode *first; + CQualifierNode *last; + u64 node_count; +}; + +typedef struct CIncludeNode CIncludeNode; +struct CIncludeNode { + CInclude *item; + CIncludeNode *prev; + CIncludeNode *next; +}; + +typedef struct CIncludeList CIncludeList; +struct CIncludeList { + CIncludeNode *first; + CIncludeNode *last; + u64 node_count; +}; + +typedef struct CUserTypeNode CUserTypeNode; +struct CUserTypeNode { + CUserType *item; + CUserTypeNode *prev; + CUserTypeNode *next; +}; + +typedef struct CUserTypeList CUserTypeList; +struct CUserTypeList { + CUserTypeNode *first; + CUserTypeNode *last; + u64 node_count; +}; + +typedef struct CFuncNode CFuncNode; +struct CFuncNode { + CFunc *item; + CFuncNode *prev; + CFuncNode *next; +}; + +typedef struct CFuncList CFuncList; +struct CFuncList { + CFuncNode *first; + CFuncNode *last; + u64 node_count; +}; + +typedef struct CStructNode CStructNode; +struct CStructNode { + CStruct *item; + CStructNode *prev; + CStructNode *next; +}; + +typedef struct CStructList CStructList; +struct CStructList { + CStructNode *first; + CStructNode *last; + u64 node_count; +}; + +typedef struct CMacroNode CMacroNode; +struct CMacroNode { + CMacro *item; + CMacroNode *prev; + CMacroNode *next; +}; + +typedef struct CMacroList CMacroList; +struct CMacroList { + CMacroNode *first; + CMacroNode *last; + u64 node_count; +}; + +CEnumValNode *wapp_cenumval_list_get(const CEnumValList *list, u64 index); +void wapp_cenumval_list_push_front(CEnumValList *list, CEnumValNode *node); +void wapp_cenumval_list_push_back(CEnumValList *list, CEnumValNode *node); +void wapp_cenumval_list_insert(CEnumValList *list, CEnumValNode *node, u64 index); +CEnumValNode *wapp_cenumval_list_pop_front(CEnumValList *list); +CEnumValNode *wapp_cenumval_list_pop_back(CEnumValList *list); +CEnumValNode *wapp_cenumval_list_remove(CEnumValList *list, u64 index); +void wapp_cenumval_list_empty(CEnumValList *list); +CArgNode *wapp_carg_list_get(const CArgList *list, u64 index); +void wapp_carg_list_push_front(CArgList *list, CArgNode *node); +void wapp_carg_list_push_back(CArgList *list, CArgNode *node); +void wapp_carg_list_insert(CArgList *list, CArgNode *node, u64 index); +CArgNode *wapp_carg_list_pop_front(CArgList *list); +CArgNode *wapp_carg_list_pop_back(CArgList *list); +CArgNode *wapp_carg_list_remove(CArgList *list, u64 index); +void wapp_carg_list_empty(CArgList *list); +CQualifierNode *wapp_cqualifier_list_get(const CQualifierList *list, u64 index); +void wapp_cqualifier_list_push_front(CQualifierList *list, CQualifierNode *node); +void wapp_cqualifier_list_push_back(CQualifierList *list, CQualifierNode *node); +void wapp_cqualifier_list_insert(CQualifierList *list, CQualifierNode *node, u64 index); +CQualifierNode *wapp_cqualifier_list_pop_front(CQualifierList *list); +CQualifierNode *wapp_cqualifier_list_pop_back(CQualifierList *list); +CQualifierNode *wapp_cqualifier_list_remove(CQualifierList *list, u64 index); +void wapp_cqualifier_list_empty(CQualifierList *list); +CIncludeNode *wapp_cinclude_list_get(const CIncludeList *list, u64 index); +void wapp_cinclude_list_push_front(CIncludeList *list, CIncludeNode *node); +void wapp_cinclude_list_push_back(CIncludeList *list, CIncludeNode *node); +void wapp_cinclude_list_insert(CIncludeList *list, CIncludeNode *node, u64 index); +CIncludeNode *wapp_cinclude_list_pop_front(CIncludeList *list); +CIncludeNode *wapp_cinclude_list_pop_back(CIncludeList *list); +CIncludeNode *wapp_cinclude_list_remove(CIncludeList *list, u64 index); +void wapp_cinclude_list_empty(CIncludeList *list); +CUserTypeNode *wapp_cusertype_list_get(const CUserTypeList *list, u64 index); +void wapp_cusertype_list_push_front(CUserTypeList *list, CUserTypeNode *node); +void wapp_cusertype_list_push_back(CUserTypeList *list, CUserTypeNode *node); +void wapp_cusertype_list_insert(CUserTypeList *list, CUserTypeNode *node, u64 index); +CUserTypeNode *wapp_cusertype_list_pop_front(CUserTypeList *list); +CUserTypeNode *wapp_cusertype_list_pop_back(CUserTypeList *list); +CUserTypeNode *wapp_cusertype_list_remove(CUserTypeList *list, u64 index); +void wapp_cusertype_list_empty(CUserTypeList *list); +CFuncNode *wapp_cfunc_list_get(const CFuncList *list, u64 index); +void wapp_cfunc_list_push_front(CFuncList *list, CFuncNode *node); +void wapp_cfunc_list_push_back(CFuncList *list, CFuncNode *node); +void wapp_cfunc_list_insert(CFuncList *list, CFuncNode *node, u64 index); +CFuncNode *wapp_cfunc_list_pop_front(CFuncList *list); +CFuncNode *wapp_cfunc_list_pop_back(CFuncList *list); +CFuncNode *wapp_cfunc_list_remove(CFuncList *list, u64 index); +void wapp_cfunc_list_empty(CFuncList *list); +CStructNode *wapp_cstruct_list_get(const CStructList *list, u64 index); +void wapp_cstruct_list_push_front(CStructList *list, CStructNode *node); +void wapp_cstruct_list_push_back(CStructList *list, CStructNode *node); +void wapp_cstruct_list_insert(CStructList *list, CStructNode *node, u64 index); +CStructNode *wapp_cstruct_list_pop_front(CStructList *list); +CStructNode *wapp_cstruct_list_pop_back(CStructList *list); +CStructNode *wapp_cstruct_list_remove(CStructList *list, u64 index); +void wapp_cstruct_list_empty(CStructList *list); +CMacroNode *wapp_cmacro_list_get(const CMacroList *list, u64 index); +void wapp_cmacro_list_push_front(CMacroList *list, CMacroNode *node); +void wapp_cmacro_list_push_back(CMacroList *list, CMacroNode *node); +void wapp_cmacro_list_insert(CMacroList *list, CMacroNode *node, u64 index); +CMacroNode *wapp_cmacro_list_pop_front(CMacroList *list); +CMacroNode *wapp_cmacro_list_pop_back(CMacroList *list); +CMacroNode *wapp_cmacro_list_remove(CMacroList *list, u64 index); +void wapp_cmacro_list_empty(CMacroList *list); + +#ifdef WAPP_PLATFORM_CPP +END_C_LINKAGE +#endif // !WAPP_PLATFORM_CPP + +#endif // !DBL_LIST_H diff --git a/ccodegen/main.c b/ccodegen/main.c new file mode 100644 index 0000000..749f5b2 --- /dev/null +++ b/ccodegen/main.c @@ -0,0 +1,7 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#include + +int main(void) { + return 0; +} diff --git a/ccodegen/type_enums.h b/ccodegen/type_enums.h new file mode 100644 index 0000000..e7cf441 --- /dev/null +++ b/ccodegen/type_enums.h @@ -0,0 +1,84 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#ifndef TYPE_ENUMS_H +#define TYPE_ENUMS_H + +#include "wapp_core.h" + +typedef enum { + CTYPE_VOID, + CTYPE_BOOL, + CTYPE_CHAR, + CTYPE_C8, + CTYPE_C16, + CTYPE_C32, + CTYPE_I8, + CTYPE_I16, + CTYPE_I32, + CTYPE_I64, + CTYPE_U8, + CTYPE_U16, + CTYPE_U32, + CTYPE_U64, + CTYPE_F32, + CTYPE_F64, + CTYPE_F128, + CTYPE_IPTR, + CTYPE_UPTR, + + COUNT_CTYPE, +} CType; +internal Str8RO ctypes[COUNT_CTYPE] = { + [CTYPE_VOID] = wapp_str8_lit_ro("void"), + [CTYPE_BOOL] = wapp_str8_lit_ro("b32"), + [CTYPE_CHAR] = wapp_str8_lit_ro("char"), + [CTYPE_C8] = wapp_str8_lit_ro("c8"), + [CTYPE_C16] = wapp_str8_lit_ro("c16"), + [CTYPE_C32] = wapp_str8_lit_ro("c32"), + [CTYPE_I8] = wapp_str8_lit_ro("i8"), + [CTYPE_I16] = wapp_str8_lit_ro("i16"), + [CTYPE_I32] = wapp_str8_lit_ro("i32"), + [CTYPE_I64] = wapp_str8_lit_ro("i64"), + [CTYPE_U8] = wapp_str8_lit_ro("u8"), + [CTYPE_U16] = wapp_str8_lit_ro("u16"), + [CTYPE_U32] = wapp_str8_lit_ro("u32"), + [CTYPE_U64] = wapp_str8_lit_ro("u64"), + [CTYPE_F32] = wapp_str8_lit_ro("f32"), + [CTYPE_F64] = wapp_str8_lit_ro("f64"), + [CTYPE_F128] = wapp_str8_lit_ro("f128"), + [CTYPE_IPTR] = wapp_str8_lit_ro("iptr"), + [CTYPE_UPTR] = wapp_str8_lit_ro("uptr"), +}; + +typedef enum { + CQUALIFIER_NONE, + CQUALIFIER_CONST, + CQUALIFIER_EXTERNAL, + CQUALIFIER_INTERNAL, + CQUALIFIER_PERSISTENT, + + COUNT_CQUALIFIER, +} CQualifier; +internal Str8RO cqualifiers[COUNT_CQUALIFIER] = { + [CQUALIFIER_NONE] = wapp_str8_lit_ro(""), + [CQUALIFIER_CONST] = wapp_str8_lit_ro("const "), + [CQUALIFIER_EXTERNAL] = wapp_str8_lit_ro("external "), + [CQUALIFIER_INTERNAL] = wapp_str8_lit_ro("internal "), + [CQUALIFIER_PERSISTENT] = wapp_str8_lit_ro("persistent "), +}; + + +typedef enum { + CPOINTERTYPE_NONE, + CPOINTERTYPE_SINGLE, + CPOINTERTYPE_DOUBLE, + + COUNT_CPOINTERTYPE, +} CPointerType; +internal Str8RO cpointertypes[COUNT_CPOINTERTYPE] = { + [CPOINTERTYPE_NONE] = wapp_str8_lit_ro(""), + [CPOINTERTYPE_SINGLE] = wapp_str8_lit_ro("*"), + [CPOINTERTYPE_DOUBLE] = wapp_str8_lit_ro("**"), +}; + +#endif // !TYPE_ENUMS_H