diff options
author | kartofen <mladenovnasko0@gmail.com> | 2023-08-14 21:20:39 +0300 |
---|---|---|
committer | kartofen <mladenovnasko0@gmail.com> | 2023-08-14 21:20:39 +0300 |
commit | a7bb8ace49f5725e0f92336ab5af28b4c8900aff (patch) | |
tree | 5d00d7a5d159e9702b46c23542fffc09e591c271 /src/value.c | |
parent | f83187a830deff27ce0cdd4c175ffe2785461685 (diff) |
parser done
Diffstat (limited to 'src/value.c')
-rw-r--r-- | src/value.c | 244 |
1 files changed, 244 insertions, 0 deletions
diff --git a/src/value.c b/src/value.c new file mode 100644 index 0000000..289aa0f --- /dev/null +++ b/src/value.c @@ -0,0 +1,244 @@ +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +#include "common.h" +#include "value.h" + +// TODO: add the other types + +// save data as a symbol +// return 0 on sucess, < 0 on error +static int symbol_save(char **symbol, char *data); +// same as value_string +static char *symbol_string(char *symbol, char *buf, size_t buf_sz); + +// try to save data as a literal +// returns 0 on sucess, > 0 on fail (data isnt a possible literal), +// and < 0 on error +static int literal_save(struct literal *literal, char *data); +static void literal_free(struct literal *literal); +// same as value_string +static char *literal_string(struct literal *literal, char *buf, size_t buf_sz); + +// for a function that saves string data as a value +#define S_FN(fn, arg) fn(arg, (char *)data) +// for a function that saves a value as a string in buf[buf_sz] +#define P_FN(fn, arg) fn(arg, buf, buf_sz) + +#define MANAGE_VALUE_TBL(X, value) \ +/* X(type, save function, \ + how to free, how to save to string) */ \ + X(VALUE_SYMBOL, S_FN(symbol_save, &value->symbol), \ + free(value->symbol), P_FN(symbol_string, value->symbol)) \ + X(VALUE_LITERAL, S_FN(literal_save, &value->literal), \ + literal_free(&value->literal), P_FN(literal_string, &value->literal)) \ +// X(VALUE_PAIR, ...) +// X(VALUE_LIST, ...) +// X(VALUE_PROC, ...) + +// ------ Exported Functions Implementations ------- // +// ------------------------------------------------- // + +#define CASE_SAVE(type, save_func, free_func, string_func) \ + case type: *ret = save_func; break; + +value_t value_create(enum value_type type, void *data, int *ret) +{ + value_t value = xmalloc(sizeof(struct value)); + + value->type = VALUE_TYPES; + value->references = 1; + + switch(type) { + MANAGE_VALUE_TBL(CASE_SAVE, value); + default: + err("value_create: Unknown value type given"); + *ret = -1; + break; + } + + if(!*ret) { + value->type = type; + return value; + } + + value_destroy(value); + return NULL; +} + +value_t value_copy(value_t value) +{ + value->references++; + return value; +} + +#define CASE_FREE(type, save_func, free_func, string_func) \ + case type: free_func; break; + +void value_destroy(value_t value) +{ + if(!value) return; + if(--value->references > 0) { + return; + } + + + switch(value->type) { + MANAGE_VALUE_TBL(CASE_FREE, value); + default: break; + } + + free(value); +} + +#define CASE_STRING(type, save_func, free_func, string_func) \ + case type: return string_func; + +char *value_string(value_t value, char *buf, size_t buf_sz) +{ + switch(value->type) { + MANAGE_VALUE_TBL(CASE_STRING, value); + default: return NULL; + } +} + +// ---------------- Symbol Functions --------------- // + +static int symbol_save(char **symbol, char *data) +{ + size_t len = strlen(data) + 1; + + *symbol = xmalloc(len); + + memcpy(*symbol, data, len); + return 0; +} + +static char *symbol_string(char *symbol, char *buf, size_t buf_sz) +{ + size_t len = strlen(symbol) + 1; + if(len> buf_sz) { + return NULL; + } + + memcpy(buf, symbol, len); + return buf; +} + +// --------------- Literal Functions --------------- // + +// write a value in a printf format to buf[buf_sz] +#define EX(...) (((size_t)snprintf(buf, buf_sz, __VA_ARGS__) > buf_sz) ? NULL : buf) + +#define MANAGE_LITERAL_TBL(X, literal) \ +/* X(type, how to free how to print) */ \ + X(LITERAL_STRING, free(literal->string), EX("%s", literal->string)) \ + X(LITERAL_NUM_INT, ;, EX("%ld", literal->num_int)) \ + X(LITERAL_NUM_FLOAT, ;, EX("%f", literal->num_float)) + +// try to convert the data to a literal +// returns 0 on success, > 0 on fail (data isnt a literal), +// and < 0 on error +static int literal_try_string(struct literal *literal, char *data); +static int literal_try_int (struct literal *literal, char *data); +static int literal_try_float (struct literal *literal, char *data); + +// list of the try_type functions (order matters) +typedef int (*try_func)(struct literal *, char *); +try_func literal_try_funcs[] = { + literal_try_string, + literal_try_int, + literal_try_float, +}; + +static int literal_save(struct literal *literal, char *data) +{ + int ret = 0; + + for(size_t i = 0; i < sizeof(literal_try_funcs)/sizeof(try_func); i++) { + // <= 0 means that it either failed fatally, or succeeded + if((ret = literal_try_funcs[i](literal, data)) <= 0) break; + } + + return ret; +} + +#define CASE_LITERAL_FREE(type, free_func, string_func) \ + case type: free_func; break; + +static void literal_free(struct literal *literal) +{ + switch(literal->type) { + MANAGE_LITERAL_TBL(CASE_LITERAL_FREE, literal); + default: break; + } +} + +#define CASE_LITERAL_STRING(type, free_func, string_func) \ + case type: return string_func; + +static char *literal_string(struct literal *literal, char *buf, size_t buf_sz) +{ + switch(literal->type) { + MANAGE_LITERAL_TBL(CASE_LITERAL_STRING, literal); + default: return NULL; break; + } +} + +// Literal try_type functions + +static int literal_try_string(struct literal *literal, char *data) +{ + if(data[0] != '"') return 1; + + literal->type = LITERAL_STRING; + + size_t len = strlen(data); // no +1 needed since first character is discarded + literal->string = xmalloc(len); + + memcpy(literal->string, data + 1, len); + return 0; +} + +static int literal_try_int(struct literal *literal, char *data) +{ + errno = ERANGE + 1; // set errno to not ERANGE + + char *endptr; + long num = strtol(data, &endptr, 10); + + if(*endptr != '\0') { // the whole string isn't a number + return 1; + } + + if(errno == ERANGE) { + warn("Given integer literal %s is outside the possible range", data); + } + + literal->type = LITERAL_NUM_INT; + literal->num_int = num; + + return 0; +} + +static int literal_try_float (struct literal *literal, char *data) +{ + errno = ERANGE + 1; // set errno to not ERANGE + + char *endptr; + float num = strtof(data, &endptr); + + if(*endptr != '\0') { // the whole string isn't a number + return 1; + } + + if(errno == ERANGE) { + warn("Given float literal %s is outside the possible range", data); + } + + literal->type = LITERAL_NUM_FLOAT; + literal->num_float = num; + + return 0; +} |