From bb3601b8f24b6b8b0770d1082667d61646adb30b Mon Sep 17 00:00:00 2001 From: herbglitch Date: Thu, 6 Mar 2025 04:21:01 -0700 Subject: [PATCH] worked more on arc chemical, need to add way to parse with seperate create and destroy function for unload --- include/arc/std/chemical.h | 119 +++++++++++++++---------------------- src/std/chemical.c | 117 ++++++++++++++++++++++++++++-------- 2 files changed, 142 insertions(+), 94 deletions(-) diff --git a/include/arc/std/chemical.h b/include/arc/std/chemical.h index 6fc9162..9f70557 100644 --- a/include/arc/std/chemical.h +++ b/include/arc/std/chemical.h @@ -8,79 +8,24 @@ extern "C" { #include #include "arc/std/parser.h" -/* - * TODO: note here in header that this uses parser - * TODO: note here in header that group being used is persistant - * TODO: add allowance for any symbol in string? - -> | | - - -> OPEN_CURLY_BRACE CLOSE_CURLY_BRACE - - -> EQUAL value SEMICOLON - - -> - -> - -> | | - -> OPEN_CURLY_BRACE CLOSE_CURLY_BRACE - -> | COMMA - - -> ALPHA_UPPER_CHAR | ALPHA_LOWER_CHAR | UNDERSCORE - -> | LAMBDA - -> ALPHA_UPPER_CHAR | ALPHA_LOWER_CHAR | UNDERSCORE | NUMBER - - -> QUOTE QUOTE - -> | | LAMBDA - -> ALPHA_UPPER_CHAR | ALPHA_LOWER_CHAR | NUMBER | WHITESPACE | UNDERSCORE | OPEN_CURLY_BRACE | CLOSE_CURLY_BRACE | OPEN_PAREN | CLOSE_PAREN | BANG | HASH | DOLLER | PERCENT | AMPERSAND | SINGLE_QUOTE | ASTERISK | PLUS | COMMA | MINUS | PERIOD | SHASH | COLON | SEMICOLON | QUESTION_MARK | AT | OPEN_BRACKET | CLOSE_BRACKET | CARET | GRAVE | VERTICAL_LINE | TILDE - -> LESS_THAN | EQUAL | GREATER_THAN - -> BACKSLASH BACKSLASH | BACKSLASH QUOTE BACKSLASH ALPHA_UPPER_CHAR | BACKSLASH ALPHA_LOWER_CHAR - - -> NUMBER | NUMBER LAMBDA - - -> SPACE | TAB | NEWLINE | LAMBDA -*/ - /** - * @brief a function to read a key from string to a ARC_ConfigTypeTemplate - * - * @param config ARC_Config to store data to - * @param string ARC_String of data that is being read in - * @param value value that is read in - * - * @note use ARC_Config_StoreValue(ARC_Config *config, ARC_String *name, void *value); to store a value to the config - * if there is an error, set arc_errno - * - * @return 0 if value not a reference, 1 if value is a reference - */ -//typedef uint8_t (* ARC_ConfigKeyRead)(ARC_Config* config, ARC_String *string, void **value); - -/** - * @brief a function to delete a value from a key in ARC_Config - * - * @param config ARC_Config that can be used to check for references in data - * @param value pointer of data to be deleted - * - * @note this function can be NULL if memory does not need to be cleaned for this type - * if there is an error, set arc_errno - */ -//typedef void (* ARC_ConfigKeyDelete)(ARC_Config* config, ARC_String *string, void *value); - -/** - * @brief TODO: write this + * @brief the config type for archeus, loads in a config file which syntax is specified in the documentation + * @TODO: add documentation link here */ typedef struct ARC_Chemical ARC_Chemical; /** - * @brief + * @brief a function callback to create a type stored within a config */ typedef void (* ARC_ChemicalType_CopyFn)(void **type, ARC_ParserTagToken *parsedData, ARC_Chemical *chemical); /** - * @brief + * @brief a function callback to destroy a type */ typedef void (* ARC_ChemicalType_DestroyFn)(void *type); /** - * @brief + * @brief the functions for used for loading and unloading a type, the name will be the key of a hashtable */ typedef struct ARC_ChemicalType { ARC_ChemicalType_CopyFn copyFn; @@ -88,25 +33,46 @@ typedef struct ARC_ChemicalType { } ARC_ChemicalType; /** - * @brief TODO: write this + * @brief creates the arc config type (a type that loads in chemical files and can have types added to it) */ void ARC_Chemical_Create(ARC_Chemical **chemical); /** - * @brief TODO: write this + * @brief destroys an ARC_Chemical type */ void ARC_Chemical_Destroy(ARC_Chemical *chemical); /** - * @brief TODO: write this + * @brief adds creation and destruction functions for a new user provided type will be used for chemical load and unload functions + * + * @note this function uses ARC_Chemical_RegisterTypeWithCStr so it shares error messages with that function + * + * @param[in] chemical the ARC_Chemical to set the new type into + * @param[in] typeName the name of the type like "uint32" or "ARC_Rect" that will be read in from a chemical file + * @param[in] type the copy and destroy functions for the type used on load and unload */ void ARC_Chemical_RegisterType(ARC_Chemical *chemical, ARC_String *typeName, ARC_ChemicalType type); /** - * @brief TODO: write this + * @brief adds creation and destruction functions for a new user provided type + * + * @param[in] chemical the ARC_Chemical to set the new type into + * @param[in] typeName the name of the type like "uint32" or "ARC_Rect" that will be read in from a chemical file + * @param[in] type the copy and destroy functions for the type used on load and unload */ void ARC_Chemical_RegisterTypeWithCStr(ARC_Chemical *chemical, const char *typeNameCStr, ARC_ChemicalType type); +/** + * @brief sets current group in config + * + * @note ARC_Chemical_Get will use this set group + * @note this function uses ARC_Chemical_SetGroupWithCStr so it shares error messages with that function + * + * @param[in] chemical ARC_Config we are setting current group in + * @param[in] groupname name of group that will be set + */ +void ARC_Chemical_SetGroup(ARC_Chemical *chemical, ARC_String *groupName); + /** * @brief sets current group in config * @@ -115,7 +81,20 @@ void ARC_Chemical_RegisterTypeWithCStr(ARC_Chemical *chemical, const char *typeN * @param[in] chemical ARC_Config we are setting current group in * @param[in] groupname name of group that will be set */ -void ARC_Chemical_SetGroup(ARC_Chemical *chemical, ARC_String *groupName); +void ARC_Chemical_SetGroupWithCStr(ARC_Chemical *chemical, const char *groupName); + +/** + * @brief get a value from a given keyname + * + * @note name may be prefaced with :: to specify group + * @note this function uses ARC_Chemical_GetWithCStr so it shares error messages with that function + * + * @param[in] chemical ARC_Chemical to get value from + * @param[in] element name of a variable that has been read in + * + * @return the stored element on success, or NULL on failure + */ +void *ARC_Chemical_Get(ARC_Chemical *chemical, ARC_String *element); /** * @brief get a value from a given keyname @@ -127,27 +106,27 @@ void ARC_Chemical_SetGroup(ARC_Chemical *chemical, ARC_String *groupName); * * @return the stored element on success, or NULL on failure */ -void *ARC_Chemical_Get(ARC_Chemical *chemical, ARC_String *element); +void *ARC_Chemical_GetWithCStr(ARC_Chemical *chemical, const char *element); /** * @brief TODO: write this */ -void ARC_Chemical_LoadFromString(ARC_String *path); +void ARC_Chemical_LoadFromString(ARC_Chemical *chemical, ARC_String **string); /** * @brief TODO: write this */ -void ARC_Chemical_LoadFromFile(ARC_String *path); +void ARC_Chemical_LoadFromFile(ARC_Chemical *chemical, ARC_String *path); /** * @brief TODO: write this */ -void ARC_Chemical_UnloadFromString(ARC_String *data); +void ARC_Chemical_UnloadFromString(ARC_Chemical *chemical, ARC_String **string); /** * @brief TODO: write this */ -void ARC_Chemical_UnloadFromFile(ARC_String *data); +void ARC_Chemical_UnloadFromFile(ARC_Chemical *chemical, ARC_String *data); #ifdef __cplusplus } diff --git a/src/std/chemical.c b/src/std/chemical.c index dae4b3e..a610c7d 100644 --- a/src/std/chemical.c +++ b/src/std/chemical.c @@ -1,26 +1,30 @@ #include "arc/std/chemical.h" #include "arc/std/parser/helpers.h" #include "arc/std/bool.h" +#include "arc/std/errno.h" #include "arc/std/hashtable.h" #include "arc/std/parser.h" #include #include #include +#include struct ARC_Chemical { ARC_Parser *parser; - ARC_Hashtable *groups; ARC_Hashtable *types; + ARC_Hashtable *groups; ARC_Hashtable *currentGroup; }; typedef struct ARC_ChemicalTypeData { void *data; - ARC_ChemicalType_DestroyFn *destroyFn; + ARC_ChemicalType_DestroyFn destroyFn; } ARC_ChemicalTypeData; +static const char *ARC_CHEMICAL_DEFAULT_GROUP = " "; + //the grouping is based on the ascii table, but the ids are sequential to make finding tokens quicker (look at the lexer continious for more explanation) static const uint32_t ARC_CHEMICAL_TAB = 0x01; static const uint32_t ARC_CHEMICAL_NEWLINE = 0x02; @@ -328,6 +332,32 @@ void ARC_ChemicalData_DestroyFn(void *data, ARC_Bool clear, void *userData){ return; } +//private function to check hashtable keys used by chemical +ARC_Bool ARC_Chemical_HashtableKeyCompareFn(void *key1, void *key2){ + return (ARC_Bool)strcmp((const char *)key1, (const char *)key2) == 0; +} + +//private function to clean up types +void ARC_Chemical_TypeHashtableDestroyKeyValueFn(void *key, void *value){ + free((char *)key); + free((ARC_ChemicalType *)value); +} + +//private function to clean up groups +void ARC_Chemical_GroupHashtableDestroyKeyValueFn(void *key, void *value){ + free((char *)key); + ARC_Hashtable_Destroy((ARC_Hashtable *)value); +} + +//private function to clean up goup data +void ARC_Chemical_GroupDataHashtableDestroyKeyValueFn(void *key, void *value){ + free((char *)key); + + ARC_ChemicalTypeData *typeData = (ARC_ChemicalTypeData *)value; + typeData->destroyFn(typeData->data); + free(typeData); +} + void ARC_Chemical_Create(ARC_Chemical **chemical){ *chemical = (ARC_Chemical *)malloc(sizeof(ARC_Chemical)); @@ -370,57 +400,96 @@ void ARC_Chemical_Create(ARC_Chemical **chemical){ ARC_ParserData_DestroyFn destroyCharFn = ARC_ChemicalData_DestroyFn; ARC_Parser_CreateFromString(&((*chemical)->parser), languageString, ARC_Chemical_InitLexerRulesFn, ARC_Chemical_GetStringIdFn, &createCharFn, &destroyCharFn, userdata); + /* ~ init types ~ */ + ARC_Hashtable_KeyCompareFn keyCompareFn = ARC_Chemical_HashtableKeyCompareFn; + ARC_Hashtable_DestroyKeyValueFn typeDestroyKeyValueFn = ARC_Chemical_TypeHashtableDestroyKeyValueFn; + ARC_Hashtable_Create(&((*chemical)->types), NULL, &keyCompareFn, &typeDestroyKeyValueFn); + + /* ~ init groups ~ */ + ARC_Hashtable_DestroyKeyValueFn groupDestroyKeyValueFn = ARC_Chemical_GroupHashtableDestroyKeyValueFn; + ARC_Hashtable_Create(&((*chemical)->groups), NULL, &keyCompareFn, &groupDestroyKeyValueFn); + + //add the default/empty group into the groups + ARC_Hashtable_DestroyKeyValueFn groupDataDestroyKeyValueFn = ARC_Chemical_GroupDataHashtableDestroyKeyValueFn; + ARC_Hashtable_Create(&((*chemical)->currentGroup), NULL, &keyCompareFn, &groupDataDestroyKeyValueFn); + ARC_Hashtable_Add((*chemical)->groups, (void *)ARC_CHEMICAL_DEFAULT_GROUP, (*chemical)->currentGroup); + //cleanup ARC_String_Destroy(languageString); } void ARC_Chemical_Destroy(ARC_Chemical *chemical){ + //NOTE: chemical->currentGroup does not need to be freed as it is stored in chemical->groups + ARC_Hashtable_Destroy(chemical->groups); + ARC_Hashtable_Destroy(chemical->types); free(chemical); } -void ARC_Chemical_HashtableCheckKeyIteratorFn(void *key, void *value){ - -} - void ARC_Chemical_RegisterType(ARC_Chemical *chemical, ARC_String *typeName, ARC_ChemicalType type){ - //TODO: check if name currently exists - ARC_String *typeNameCopy; - ARC_String_Copy(&typeNameCopy, typeName); - - ARC_ChemicalType *typeCopy = (ARC_ChemicalType *)malloc(sizeof(ARC_ChemicalType)); - *typeCopy = type; - - ARC_Hashtable_Add(chemical->types, typeName, typeCopy); + ARC_Chemical_RegisterTypeWithCStr(chemical, typeName->data, type); } void ARC_Chemical_RegisterTypeWithCStr(ARC_Chemical *chemical, const char *typeNameCStr, ARC_ChemicalType type){ - //TODO: check if name currently exists - ARC_String *typeName; - ARC_String_CreateWithStrlen(&typeName, (char *)typeNameCStr); + //check if the type key already exists and error if it does + if(ARC_Hashtable_Get(chemical->types, (void *)typeNameCStr) != NULL){ + arc_errno = ARC_ERRNO_EXISTS; + ARC_DEBUG_LOG_ERROR_WITH_VARIABLES("ARC_Chemical_RegisterTypeWithCStr(chemical, typeName, type), type \"%s\" has already been registered", typeNameCStr); + return; + } + //copy the string into a cstring for long term storage + char *typeNameCopy = malloc(sizeof(char) * strlen(typeNameCStr)); + strcpy(typeNameCopy, typeNameCStr); + + //copy the type for long term storage ARC_ChemicalType *typeCopy = (ARC_ChemicalType *)malloc(sizeof(ARC_ChemicalType)); *typeCopy = type; - ARC_Hashtable_Add(chemical->types, typeName, typeCopy); + //add the type to a hashtable containing all the types + ARC_Hashtable_Add(chemical->types, typeNameCopy, typeCopy); } void ARC_Chemical_SetGroup(ARC_Chemical *chemical, ARC_String *groupName){ - + ARC_Chemical_SetGroupWithCStr(chemical, groupName->data); +} + +void ARC_Chemical_SetGroupWithCStr(ARC_Chemical *chemical, const char *groupName){ + //try to get the current group + void *currentGroup = ARC_Hashtable_Get(chemical->groups, (void *)groupName); + + //error if the current group does not exist + if(currentGroup == NULL){ + arc_errno = ARC_ERRNO_NULL; + ARC_DEBUG_LOG_ERROR_WITH_VARIABLES("ARC_Chemical_SetGroupWithCStr(chemical, groupName), no group with name \"%s\"", groupName); + return; + } + + //set the current group + chemical->currentGroup = currentGroup; } void *ARC_Chemical_Get(ARC_Chemical *chemical, ARC_String *element){ - return NULL; + return ARC_Chemical_GetWithCStr(chemical, element->data); } -void ARC_Chemical_LoadFromString(ARC_String *path){ +void *ARC_Chemical_GetWithCStr(ARC_Chemical *chemical, const char *element){ + //TODO: set the parent group + + //this will either return the value or NULL + return ARC_Hashtable_Get(chemical->currentGroup, (void *)element); } -void ARC_Chemical_LoadFromFile(ARC_String *path){ +void ARC_Chemical_LoadFromString(ARC_Chemical *chemical, ARC_String **string){ + ARC_Parser_Parse(chemical->parser, string); } -void ARC_Chemical_UnloadFromString(ARC_String *data){ +void ARC_Chemical_LoadFromFile(ARC_Chemical *chemical, ARC_String *path){ + ARC_Parser_ParseFile(chemical->parser, path); } -void ARC_Chemical_UnloadFromFile(ARC_String *data){ +void ARC_Chemical_UnloadFromString(ARC_Chemical *chemical, ARC_String **string){ +} + +void ARC_Chemical_UnloadFromFile(ARC_Chemical *chemical, ARC_String *data){ }