basic chemical (config) working, still needs more testing

This commit is contained in:
herbglitch 2025-03-09 06:03:38 -06:00
parent 0e83921632
commit 3fbccd9752
4 changed files with 420 additions and 96 deletions

View file

@ -23,73 +23,6 @@ typedef struct ARC_ChemicalTypeData {
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;
static const uint32_t ARC_CHEMICAL_SPACE = 0x03;
static const uint32_t ARC_CHEMICAL_BANG = 0x04;
static const uint32_t ARC_CHEMICAL_QUOTE = 0x05;
static const uint32_t ARC_CHEMICAL_HASH = 0x06;
static const uint32_t ARC_CHEMICAL_DOLLAR = 0x07;
static const uint32_t ARC_CHEMICAL_PERCENT = 0x08;
static const uint32_t ARC_CHEMICAL_AMPERSAND = 0x09;
static const uint32_t ARC_CHEMICAL_SINGLE_QUOTE = 0x0A;
static const uint32_t ARC_CHEMICAL_OPEN_PAREN = 0x0B;
static const uint32_t ARC_CHEMICAL_CLOSE_PAREN = 0x0C;
static const uint32_t ARC_CHEMICAL_ASTERISK = 0x0D;
static const uint32_t ARC_CHEMICAL_PLUS = 0x0E;
static const uint32_t ARC_CHEMICAL_COMMA = 0x0F;
static const uint32_t ARC_CHEMICAL_MINUS = 0x10;
static const uint32_t ARC_CHEMICAL_PERIOD = 0x11;
static const uint32_t ARC_CHEMICAL_SLASH = 0x12;
static const uint32_t ARC_CHEMICAL_NUMBER = 0x13;
static const uint32_t ARC_CHEMICAL_COLON = 0x14;
static const uint32_t ARC_CHEMICAL_SEMICOLON = 0x15;
static const uint32_t ARC_CHEMICAL_LESS_THAN = 0x16;
static const uint32_t ARC_CHEMICAL_GREATER_THAN = 0x17;
static const uint32_t ARC_CHEMICAL_EQUAL = 0x18;
static const uint32_t ARC_CHEMICAL_QUESTION_MARK = 0x19;
static const uint32_t ARC_CHEMICAL_AT = 0x1A;
static const uint32_t ARC_CHEMICAL_ALPHA_UPPER_CHAR = 0x1B;
static const uint32_t ARC_CHEMICAL_OPEN_BRACKET = 0x1C;
static const uint32_t ARC_CHEMICAL_BACKSLASH = 0x1D;
static const uint32_t ARC_CHEMICAL_CLOSE_BRACKET = 0x1E;
static const uint32_t ARC_CHEMICAL_CARET = 0x1F;
static const uint32_t ARC_CHEMICAL_UNDERSCORE = 0x20;
static const uint32_t ARC_CHEMICAL_GRAVE = 0x21;
static const uint32_t ARC_CHEMICAL_ALPHA_LOWER_CHAR = 0x22;
static const uint32_t ARC_CHEMICAL_OPEN_CURLY_BRACE = 0x23;
static const uint32_t ARC_CHEMICAL_VERTICAL_LINE = 0x24;
static const uint32_t ARC_CHEMICAL_CLOSE_CURLY_BRACE = 0x25;
static const uint32_t ARC_CHEMICAL_TILDE = 0x26;
static const uint32_t ARC_CHEMICAL_LANGUAGE = 0x27;
static const uint32_t ARC_CHEMICAL_GROUP = 0x28;
static const uint32_t ARC_CHEMICAL_GROUP_NAME = 0x29;
static const uint32_t ARC_CHEMICAL_GROUP_ARGS = 0x2A;
static const uint32_t ARC_CHEMICAL_VARIABLE_LINES = 0x2B;
static const uint32_t ARC_CHEMICAL_VARIABLE_LINE = 0x2C;
static const uint32_t ARC_CHEMICAL_ALLOW_SPACE = 0x2D;
static const uint32_t ARC_CHEMICAL_TYPE = 0x2E;
static const uint32_t ARC_CHEMICAL_VALUE = 0x2F;
static const uint32_t ARC_CHEMICAL_NESTED_VALUE = 0x30;
static const uint32_t ARC_CHEMICAL_VALUE_ARGS = 0x31;
static const uint32_t ARC_CHEMICAL_VARIABLE = 0x32;
static const uint32_t ARC_CHEMICAL_VARIABLE_NAME = 0x33;
static const uint32_t ARC_CHEMICAL_VARIABLE_CHAR = 0x34;
static const uint32_t ARC_CHEMICAL_STRING = 0x35;
static const uint32_t ARC_CHEMICAL_STRING_CHARS = 0x36;
static const uint32_t ARC_CHEMICAL_STRING_CHAR = 0x37;
static const uint32_t ARC_CHEMICAL_ESCAPE_CHAR = 0x38;
static const uint32_t ARC_CHEMICAL_WHITESPACE = 0x39;
static const uint32_t ARC_CHEMICAL_NUMBER_TAG = 0x3A;
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'));
@ -325,23 +258,6 @@ uint32_t ARC_Chemical_GetStringIdFn(ARC_String *string){
return ~(uint32_t)0;
}
void ARC_ChemicalData_CreateFn(void **data, ARC_ParserTagToken *parsedData, void *userData){
printf("HERE??\n");
*data = NULL;
if(parsedData == NULL || userData == NULL){
printf("Parsed Data was NULL\n");
//TODO: error here?
*data = NULL;
return;
}
}
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;
@ -368,6 +284,234 @@ void ARC_Chemical_GroupDataHashtableDestroyKeyValueFn(void *key, void *value){
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 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);
//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));
@ -438,6 +582,7 @@ void ARC_Chemical_Create(ARC_Chemical **chemical){
}
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);
@ -457,8 +602,10 @@ void ARC_Chemical_RegisterTypeWithCStr(ARC_Chemical *chemical, const char *typeN
}
//copy the string into a cstring for long term storage
char *typeNameCopy = malloc(sizeof(char) * strlen(typeNameCStr));
strcpy(typeNameCopy, typeNameCStr);
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));
@ -488,14 +635,59 @@ void ARC_Chemical_SetGroupWithCStr(ARC_Chemical *chemical, const char *groupName
}
void *ARC_Chemical_Get(ARC_Chemical *chemical, ARC_String *element){
return ARC_Chemical_GetWithCStr(chemical, element->data);
//check if the group separator exists
uint64_t startSeparatorIndex = ARC_String_FindCStringWithStrlen(element, 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 *)element->data);
if(typeData == NULL){
return NULL;
}
return typeData->data;
}
//get the group
startSeparatorIndex--;
ARC_String *groupString;
ARC_String_CopySubstring(&groupString, element, 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 *elementString;
startSeparatorIndex += strlen(ARC_CHEMICAL_GROUP_SEPARATOR);
ARC_String_CopySubstring(&elementString, element, startSeparatorIndex, element->length - startSeparatorIndex);
//this will either return the value or NULL
ARC_ChemicalTypeData *typeData = (ARC_ChemicalTypeData *)ARC_Hashtable_Get(chemical->currentGroup, (void *)elementString->data);
ARC_String_Destroy(elementString);
if(typeData == NULL){
return NULL;
}
return typeData->data;
}
void *ARC_Chemical_GetWithCStr(ARC_Chemical *chemical, const char *element){
//TODO: set the parent group
//create and copy into ARC_String
ARC_String *elementString;
ARC_String_CreateWithStrlen(&elementString, (char *)element);
//this will either return the value or NULL
return ARC_Hashtable_Get(chemical->currentGroup, (void *)element);
//get the return value
void *returnValue = ARC_Chemical_Get(chemical, elementString);
//cleanup
ARC_String_Destroy(elementString);
return returnValue;
}
void ARC_Chemical_LoadFromString(ARC_Chemical *chemical, ARC_String **string){

View file

@ -88,10 +88,6 @@ void ARC_String_CopySubstring(ARC_String **substring, ARC_String *original, uint
}
char data[length];
for(uint32_t i = 0; i < length; i++){
data[i] = 0;
}
strncpy(data, original->data + start, length);
ARC_String_Create(substring, data, length);