renamed chemical to config, and renamed life to entity

This commit is contained in:
herbglitch 2025-03-11 00:41:17 -06:00
parent 30e8d94805
commit 04c89e46fe
10 changed files with 862 additions and 1725 deletions

View file

@ -62,7 +62,8 @@ set(ARCHEUS_LINK_LIBRARIES
# ~ ARCHEUS_SOURCES ~ # # ~ ARCHEUS_SOURCES ~ #
set(ARCHEUS_SOURCES set(ARCHEUS_SOURCES
src/std/chemical.c src/std/config.c
src/std/entity.c
src/std/errno.c src/std/errno.c
src/std/handler.c src/std/handler.c
src/std/hashtable.c src/std/hashtable.c
@ -128,7 +129,8 @@ if(ARCHEUS_TESTS)
add_executable(tests add_executable(tests
tests/test.c tests/test.c
#tests/std/chemical.c tests/std/config.c
#tests/std/entity.c
#tests/std/hashtable.c #tests/std/hashtable.c
#tests/std/lexer.c #tests/std/lexer.c
#tests/std/parser.c #tests/std/parser.c

View file

@ -1,205 +0,0 @@
#ifndef ARC_STD_PARSER_CHEMICAL_H_
#define ARC_STD_PARSER_CHEMICAL_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include "arc/std/parser.h"
/**
* @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 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 a function callback to destroy a type
*/
typedef void (* ARC_ChemicalType_DestroyFn)(void *type);
/**
* @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;
ARC_ChemicalType_DestroyFn destroyFn;
} ARC_ChemicalType;
/**
* @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 destroys an ARC_Chemical type
*/
void ARC_Chemical_Destroy(ARC_Chemical *chemical);
/**
* @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 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
*
* @note ARC_Chemical_Get will use this set group
*
* @param[in] chemical ARC_Config we are setting current group in
* @param[in] groupname name of group that will be set
*/
void ARC_Chemical_SetGroupWithCStr(ARC_Chemical *chemical, const char *groupName);
/**
* @brief get a value from a given keyname
*
* @note name may be prefaced with <group>:: to specify group
*
* @param[in] chemical ARC_Chemical to get value from
* @param[in] energy 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 *energy);
/**
* @brief get a value from a given keyname
*
* @note name may be prefaced with <group>:: to specify group
* @note this function uses ARC_Chemical_Get so it shares error messages with that function
*
* @param[in] chemical ARC_Chemical to get value from
* @param[in] energy name of a variable that has been read in
*
* @return the stored element on success, or NULL on failure
*/
void *ARC_Chemical_GetWithCStr(ARC_Chemical *chemical, const char *energy);
/**
* @brief TODO: write this
*/
void ARC_Chemical_LoadFromString(ARC_Chemical *chemical, ARC_String **string);
/**
* @brief TODO: write this
*/
void ARC_Chemical_LoadFromFile(ARC_Chemical *chemical, ARC_String *path);
/**
* @brief TODO: write this
*/
void ARC_Chemical_UnloadFromString(ARC_Chemical *chemical, ARC_String **string);
/**
* @brief TODO: write this
*/
void ARC_Chemical_UnloadFromFile(ARC_Chemical *chemical, ARC_String *data);
#define ARC_CHEMICAL_DEFAULT_GROUP " "
#define ARC_CHEMICAL_GROUP_TAG_NAME "group"
#define ARC_CHEMICAL_GROUP_SEPARATOR "::"
//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)
#define ARC_CHEMICAL_TAB 0x01
#define ARC_CHEMICAL_NEWLINE 0x02
#define ARC_CHEMICAL_SPACE 0x03
#define ARC_CHEMICAL_BANG 0x04
#define ARC_CHEMICAL_QUOTE 0x05
#define ARC_CHEMICAL_HASH 0x06
#define ARC_CHEMICAL_DOLLAR 0x07
#define ARC_CHEMICAL_PERCENT 0x08
#define ARC_CHEMICAL_AMPERSAND 0x09
#define ARC_CHEMICAL_SINGLE_QUOTE 0x0A
#define ARC_CHEMICAL_OPEN_PAREN 0x0B
#define ARC_CHEMICAL_CLOSE_PAREN 0x0C
#define ARC_CHEMICAL_ASTERISK 0x0D
#define ARC_CHEMICAL_PLUS 0x0E
#define ARC_CHEMICAL_COMMA 0x0F
#define ARC_CHEMICAL_MINUS 0x10
#define ARC_CHEMICAL_PERIOD 0x11
#define ARC_CHEMICAL_SLASH 0x12
#define ARC_CHEMICAL_NUMBER 0x13
#define ARC_CHEMICAL_COLON 0x14
#define ARC_CHEMICAL_SEMICOLON 0x15
#define ARC_CHEMICAL_LESS_THAN 0x16
#define ARC_CHEMICAL_GREATER_THAN 0x17
#define ARC_CHEMICAL_EQUAL 0x18
#define ARC_CHEMICAL_QUESTION_MARK 0x19
#define ARC_CHEMICAL_AT 0x1A
#define ARC_CHEMICAL_ALPHA_UPPER_CHAR 0x1B
#define ARC_CHEMICAL_OPEN_BRACKET 0x1C
#define ARC_CHEMICAL_BACKSLASH 0x1D
#define ARC_CHEMICAL_CLOSE_BRACKET 0x1E
#define ARC_CHEMICAL_CARET 0x1F
#define ARC_CHEMICAL_UNDERSCORE 0x20
#define ARC_CHEMICAL_GRAVE 0x21
#define ARC_CHEMICAL_ALPHA_LOWER_CHAR 0x22
#define ARC_CHEMICAL_OPEN_CURLY_BRACE 0x23
#define ARC_CHEMICAL_VERTICAL_LINE 0x24
#define ARC_CHEMICAL_CLOSE_CURLY_BRACE 0x25
#define ARC_CHEMICAL_TILDE 0x26
#define ARC_CHEMICAL_LANGUAGE 0x27
#define ARC_CHEMICAL_GROUP 0x28
#define ARC_CHEMICAL_GROUP_NAME 0x29
#define ARC_CHEMICAL_GROUP_ARGS 0x2A
#define ARC_CHEMICAL_VARIABLE_LINES 0x2B
#define ARC_CHEMICAL_VARIABLE_LINE 0x2C
#define ARC_CHEMICAL_ALLOW_SPACE 0x2D
#define ARC_CHEMICAL_TYPE 0x2E
#define ARC_CHEMICAL_VALUE 0x2F
#define ARC_CHEMICAL_NESTED_VALUE 0x30
#define ARC_CHEMICAL_VALUE_ARGS 0x31
#define ARC_CHEMICAL_VARIABLE 0x32
#define ARC_CHEMICAL_VARIABLE_NAME 0x33
#define ARC_CHEMICAL_VARIABLE_CHAR 0x34
#define ARC_CHEMICAL_STRING 0x35
#define ARC_CHEMICAL_STRING_CHARS 0x36
#define ARC_CHEMICAL_STRING_CHAR 0x37
#define ARC_CHEMICAL_ESCAPE_CHAR 0x38
#define ARC_CHEMICAL_NUMBER_SIGN 0x39
#define ARC_CHEMICAL_NUMBER_TAG 0x3A
#define ARC_CHEMICAL_WHITESPACE 0x3B
#ifdef __cplusplus
}
#endif
#endif //ARC_STD_PARSER_CHEMICAL_H_

View file

@ -5,122 +5,201 @@
extern "C" { extern "C" {
#endif #endif
#include "arc/std/hashtable.h"
#include "arc/std/string.h"
#include <stdint.h> #include <stdint.h>
#include "arc/std/parser.h"
#define ARC_KEY_BUCKET_SIZE 0x20
#define ARC_GROUP_BUCKET_SIZE 0x20
#define ARC_GROUP_DATA_BUCKET_SIZE 0x20
/** /**
* @brief a type that keeps permanice of data for when loading and unloading config files * @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_Config ARC_Config; typedef struct ARC_Config ARC_Config;
/** /**
* @brief a function to read a key from string to a ARC_ConfigTypeTemplate * @brief a function callback to create a type stored within a config
*
* @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); typedef void (* ARC_ConfigType_CopyFn)(void **type, ARC_ParserTagToken *parsedData, ARC_Config *config);
/** /**
* @brief a function to delete a value from a key in ARC_Config * @brief a function callback to destroy a type
*
* @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); typedef void (* ARC_ConfigType_DestroyFn)(void *type);
/** /**
* @brief adds a usable key to ARC_Config * @brief the functions for used for loading and unloading a type, the name will be the key of a hashtable
*
* @param config ARC_Config to add keys to
* @param type string of key type
* @param keyRead function for reading/creating key from string
* @param keyDelete function for deleting stored key
*/ */
void ARC_Config_AddKey(ARC_Config *config, ARC_String *type, ARC_ConfigKeyRead keyRead, ARC_ConfigKeyDelete keyDelete); typedef struct ARC_ConfigType {
ARC_ConfigType_CopyFn copyFn;
ARC_ConfigType_DestroyFn destroyFn;
} ARC_ConfigType;
/** /**
* @brief adds a key from a cstring * @brief creates the arc config type (a type that loads in config files and can have types added to it)
* @param config ARC_Config to add keys to
* @param type cstring of key type
* @param length length of cstring
* @param keyRead function for reading/creating key from string
* @param keyDelete function for deleting stored key
*/
//void ARC_Config_AddKeyCString(ARC_Config *config, const char *type, uint64_t length, ARC_ConfigKeyRead keyRead, ARC_ConfigKeyDelete keyDelete);
/**
* @brief external callback to add keys to config
*/
typedef void (* ARC_ConfigKey_AddFunc)(ARC_Config *config);
/**
* @brief creates ARC_Config type
*
* @param config ARC_Config to initialize
*/ */
void ARC_Config_Create(ARC_Config **config); void ARC_Config_Create(ARC_Config **config);
/** /**
* @brief destroys ARC_Config type * @brief destroys an ARC_Config type
*/ */
void ARC_Config_Destroy(ARC_Config *config); void ARC_Config_Destroy(ARC_Config *config);
/**
* @brief adds creation and destruction functions for a new user provided type will be used for config load and unload functions
*
* @note this function uses ARC_Config_RegisterTypeWithCStr so it shares error messages with that function
*
* @param[in] config the ARC_Config 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 config file
* @param[in] type the copy and destroy functions for the type used on load and unload
*/
void ARC_Config_RegisterType(ARC_Config *config, ARC_String *typeName, ARC_ConfigType type);
/**
* @brief adds creation and destruction functions for a new user provided type
*
* @param[in] config the ARC_Config 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 config file
* @param[in] type the copy and destroy functions for the type used on load and unload
*/
void ARC_Config_RegisterTypeWithCStr(ARC_Config *config, const char *typeNameCStr, ARC_ConfigType type);
/**
* @brief sets current group in config
*
* @note ARC_Config_Get will use this set group
* @note this function uses ARC_Config_SetGroupWithCStr so it shares error messages with that function
*
* @param[in] config ARC_Config we are setting current group in
* @param[in] groupname name of group that will be set
*/
void ARC_Config_SetGroup(ARC_Config *config, ARC_String *groupName);
/** /**
* @brief sets current group in config * @brief sets current group in config
* *
* @note ARC_Config_Get will use this set group * @note ARC_Config_Get will use this set group
* *
* @param config ARC_Config we are setting current group in * @param[in] config ARC_Config we are setting current group in
* @param groupname name of group that will be set * @param[in] groupname name of group that will be set
*/ */
void ARC_Config_SetGroup(ARC_Config *config, ARC_String *groupname); void ARC_Config_SetGroupWithCStr(ARC_Config *config, const char *groupName);
/**
* @brief get a value from a given name
*
* @note name should be prefaced with <group>:: to specify group
*
* @param[in] config ARC_Config to get value from
* @param[in] name name of a variable that has been read in
*
* @return the stored element on success, or NULL on failure
*/
void *ARC_Config_Get(ARC_Config *config, ARC_String *name);
/** /**
* @brief get a value from a given keyname * @brief get a value from a given keyname
* *
* @note name may be prefaced with <group>:: to specify group * @note name should be prefaced with <group>:: to specify group
* @note this function uses ARC_Config_Get so it shares error messages with that function
* *
* @param config ARC_Config to get value from * @param[in] config ARC_Config to get value from
* @param keyname name of key to get from config * @param[in] name name of a variable that has been read in
* @param value data retrieved from config *
* @return the stored element on success, or NULL on failure
*/ */
//void ARC_Config_Get(ARC_Config *config, ARC_String *keyname, void **value); void *ARC_Config_GetWithCStr(ARC_Config *config, const char *name);
/** /**
* @brief commands that can be used in ARC_Config_FileIO * @brief TODO: write this
*/ */
#define ARC_CONFIG_FILE_IO_LOAD 0x00 void ARC_Config_LoadFromString(ARC_Config *config, ARC_String **string);
#define ARC_CONFIG_FILE_IO_UNLOAD 0x01
/** /**
* @brief handles file io for ARC_Config Type * @brief TODO: write this
*
* @param config ARC_Config where io operations will take place
* @param path file path for io
*/ */
void ARC_Config_FileIO(ARC_Config *config, ARC_String *path, uint8_t command); void ARC_Config_LoadFromFile(ARC_Config *config, ARC_String *path);
/**
* @brief TODO: write this
*/
void ARC_Config_UnloadFromString(ARC_Config *config, ARC_String **string);
/**
* @brief TODO: write this
*/
void ARC_Config_UnloadFromFile(ARC_Config *config, ARC_String *data);
#define ARC_CONFIG_DEFAULT_GROUP " "
#define ARC_CONFIG_GROUP_TAG_NAME "group"
#define ARC_CONFIG_GROUP_SEPARATOR "::"
//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)
#define ARC_CONFIG_TAB 0x01
#define ARC_CONFIG_NEWLINE 0x02
#define ARC_CONFIG_SPACE 0x03
#define ARC_CONFIG_BANG 0x04
#define ARC_CONFIG_QUOTE 0x05
#define ARC_CONFIG_HASH 0x06
#define ARC_CONFIG_DOLLAR 0x07
#define ARC_CONFIG_PERCENT 0x08
#define ARC_CONFIG_AMPERSAND 0x09
#define ARC_CONFIG_SINGLE_QUOTE 0x0A
#define ARC_CONFIG_OPEN_PAREN 0x0B
#define ARC_CONFIG_CLOSE_PAREN 0x0C
#define ARC_CONFIG_ASTERISK 0x0D
#define ARC_CONFIG_PLUS 0x0E
#define ARC_CONFIG_COMMA 0x0F
#define ARC_CONFIG_MINUS 0x10
#define ARC_CONFIG_PERIOD 0x11
#define ARC_CONFIG_SLASH 0x12
#define ARC_CONFIG_NUMBER 0x13
#define ARC_CONFIG_COLON 0x14
#define ARC_CONFIG_SEMICOLON 0x15
#define ARC_CONFIG_LESS_THAN 0x16
#define ARC_CONFIG_GREATER_THAN 0x17
#define ARC_CONFIG_EQUAL 0x18
#define ARC_CONFIG_QUESTION_MARK 0x19
#define ARC_CONFIG_AT 0x1A
#define ARC_CONFIG_ALPHA_UPPER_CHAR 0x1B
#define ARC_CONFIG_OPEN_BRACKET 0x1C
#define ARC_CONFIG_BACKSLASH 0x1D
#define ARC_CONFIG_CLOSE_BRACKET 0x1E
#define ARC_CONFIG_CARET 0x1F
#define ARC_CONFIG_UNDERSCORE 0x20
#define ARC_CONFIG_GRAVE 0x21
#define ARC_CONFIG_ALPHA_LOWER_CHAR 0x22
#define ARC_CONFIG_OPEN_CURLY_BRACE 0x23
#define ARC_CONFIG_VERTICAL_LINE 0x24
#define ARC_CONFIG_CLOSE_CURLY_BRACE 0x25
#define ARC_CONFIG_TILDE 0x26
#define ARC_CONFIG_LANGUAGE 0x27
#define ARC_CONFIG_GROUP 0x28
#define ARC_CONFIG_GROUP_NAME 0x29
#define ARC_CONFIG_GROUP_ARGS 0x2A
#define ARC_CONFIG_VARIABLE_LINES 0x2B
#define ARC_CONFIG_VARIABLE_LINE 0x2C
#define ARC_CONFIG_ALLOW_SPACE 0x2D
#define ARC_CONFIG_TYPE 0x2E
#define ARC_CONFIG_VALUE 0x2F
#define ARC_CONFIG_NESTED_VALUE 0x30
#define ARC_CONFIG_VALUE_ARGS 0x31
#define ARC_CONFIG_VARIABLE 0x32
#define ARC_CONFIG_VARIABLE_NAME 0x33
#define ARC_CONFIG_VARIABLE_CHAR 0x34
#define ARC_CONFIG_STRING 0x35
#define ARC_CONFIG_STRING_CHARS 0x36
#define ARC_CONFIG_STRING_CHAR 0x37
#define ARC_CONFIG_ESCAPE_CHAR 0x38
#define ARC_CONFIG_NUMBER_SIGN 0x39
#define ARC_CONFIG_NUMBER_TAG 0x3A
#define ARC_CONFIG_WHITESPACE 0x3B
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
#endif //ARC_STD_CONFIG_H_ #endif //ARC_STD_CONFIG_H_
#ifdef ARC_DEFAULT_CONFIG
#include "defaults/config.h"
#endif //ARC_DEFAULT_CONFIG

View file

@ -1,17 +0,0 @@
#ifndef ARC_STD_LIFE_H_
#define ARC_STD_LIFE_H_
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief an entity component system type
*/
typedef struct ARC_Life ARC_Life;
#ifdef __cplusplus
}
#endif
#endif // !ARC_STD_LIFE_H_

View file

@ -1,751 +0,0 @@
#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 <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
struct ARC_Chemical {
ARC_Parser *parser;
ARC_Hashtable *types;
ARC_Hashtable *groups;
ARC_Hashtable *currentGroup;
ARC_Bool load;
};
typedef struct ARC_ChemicalTypeData {
void *data;
ARC_ChemicalType_DestroyFn destroyFn;
} ARC_ChemicalTypeData;
void ARC_Chemical_InitLexerRulesFn(ARC_Lexer *lexer){
ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CHEMICAL_TAB , '\t'));
ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CHEMICAL_NEWLINE, '\n'));
ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CHEMICAL_SPACE , ' ' ));
ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CHEMICAL_BANG , '!' ));
ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CHEMICAL_QUOTE , '"' ));
ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CHEMICAL_HASH , '#' ));
ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CHEMICAL_DOLLAR , '$' ));
ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CHEMICAL_PERCENT , '%' ));
ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CHEMICAL_AMPERSAND , '&' ));
ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CHEMICAL_SINGLE_QUOTE, '\''));
ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CHEMICAL_OPEN_PAREN , '(' ));
ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CHEMICAL_CLOSE_PAREN , ')' ));
ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CHEMICAL_ASTERISK , '*' ));
ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CHEMICAL_PLUS , '+' ));
ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CHEMICAL_COMMA , ',' ));
ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CHEMICAL_MINUS , '-' ));
ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CHEMICAL_PERIOD , '.' ));
ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CHEMICAL_SLASH , '/' ));
ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharOrBetween(ARC_CHEMICAL_NUMBER , '0', '9'));
ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CHEMICAL_COLON , ':'));
ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CHEMICAL_SEMICOLON , ';'));
ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CHEMICAL_LESS_THAN , '<'));
ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CHEMICAL_GREATER_THAN , '>'));
ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CHEMICAL_EQUAL , '='));
ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CHEMICAL_QUESTION_MARK, '?'));
ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CHEMICAL_AT , '@'));
ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharOrBetween(ARC_CHEMICAL_ALPHA_UPPER_CHAR, 'A', 'Z'));
ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CHEMICAL_OPEN_BRACKET , '[' ));
ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CHEMICAL_BACKSLASH , '\\'));
ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CHEMICAL_CLOSE_BRACKET, ']' ));
ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CHEMICAL_CARET , '^' ));
ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CHEMICAL_UNDERSCORE , '_' ));
ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CHEMICAL_GRAVE , '`' ));
ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharOrBetween(ARC_CHEMICAL_ALPHA_LOWER_CHAR, 'a', 'z'));
ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CHEMICAL_OPEN_CURLY_BRACE , '{'));
ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CHEMICAL_VERTICAL_LINE , '|'));
ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CHEMICAL_CLOSE_CURLY_BRACE, '}'));
ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CHEMICAL_TILDE , '~'));
}
uint32_t ARC_Chemical_GetStringIdFn(ARC_String *string){
if(ARC_String_EqualsCStringWithStrlen(string, "LAMBDA")){
return ARC_PARSER_TAG_LAMBDA;
}
if(ARC_String_EqualsCStringWithStrlen(string, "TAB")){
return ARC_CHEMICAL_TAB;
}
if(ARC_String_EqualsCStringWithStrlen(string, "NEWLINE")){
return ARC_CHEMICAL_NEWLINE;
}
if(ARC_String_EqualsCStringWithStrlen(string, "SPACE")){
return ARC_CHEMICAL_SPACE;
}
if(ARC_String_EqualsCStringWithStrlen(string, "BANG")){
return ARC_CHEMICAL_BANG;
}
if(ARC_String_EqualsCStringWithStrlen(string, "QUOTE")){
return ARC_CHEMICAL_QUOTE;
}
if(ARC_String_EqualsCStringWithStrlen(string, "HASH")){
return ARC_CHEMICAL_HASH;
}
if(ARC_String_EqualsCStringWithStrlen(string, "DOLLAR")){
return ARC_CHEMICAL_DOLLAR;
}
if(ARC_String_EqualsCStringWithStrlen(string, "PERCENT")){
return ARC_CHEMICAL_PERCENT;
}
if(ARC_String_EqualsCStringWithStrlen(string, "AMPERSAND")){
return ARC_CHEMICAL_AMPERSAND;
}
if(ARC_String_EqualsCStringWithStrlen(string, "SINGLE_QUOTE")){
return ARC_CHEMICAL_SINGLE_QUOTE;
}
if(ARC_String_EqualsCStringWithStrlen(string, "OPEN_PAREN")){
return ARC_CHEMICAL_OPEN_PAREN;
}
if(ARC_String_EqualsCStringWithStrlen(string, "CLOSE_PAREN")){
return ARC_CHEMICAL_CLOSE_PAREN;
}
if(ARC_String_EqualsCStringWithStrlen(string, "ASTERISK")){
return ARC_CHEMICAL_ASTERISK;
}
if(ARC_String_EqualsCStringWithStrlen(string, "PLUS")){
return ARC_CHEMICAL_PLUS;
}
if(ARC_String_EqualsCStringWithStrlen(string, "COMMA")){
return ARC_CHEMICAL_COMMA;
}
if(ARC_String_EqualsCStringWithStrlen(string, "MINUS")){
return ARC_CHEMICAL_MINUS;
}
if(ARC_String_EqualsCStringWithStrlen(string, "PERIOD")){
return ARC_CHEMICAL_PERIOD;
}
if(ARC_String_EqualsCStringWithStrlen(string, "SLASH")){
return ARC_CHEMICAL_SLASH;
}
if(ARC_String_EqualsCStringWithStrlen(string, "NUMBER")){
return ARC_CHEMICAL_NUMBER;
}
if(ARC_String_EqualsCStringWithStrlen(string, "COLON")){
return ARC_CHEMICAL_COLON;
}
if(ARC_String_EqualsCStringWithStrlen(string, "SEMICOLON")){
return ARC_CHEMICAL_SEMICOLON;
}
if(ARC_String_EqualsCStringWithStrlen(string, "LESS_THAN")){
return ARC_CHEMICAL_LESS_THAN;
}
if(ARC_String_EqualsCStringWithStrlen(string, "GREATER_THAN")){
return ARC_CHEMICAL_GREATER_THAN;
}
if(ARC_String_EqualsCStringWithStrlen(string, "EQUAL")){
return ARC_CHEMICAL_EQUAL;
}
if(ARC_String_EqualsCStringWithStrlen(string, "QUESTION_MARK")){
return ARC_CHEMICAL_QUESTION_MARK;
}
if(ARC_String_EqualsCStringWithStrlen(string, "AT")){
return ARC_CHEMICAL_AT;
}
if(ARC_String_EqualsCStringWithStrlen(string, "ALPHA_UPPER_CHAR")){
return ARC_CHEMICAL_ALPHA_UPPER_CHAR;
}
if(ARC_String_EqualsCStringWithStrlen(string, "OPEN_BRACKET")){
return ARC_CHEMICAL_OPEN_BRACKET;
}
if(ARC_String_EqualsCStringWithStrlen(string, "BACKSLASH")){
return ARC_CHEMICAL_BACKSLASH;
}
if(ARC_String_EqualsCStringWithStrlen(string, "CLOSE_BRACKET")){
return ARC_CHEMICAL_CLOSE_BRACKET;
}
if(ARC_String_EqualsCStringWithStrlen(string, "CARET")){
return ARC_CHEMICAL_CARET;
}
if(ARC_String_EqualsCStringWithStrlen(string, "UNDERSCORE")){
return ARC_CHEMICAL_UNDERSCORE;
}
if(ARC_String_EqualsCStringWithStrlen(string, "GRAVE")){
return ARC_CHEMICAL_GRAVE;
}
if(ARC_String_EqualsCStringWithStrlen(string, "ALPHA_LOWER_CHAR")){
return ARC_CHEMICAL_ALPHA_LOWER_CHAR;
}
if(ARC_String_EqualsCStringWithStrlen(string, "OPEN_CURLY_BRACE")){
return ARC_CHEMICAL_OPEN_CURLY_BRACE;
}
if(ARC_String_EqualsCStringWithStrlen(string, "VERTICAL_LINE")){
return ARC_CHEMICAL_VERTICAL_LINE;
}
if(ARC_String_EqualsCStringWithStrlen(string, "CLOSE_CURLY_BRACE")){
return ARC_CHEMICAL_CLOSE_CURLY_BRACE;
}
if(ARC_String_EqualsCStringWithStrlen(string, "TILDE")){
return ARC_CHEMICAL_TILDE;
}
if(ARC_String_EqualsCStringWithStrlen(string, "<language>")){
return ARC_CHEMICAL_LANGUAGE;
}
if(ARC_String_EqualsCStringWithStrlen(string, "<group>")){
return ARC_CHEMICAL_GROUP;
}
if(ARC_String_EqualsCStringWithStrlen(string, "<groupName>")){
return ARC_CHEMICAL_GROUP_NAME;
}
if(ARC_String_EqualsCStringWithStrlen(string, "<groupArgs>")){
return ARC_CHEMICAL_GROUP_ARGS;
}
if(ARC_String_EqualsCStringWithStrlen(string, "<variableLines>")){
return ARC_CHEMICAL_VARIABLE_LINES;
}
if(ARC_String_EqualsCStringWithStrlen(string, "<variableLine>")){
return ARC_CHEMICAL_VARIABLE_LINE;
}
if(ARC_String_EqualsCStringWithStrlen(string, "<allowSpace>")){
return ARC_CHEMICAL_ALLOW_SPACE;
}
if(ARC_String_EqualsCStringWithStrlen(string, "<type>")){
return ARC_CHEMICAL_TYPE;
}
if(ARC_String_EqualsCStringWithStrlen(string, "<value>")){
return ARC_CHEMICAL_VALUE;
}
if(ARC_String_EqualsCStringWithStrlen(string, "<nestedValue>")){
return ARC_CHEMICAL_NESTED_VALUE;
}
if(ARC_String_EqualsCStringWithStrlen(string, "<valueArgs>")){
return ARC_CHEMICAL_VALUE_ARGS;
}
if(ARC_String_EqualsCStringWithStrlen(string, "<variable>")){
return ARC_CHEMICAL_VARIABLE;
}
if(ARC_String_EqualsCStringWithStrlen(string, "<variableName>")){
return ARC_CHEMICAL_VARIABLE_NAME;
}
if(ARC_String_EqualsCStringWithStrlen(string, "<variableChar>")){
return ARC_CHEMICAL_VARIABLE_CHAR;
}
if(ARC_String_EqualsCStringWithStrlen(string, "<string>")){
return ARC_CHEMICAL_STRING;
}
if(ARC_String_EqualsCStringWithStrlen(string, "<stringChars>")){
return ARC_CHEMICAL_STRING_CHARS;
}
if(ARC_String_EqualsCStringWithStrlen(string, "<stringChar>")){
return ARC_CHEMICAL_STRING_CHAR;
}
if(ARC_String_EqualsCStringWithStrlen(string, "<escapeChar>")){
return ARC_CHEMICAL_ESCAPE_CHAR;
}
if(ARC_String_EqualsCStringWithStrlen(string, "<numberSign>")){
return ARC_CHEMICAL_NUMBER_SIGN;
}
if(ARC_String_EqualsCStringWithStrlen(string, "<number>")){
return ARC_CHEMICAL_NUMBER_TAG;
}
if(ARC_String_EqualsCStringWithStrlen(string, "<whitespace>")){
return ARC_CHEMICAL_WHITESPACE;
}
return ~(uint32_t)0;
}
//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);
}
//<variableLine> -> <whitespace> <type> <whitespace> <variable> <whitespace> EQUAL <whitespace> <value> <whitespace> SEMICOLON
void ARC_ChemicalData_RunVariableLineTag(ARC_ParserTagToken *tagToken, ARC_Chemical *chemical){
//skip whitespace and check for group name
ARC_ParserTagToken *childTagToken = (ARC_ParserTagToken *)ARC_Vector_Get(tagToken->tagTokens, 1);
//get the type
ARC_String *typeString;
ARC_String_Create(&typeString, NULL, 0);
ARC_ParserData_HelperRecurseStringAdd(&typeString, childTagToken);
//check if type exists in the types hashtable
ARC_ChemicalType *type = (ARC_ChemicalType *)ARC_Hashtable_Get(chemical->types, typeString->data);
if(type == NULL){
//throw an error and return
arc_errno = ARC_ERRNO_DATA;
ARC_DEBUG_LOG_ERROR_WITH_VARIABLES("ARC_ChemicalData_RunVariableLineTag(tagToken, chemical), type \"%s\" was not registered to chemical", typeString->data);
ARC_String_Destroy(typeString);
return;
}
//cleanup
ARC_String_Destroy(typeString);
//get the variable
childTagToken = (ARC_ParserTagToken *)ARC_Vector_Get(tagToken->tagTokens, 3);
ARC_String *variableString;
ARC_String_Create(&variableString, NULL, 0);
ARC_ParserData_HelperRecurseStringAdd(&variableString, childTagToken);
//check if removing
if(chemical->load == ARC_False){
ARC_Hashtable_Remove(chemical->currentGroup, (void *)variableString->data);
ARC_String_Destroy(variableString);
return;
}
//check to see if the current variable is already in the current group hashtable
ARC_ChemicalTypeData *typeData = (ARC_ChemicalTypeData *)ARC_Hashtable_Get(chemical->currentGroup, variableString->data);
if(typeData != NULL){
//there is already a value so throw an error and return
arc_errno = ARC_ERRNO_DATA;
ARC_DEBUG_LOG_ERROR_WITH_VARIABLES("ARC_ChemicalData_RunVariableLineTag(tagToken, chemical), variable \"%s\" already registered to the current group", variableString->data);
ARC_String_Destroy(variableString);
return;
}
//copy the string into a cstring that will be stored in the hashtable
char *elementVariableCStr = malloc(sizeof(char) * (variableString->length + 1));
strncpy(elementVariableCStr, variableString->data, variableString->length);
elementVariableCStr[variableString->length] = '\0';
ARC_String_Destroy(variableString);
//get <value>
childTagToken = (ARC_ParserTagToken *)ARC_Vector_Get(tagToken->tagTokens, 7);
//check if <value> is a reference
ARC_String *valueString;
ARC_String_Create(&valueString, NULL, 0);
ARC_ParserData_HelperRecurseStringAdd(&valueString, childTagToken);
void *value = ARC_Hashtable_Get(chemical->currentGroup, valueString);
ARC_String_Destroy(valueString);
//create where to store either the reference or type data
typeData = (ARC_ChemicalTypeData *)malloc(sizeof(ARC_ChemicalTypeData));
if(value != NULL){
//point to the already stored data
typeData->data = value;
typeData->destroyFn = NULL;
//add to the current group hashtable
ARC_Hashtable_Add(chemical->currentGroup, (void *)elementVariableCStr, (void *)typeData);
return;
}
//passed the parsed value into the copy type function and set the destroy function
type->copyFn(&(typeData->data), childTagToken, chemical);
typeData->destroyFn = type->destroyFn;
//add to the current group hashtable
ARC_Hashtable_Add(chemical->currentGroup, (void *)elementVariableCStr, (void *)typeData);
}
//<variableLines> -> <variableLine> <whitespace> <variableLines> | <variableLine>
void ARC_ChemicalData_RunVariableLinesTag(ARC_ParserTagToken *tagToken, ARC_Chemical *chemical){
//loop through the tags either going to the next line or the next body
for(uint32_t index = 0; index < ARC_Vector_GetSize(tagToken->tagTokens); index++){
ARC_ParserTagToken *childTagToken = (ARC_ParserTagToken *)ARC_Vector_Get(tagToken->tagTokens, index);
switch(childTagToken->id){
//recuse to run the next line
case ARC_CHEMICAL_VARIABLE_LINES:
ARC_ChemicalData_RunVariableLinesTag(childTagToken, chemical);
if(arc_errno != 0){
ARC_DEBUG_LOG_ERROR("ARC_ChemicalData_RunVariableLinesTag(tagToken, chemical), chemical errored when trying to used parsed data for variable lines");
return;
}
continue;
//recurse into a variable line tag
case ARC_CHEMICAL_VARIABLE_LINE:
ARC_ChemicalData_RunVariableLineTag(childTagToken, chemical);
if(arc_errno != 0){
ARC_DEBUG_LOG_ERROR("ARC_ChemicalData_RunVariableLinesTag(tagToken, chemical), chemical errored when trying to used parsed data for variable line");
return;
}
continue;
//this is for whitespace and any oddities
default:
continue;
}
}
}
//<group> -> <whitespace> <groupName> <whitespace> <variable> <whitespace> OPEN_CURLY_BRACE <groupArgs> <whitespace> CLOSE_CURLY_BRACE
void ARC_ChemicalData_RunGroupTag(ARC_ParserTagToken *tagToken, ARC_Chemical *chemical){
//skip whitespace and check for group name
ARC_ParserTagToken *childTagToken = (ARC_ParserTagToken *)ARC_Vector_Get(tagToken->tagTokens, 1);
/* ~ <groupName> ~ */
//get the group name and check if it is named "group"
//NOTE: this check may be usedful in the future if there is different functionality for group like tag names
ARC_String *groupName;
ARC_String_Create(&groupName, NULL, 0);
ARC_ParserData_HelperRecurseStringAdd(&groupName, childTagToken);
if(ARC_String_EqualsCStringWithStrlen(groupName, ARC_CHEMICAL_GROUP_TAG_NAME) == ARC_False){
//throw an error and return
arc_errno = ARC_ERRNO_DATA;
ARC_DEBUG_LOG_ERROR_WITH_VARIABLES("ARC_ChemicalData_RunGroupTag(tagToken, chemical), chemical contained keyword \"%s\" instead of using the correct keyword: \"%s\" ", groupName->data, ARC_CHEMICAL_GROUP_TAG_NAME);
ARC_String_Destroy(groupName);
return;
}
//cleanup
ARC_String_Destroy(groupName);
/* ~ <variable> ~ */
//get the group's variable name
childTagToken = (ARC_ParserTagToken *)ARC_Vector_Get(tagToken->tagTokens, 3);
ARC_String *groupVariable;
ARC_String_Create(&groupVariable, NULL, 0);
ARC_ParserData_HelperRecurseStringAdd(&groupVariable, childTagToken);
//check if removing
if(chemical->load == ARC_False){
/* ~ <groupArgs> ~ */
childTagToken = (ARC_ParserTagToken *)ARC_Vector_Get(tagToken->tagTokens, 6);
//<groupArgs> -> <whitespace> <variableLines> | LAMBDA
if(childTagToken->token == NULL && ARC_Vector_GetSize(childTagToken->tagTokens) == 2){
ARC_ParserTagToken *variableLines = (ARC_ParserTagToken *)ARC_Vector_Get(childTagToken->tagTokens, 1);
ARC_ChemicalData_RunVariableLinesTag(variableLines, chemical);
//log error if it happens
if(arc_errno != 0){
ARC_DEBUG_LOG_ERROR("ARC_ChemicalData_RunGroupTag(tagToken, chemical), chemical errored when trying to used parsed data for variable lines");
}
}
//remove an empty hashtable if it is now empty
if(ARC_Hashtable_GetSize(chemical->groups)){
ARC_String_Destroy(groupVariable);
}
return;
}
//get the needed hashtable or create it from the groups hashtable
ARC_Hashtable *groupHashtable = ARC_Hashtable_Get(chemical->groups, (void *)groupVariable->data);
if(groupHashtable == NULL){
//copy the string into a cstring that will be stored in the hashtable
char *groupVariableCStr = malloc(sizeof(char) * (groupVariable->length + 1));
strncpy(groupVariableCStr, groupVariable->data, groupVariable->length);
groupVariableCStr[groupVariable->length] = '\0';
//create the hashtable with the given group name key
ARC_Hashtable_KeyCompareFn keyCompareFn = ARC_Chemical_HashtableKeyCompareFn;
ARC_Hashtable_DestroyKeyValueFn groupDataDestroyKeyValueFn = ARC_Chemical_GroupDataHashtableDestroyKeyValueFn;
ARC_Hashtable_Create(&groupHashtable, NULL, &keyCompareFn, &groupDataDestroyKeyValueFn);
ARC_Hashtable_Add(chemical->groups, (void *)groupVariableCStr, (void *)groupHashtable);
}
//cleanup
ARC_String_Destroy(groupVariable);
//set the current group to the group just created or found
chemical->currentGroup = groupHashtable;
/* ~ <groupArgs> ~ */
childTagToken = (ARC_ParserTagToken *)ARC_Vector_Get(tagToken->tagTokens, 6);
//<groupArgs> -> <whitespace> <variableLines> | LAMBDA
if(childTagToken->token == NULL && ARC_Vector_GetSize(childTagToken->tagTokens) == 2){
ARC_ParserTagToken *variableLines = (ARC_ParserTagToken *)ARC_Vector_Get(childTagToken->tagTokens, 1);
ARC_ChemicalData_RunVariableLinesTag(variableLines, chemical);
//log error if it happens, but as setting the group back is the last thing we shouldn't return
if(arc_errno != 0){
ARC_DEBUG_LOG_ERROR("ARC_ChemicalData_RunGroupTag(tagToken, chemical), chemical errored when trying to used parsed data for variable lines");
}
}
/* ~ reset current group ~ */
chemical->currentGroup = ARC_Hashtable_Get(chemical->groups, (void *)ARC_CHEMICAL_DEFAULT_GROUP);
}
//<language> -> <group> <language> | <variableLines> <language> | <whitespace>
void ARC_ChemicalData_RunLanguageTag(ARC_ParserTagToken *tagToken, ARC_Chemical *chemical){
//loop through the tags either going to the next language, group, or variable lines
for(uint32_t index = 0; index < ARC_Vector_GetSize(tagToken->tagTokens); index++){
ARC_ParserTagToken *childTagToken = (ARC_ParserTagToken *)ARC_Vector_Get(tagToken->tagTokens, index);
switch(childTagToken->id){
//recuse to run the next line
case ARC_CHEMICAL_LANGUAGE:
ARC_ChemicalData_RunLanguageTag(childTagToken, chemical);
continue;
//recurse into a group tag
case ARC_CHEMICAL_GROUP:
ARC_ChemicalData_RunGroupTag(childTagToken, chemical);
if(arc_errno != 0){
ARC_DEBUG_LOG_ERROR("ARC_ChemicalData_RunLanguageTag(tagToken, chemical), chemical errored when trying to used parsed data for a group");
return;
}
continue;
//recurse through variable lines
case ARC_CHEMICAL_VARIABLE_LINES:
ARC_ChemicalData_RunVariableLinesTag(childTagToken, chemical);
ARC_ChemicalData_RunGroupTag(childTagToken, chemical);
if(arc_errno != 0){
ARC_DEBUG_LOG_ERROR("ARC_ChemicalData_RunLanguageTag(tagToken, chemical), chemical errored when trying to used parsed data for variable lines");
return;
}
continue;
//this is for whitespace and any oddities
default:
continue;
}
}
}
void ARC_ChemicalData_CreateFn(void **data, ARC_ParserTagToken *parsedData, void *userData){
*data = NULL;
if(parsedData == NULL || userData == NULL){
//TODO: error here?
*data = NULL;
return;
}
ARC_ChemicalData_RunLanguageTag(parsedData, (ARC_Chemical *)userData);
}
void ARC_ChemicalData_DestroyFn(void *data, ARC_Bool clear, void *userData){
return;
}
void ARC_Chemical_Create(ARC_Chemical **chemical){
*chemical = (ARC_Chemical *)malloc(sizeof(ARC_Chemical));
/* ~ define the language as a string ~ */
char *languageCString =
"<language> -> <group> <language> | <variableLines> <language> | <whitespace>\n"
"<group> -> <whitespace> <groupName> <whitespace> <variable> <whitespace> OPEN_CURLY_BRACE <groupArgs> <whitespace> CLOSE_CURLY_BRACE\n"
"<groupName> -> <variable>\n"
"<groupArgs> -> <whitespace> <variableLines> | LAMBDA\n"
"<variableLines> -> <variableLine> <whitespace> <variableLines> | <variableLine>\n"
"<variableLine> -> <whitespace> <type> <whitespace> <variable> <whitespace> EQUAL <whitespace> <value> <whitespace> SEMICOLON\n"
"<allowSpace> -> SPACE <allowSpace> | TAB <allowSpace> | LAMBDA\n"
"<type> -> <variable>\n"
"<value> -> <variable> | <numberSign> | <string> | <nestedValue>\n"
"<nestedValue> -> OPEN_CURLY_BRACE <whitespace> <valueArgs> <whitespace> CLOSE_CURLY_BRACE\n"
"<valueArgs> -> <value> COMMA <valueArgs> | <value>\n"
"<variable> -> ALPHA_UPPER_CHAR <variableName> | ALPHA_LOWER_CHAR <variableName> | UNDERSCORE <variableName>\n"
"<variableName> -> <variableChar> <variableName> | LAMBDA\n"
"<variableChar> -> ALPHA_UPPER_CHAR | ALPHA_LOWER_CHAR | UNDERSCORE | NUMBER\n"
"<string> -> QUOTE <stringChars> QUOTE\n"
"<stringChars> -> <stringChar> <stringChars> | <escapeChar> <stringChars> | LAMBDA\n"
"<stringChar> -> TAB | SPACE | BANG | HASH | DOLLAR | PERCENT | AMPERSAND | SINGLE_QUOTE | OPEN_PAREN | CLOSE_PAREN | ASTERISK | PLUS | COMMA | MINUS | PERIOD | SLASH | NUMBER | COLON | SEMICOLON | LESS_THAN | GREATER_THAN | EQUAL | QUESTION_MARK | AT | ALPHA_UPPER_CHAR | OPEN_BRACKET | CLOSE_BRACKET | CARET | UNDERSCORE | GRAVE | ALPHA_LOWER_CHAR | OPEN_CURLY_BRACE | VERTICAL_LINE | CLOSE_CURLY_BRACE | TILDE\n"
"<escapeChar> -> BACKSLASH BACKSLASH | BACKSLASH QUOTE | BACKSLASH ALPHA_UPPER_CHAR | BACKSLASH ALPHA_LOWER_CHAR\n"
"<numberSign> -> MINUS <number> | <number>\n"
"<number> -> NUMBER <number> | NUMBER\n"
"<whitespace> -> SPACE <whitespace> | TAB <whitespace> | NEWLINE <whitespace> | LAMBDA\n";
/* ~ define the language as a string ~ */
ARC_String *languageString;
ARC_String_CreateWithStrlen(&languageString, languageCString);
/* ~ set chemical as userdata ~ */
void *userdata = *chemical;
/* ~ create the language ~ */
ARC_ParserData_CreateFn createCharFn = ARC_ChemicalData_CreateFn;
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;
//copy empty group cstring (to be freed by hashtable on cleanup, passing directly would cause a segfault)
char *emptyCStr = (char *)malloc(sizeof(char) * (strlen(ARC_CHEMICAL_DEFAULT_GROUP) + 1));
strcpy(emptyCStr, ARC_CHEMICAL_DEFAULT_GROUP);
//set the current group as empty, then add that into the groups hashtable
ARC_Hashtable_Create(&((*chemical)->currentGroup), NULL, &keyCompareFn, &groupDataDestroyKeyValueFn);
ARC_Hashtable_Add((*chemical)->groups, (void *)emptyCStr, (*chemical)->currentGroup);
(*chemical)->load = ARC_True;
//cleanup
ARC_String_Destroy(languageString);
}
void ARC_Chemical_Destroy(ARC_Chemical *chemical){
ARC_Parser_Destroy(chemical->parser);
//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_RegisterType(ARC_Chemical *chemical, ARC_String *typeName, ARC_ChemicalType type){
ARC_Chemical_RegisterTypeWithCStr(chemical, typeName->data, type);
}
void ARC_Chemical_RegisterTypeWithCStr(ARC_Chemical *chemical, const char *typeNameCStr, ARC_ChemicalType type){
//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
uint64_t typeNameCopyLength = strlen(typeNameCStr) + 1;
char *typeNameCopy = (char *)malloc(sizeof(char) * typeNameCopyLength);
strncpy(typeNameCopy, typeNameCStr, typeNameCopyLength);
typeNameCopy[strlen(typeNameCStr)] = '\0';
//copy the type for long term storage
ARC_ChemicalType *typeCopy = (ARC_ChemicalType *)malloc(sizeof(ARC_ChemicalType));
*typeCopy = type;
//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 *energy){
//check if the group separator exists
uint64_t startSeparatorIndex = ARC_String_FindCStringWithStrlen(energy, ARC_CHEMICAL_GROUP_SEPARATOR);
if(startSeparatorIndex == ~(uint64_t)0){
//use empty group
chemical->currentGroup = ARC_Hashtable_Get(chemical->groups, (void *)ARC_CHEMICAL_DEFAULT_GROUP);
//get the typeData and pass back the data without the cleanup function
ARC_ChemicalTypeData *typeData = (ARC_ChemicalTypeData *)ARC_Hashtable_Get(chemical->currentGroup, (void *)energy->data);
if(typeData == NULL){
return NULL;
}
return typeData->data;
}
//get the group
startSeparatorIndex--;
ARC_String *groupString;
ARC_String_CopySubstring(&groupString, energy, 0, startSeparatorIndex);
//set the group
chemical->currentGroup = ARC_Hashtable_Get(chemical->groups, (void *)groupString->data);
//cleanup
ARC_String_Destroy(groupString);
//get the element
ARC_String *energyString;
startSeparatorIndex += strlen(ARC_CHEMICAL_GROUP_SEPARATOR);
ARC_String_CopySubstring(&energyString, energy, startSeparatorIndex, energy->length - startSeparatorIndex);
//this will either return the value or NULL
ARC_ChemicalTypeData *typeData = (ARC_ChemicalTypeData *)ARC_Hashtable_Get(chemical->currentGroup, (void *)energyString->data);
ARC_String_Destroy(energyString);
if(typeData == NULL){
return NULL;
}
return typeData->data;
}
void *ARC_Chemical_GetWithCStr(ARC_Chemical *chemical, const char *energy){
//create and copy into ARC_String
ARC_String *energyString;
ARC_String_CreateWithStrlen(&energyString, (char *)energy);
//get the return value
void *returnValue = ARC_Chemical_Get(chemical, energyString);
//cleanup
ARC_String_Destroy(energyString);
return returnValue;
}
void ARC_Chemical_LoadFromString(ARC_Chemical *chemical, ARC_String **string){
chemical->load = ARC_True;
ARC_Parser_Parse(chemical->parser, string);
}
void ARC_Chemical_LoadFromFile(ARC_Chemical *chemical, ARC_String *path){
chemical->load = ARC_True;
ARC_Parser_ParseFile(chemical->parser, path);
}
void ARC_Chemical_UnloadFromString(ARC_Chemical *chemical, ARC_String **string){
chemical->load = ARC_False;
ARC_Parser_Parse(chemical->parser, string);
}
void ARC_Chemical_UnloadFromFile(ARC_Chemical *chemical, ARC_String *path){
chemical->load = ARC_False;
ARC_Parser_ParseFile(chemical->parser, path);
}

File diff suppressed because it is too large Load diff

View file

View file

@ -1,5 +0,0 @@
group test {
int32 test = 5;
int32 test1 = -7;
}

View file

@ -1,108 +0,0 @@
#include "../test.h"
#include "arc/std/errno.h"
#include "arc/std/chemical.h"
#include "arc/std/parser.h"
#include "arc/std/parser/helpers.h"
#include <stdlib.h>
static const char *testType = "int32";
void TEST_ChemicalType_CopyInt32Fn(void **type, ARC_ParserTagToken *parsedData, ARC_Chemical *chemical){
//go into the <numberSign> tag
ARC_ParserTagToken *childTagToken = (ARC_ParserTagToken *)ARC_Vector_Get(parsedData->tagTokens, 0);
if(childTagToken->id != ARC_CHEMICAL_NUMBER_SIGN){
arc_errno = ARC_ERRNO_DATA;
ARC_DEBUG_LOG_ERROR("TEST_ChemicalType_CopyInt32Fn(type, parsedData, chemical), parsed data was not a <numberSign>");
*type = NULL;
return;
}
//check if the first tag is a minus sign and create a string starting with that if it is
childTagToken = (ARC_ParserTagToken *)ARC_Vector_Get(childTagToken->tagTokens, 0);
ARC_String *int32String;
ARC_String_Create(&int32String, NULL, 0);
if(childTagToken->id == ARC_CHEMICAL_MINUS){
ARC_String_AppendCStringWithStrlen(&int32String, "-");
}
ARC_ParserData_HelperRecurseStringAdd(&int32String, parsedData);
//set the max character size 2,147,483,647 (10 characters) or -2,147,483,648 (11 characters)
uint32_t maxInt32Size = 10;
if(int32String->data[0] == '-'){
maxInt32Size++;
}
//if the string is bigger than the possible size return NULL and error
if(int32String->length > maxInt32Size){
arc_errno = ARC_ERRNO_DATA;
ARC_DEBUG_LOG_ERROR_WITH_VARIABLES("TEST_ChemicalType_CopyInt32Fn(type, parsedData, chemical), size \"%s\" was bigger or smaller than the max 2,147,483,647 or min -2,147,483,648", int32String->data);
*type = NULL;
ARC_String_Destroy(int32String);
return;
}
if(int32String->length == maxInt32Size){
char maxint32CStr[10] = "2147483647";
//offset starting index and last number if there is a negative
uint8_t stringIndex = 0;
if(int32String->data[0] == '-'){
stringIndex++;
maxint32CStr[9]++;
}
for(uint8_t index = 0; index < 10; index++, stringIndex++){
if(int32String->data[stringIndex] > maxint32CStr[index]){
arc_errno = ARC_ERRNO_DATA;
ARC_DEBUG_LOG_ERROR_WITH_VARIABLES("TEST_ChemicalType_CopyInt32Fn(type, parsedData, chemical), size \"%s\" was bigger or smaller than the max 2,147,483,647 or min -2,147,483,648", int32String->data);
*type = NULL;
ARC_String_Destroy(int32String);
return;
}
}
}
//copy the int32_t
*type = malloc(sizeof(int32_t));
*(int32_t *)(*type) = (int32_t)ARC_String_ToInt64_t(int32String);
//cleanup
ARC_String_Destroy(int32String);
}
void TEST_ChemicalType_DestroyInt32Fn(void *type){
free((int32_t *)type);
}
ARC_TEST(Chemical_BasicTest){
ARC_Chemical *chemical;
ARC_Chemical_Create(&chemical);
ARC_CHECK(arc_errno == 0);
ARC_ChemicalType int32Type = {
TEST_ChemicalType_CopyInt32Fn,
TEST_ChemicalType_DestroyInt32Fn
};
ARC_Chemical_RegisterTypeWithCStr(chemical, testType, int32Type);
char *tempCString = "tests/res/std/chemical/first.chemical";
ARC_String *tempString;
ARC_String_CreateWithStrlen(&tempString, tempCString);
ARC_Chemical_LoadFromFile(chemical, tempString);
int32_t testVal = *(int32_t *)ARC_Chemical_GetWithCStr(chemical, "test::test");
ARC_CHECK(testVal == 5);
testVal = *(int32_t *)ARC_Chemical_GetWithCStr(chemical, "test::test1");
ARC_CHECK(testVal == -7);
ARC_Chemical_UnloadFromFile(chemical, tempString);
void *nullVal = ARC_Chemical_GetWithCStr(chemical, "test::test");
ARC_CHECK(nullVal == NULL);
//cleanup
ARC_String_Destroy(tempString);
ARC_Chemical_Destroy(chemical);
}

View file