replaced TomlTable with HashMap
This commit is contained in:
parent
a33505ffe4
commit
c49a8cb1e5
@ -11,9 +11,10 @@ extern "C" {
|
||||
#include <time.h>
|
||||
#include "tlibc/std.h"
|
||||
#include "tlibc/string/str.h"
|
||||
#include "tlibc/string/StringBuilder.h"
|
||||
#include "tlibc/collections/HashMap.h"
|
||||
|
||||
typedef struct tm TomlDateTime;
|
||||
typedef HashMap(TomlValue) TomlTable;
|
||||
|
||||
typedef enum {
|
||||
TOML_OK,
|
||||
@ -29,28 +30,17 @@ typedef struct {
|
||||
NULLABLE(char*) message;
|
||||
} TomlErr;
|
||||
|
||||
typedef struct _TomlValue TomlValue;
|
||||
typedef struct TomlValue TomlValue;
|
||||
|
||||
typedef struct {
|
||||
TomlValue** elements;
|
||||
TomlValue* elements;
|
||||
u64 len;
|
||||
u64 _capacity;
|
||||
} TomlArray;
|
||||
|
||||
typedef struct _TomlKeyValue TomlKeyValue;
|
||||
|
||||
typedef struct {
|
||||
u64 _capacity;
|
||||
u64 len;
|
||||
TomlKeyValue* _keyvals;
|
||||
} TomlTable;
|
||||
|
||||
typedef struct {
|
||||
TomlTable* _table;
|
||||
TomlKeyValue* _keyval;
|
||||
} TomlTableIter;
|
||||
|
||||
typedef enum {
|
||||
TOML_INVALID_TYPE,
|
||||
TOML_TABLE,
|
||||
TOML_ARRAY,
|
||||
TOML_STRING,
|
||||
@ -60,7 +50,7 @@ typedef enum {
|
||||
TOML_BOOLEAN,
|
||||
} TomlType;
|
||||
|
||||
struct _TomlValue {
|
||||
struct TomlValue {
|
||||
TomlType type;
|
||||
union {
|
||||
TomlTable* table;
|
||||
@ -68,16 +58,11 @@ struct _TomlValue {
|
||||
str s;
|
||||
i64 i;
|
||||
f64 f;
|
||||
TomlDateTime dt;
|
||||
TomlDateTime* dt;
|
||||
bool b;
|
||||
} value;
|
||||
};
|
||||
|
||||
struct _TomlKeyValue {
|
||||
str key;
|
||||
TomlValue* value;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
void* (*malloc)(void* context, u64 size);
|
||||
void* (*realloc)(void* context, void* p, u64 size);
|
||||
@ -97,35 +82,30 @@ void toml_err_clear(void);
|
||||
TomlTable* toml_table_new(void);
|
||||
void toml_table_free(TomlTable* self);
|
||||
|
||||
void toml_table_set(TomlTable* self, str key, TomlValue* value);
|
||||
void toml_table_set(TomlTable* self, str key, TomlValue value);
|
||||
TomlValue* toml_table_get(const TomlTable* self, str key);
|
||||
TomlTable* toml_table_get_table(const TomlTable* self, str key);
|
||||
TomlArray* toml_table_get_array(const TomlTable* self, str key);
|
||||
str toml_table_get_str(const TomlTable* self, str key);
|
||||
i64 toml_table_get_integer(const TomlTable* self, str key);
|
||||
f64 toml_table_get_float(const TomlTable* self, str key);
|
||||
const TomlDateTime* toml_table_get_datetime(const TomlTable* self, str key);
|
||||
TomlDateTime* toml_table_get_datetime(const TomlTable* self, str key);
|
||||
bool toml_table_get_bool(const TomlTable* self, str key);
|
||||
|
||||
TomlTableIter toml_table_iter_new(TomlTable* table);
|
||||
TomlKeyValue* toml_table_iter_get(TomlTableIter* self);
|
||||
i32 toml_table_iter_has_next(TomlTableIter* self);
|
||||
void toml_table_iter_next(TomlTableIter* self);
|
||||
|
||||
TomlArray* toml_array_new(void);
|
||||
void toml_array_free(TomlArray* self);
|
||||
void toml_array_append(TomlArray* self, TomlValue* value);
|
||||
void toml_array_append(TomlArray* self, TomlValue value);
|
||||
|
||||
TomlValue* toml_value_new(TomlType type);
|
||||
TomlValue* toml_value_new_string(TomlType type);
|
||||
TomlValue* toml_value_new_table(void);
|
||||
TomlValue* toml_value_new_array(void);
|
||||
TomlValue* toml_value_new_integer(i64 integer);
|
||||
TomlValue* toml_value_new_float(f64 flt);
|
||||
TomlValue* toml_value_new_datetime(void);
|
||||
TomlValue* toml_value_new_bool(bool b);
|
||||
TomlValue* toml_value_from_str(str s);
|
||||
void toml_value_free(TomlValue* self);
|
||||
TomlValue TomlValue_new(TomlType type);
|
||||
TomlValue TomlValue_new_string(TomlType type);
|
||||
TomlValue TomlValue_new_table(void);
|
||||
TomlValue TomlValue_new_array(void);
|
||||
TomlValue TomlValue_new_integer(i64 integer);
|
||||
TomlValue TomlValue_new_float(f64 flt);
|
||||
TomlValue TomlValue_new_datetime(void);
|
||||
TomlValue TomlValue_new_bool(bool b);
|
||||
TomlValue TomlValue_from_str(str s);
|
||||
void TomlValue_destroy(TomlValue* self);
|
||||
|
||||
TomlTable* toml_load_str(str s);
|
||||
TomlTable* toml_load_file(FILE* file);
|
||||
|
||||
458
src/toml.c
458
src/toml.c
@ -7,6 +7,8 @@
|
||||
#include "tlibtoml/toml.h"
|
||||
#include "tlibc/errors.h"
|
||||
#include "tlibc/string/StringBuilder.h"
|
||||
#include "tlibc/collections/HashMap.h"
|
||||
#include "tlibc/collections/List.h"
|
||||
|
||||
static ATTRIBUTE_THREAD_LOCAL TomlErr g_err = { TOML_OK, NULL };
|
||||
|
||||
@ -85,70 +87,38 @@ static inline void toml_err_set(TomlErrCode code, cstr format, ...)
|
||||
g_err.code = code;
|
||||
g_err.message = vsprintf_malloc(format, args);
|
||||
va_end(args);
|
||||
|
||||
printfe("ERROR: %s\n", toml_err()->message);
|
||||
fflush(stderr);
|
||||
}
|
||||
|
||||
|
||||
|
||||
TomlTable* toml_table_new(void)
|
||||
{
|
||||
TomlTable* self = toml_malloc(sizeof(TomlTable));
|
||||
self->_capacity = 0;
|
||||
self->_keyvals = NULL;
|
||||
self->len = 0;
|
||||
return self;
|
||||
TomlTable* table = toml_malloc(sizeof(TomlTable));
|
||||
HashMap_construct(table, TomlValue, (FreeFunction)TomlValue_destroy);
|
||||
return table;
|
||||
}
|
||||
|
||||
void toml_table_free(TomlTable* self)
|
||||
{
|
||||
if (self != NULL) {
|
||||
for (u64 i = 0; i < self->len; i++) {
|
||||
free(self->_keyvals[i].key.data);
|
||||
toml_value_free(self->_keyvals[i].value);
|
||||
}
|
||||
free(self->_keyvals);
|
||||
if(!self)
|
||||
return;
|
||||
HashMap_destroy(self);
|
||||
free(self);
|
||||
}
|
||||
}
|
||||
|
||||
void toml_table_expand_if_necessary(TomlTable* self)
|
||||
{
|
||||
if (self->len + 1 > self->_capacity) {
|
||||
u64 new_capacity = self->_capacity > 0 ? self->_capacity * 2 : 8;
|
||||
void* p = toml_realloc(self->_keyvals, sizeof(TomlKeyValue) * new_capacity);
|
||||
self->_keyvals = p;
|
||||
self->_capacity = new_capacity;
|
||||
}
|
||||
}
|
||||
|
||||
void toml_table_set(TomlTable* self, str key, TomlValue* value)
|
||||
void toml_table_set(TomlTable* self, str key, TomlValue value)
|
||||
{
|
||||
assert(key.data != NULL);
|
||||
TomlValue** slot = NULL;
|
||||
for (u64 i = 0; i < self->len; i++) {
|
||||
if (str_equals(self->_keyvals[i].key, key)) {
|
||||
slot = &self->_keyvals[i].value;
|
||||
}
|
||||
}
|
||||
|
||||
if (slot == NULL) {
|
||||
toml_table_expand_if_necessary(self);
|
||||
self->_keyvals[self->len].key = str_copy(key);
|
||||
self->_keyvals[self->len].value = value;
|
||||
self->len++;
|
||||
} else {
|
||||
*slot = value;
|
||||
}
|
||||
HashMap_pushOrUpdate(self, key, &value);
|
||||
}
|
||||
|
||||
TomlValue* toml_table_get(const TomlTable* self, const str key)
|
||||
{
|
||||
assert(key.data != NULL);
|
||||
TomlValue* value = NULL;
|
||||
for (u64 i = 0; i < self->len; i++) {
|
||||
if (str_equals(self->_keyvals[i].key, key)) {
|
||||
value = self->_keyvals[i].value;
|
||||
}
|
||||
}
|
||||
TomlValue* value = HashMap_tryGetPtr(self, key);
|
||||
return value;
|
||||
}
|
||||
|
||||
@ -192,12 +162,12 @@ f64 toml_table_get_float(const TomlTable* self, str key)
|
||||
return v->value.f;
|
||||
}
|
||||
|
||||
const TomlDateTime* toml_table_get_datetime(const TomlTable* self, str key)
|
||||
TomlDateTime* toml_table_get_datetime(const TomlTable* self, str key)
|
||||
{
|
||||
TomlValue* v = toml_table_get(self, key);
|
||||
assert(v != NULL);
|
||||
assert(v->type == TOML_DATETIME);
|
||||
return &v->value.dt;
|
||||
return v->value.dt;
|
||||
}
|
||||
|
||||
bool toml_table_get_bool(const TomlTable* self, str key)
|
||||
@ -208,47 +178,20 @@ bool toml_table_get_bool(const TomlTable* self, str key)
|
||||
return v->value.b;
|
||||
}
|
||||
|
||||
TomlTableIter toml_table_iter_new(TomlTable* table)
|
||||
{
|
||||
TomlTableIter self = { table, table->_keyvals };
|
||||
return self;
|
||||
}
|
||||
|
||||
TomlKeyValue* toml_table_iter_get(TomlTableIter* self)
|
||||
{
|
||||
return self->_keyval;
|
||||
}
|
||||
|
||||
i32 toml_table_iter_has_next(TomlTableIter* self)
|
||||
{
|
||||
return self->_keyval != NULL;
|
||||
}
|
||||
|
||||
void toml_table_iter_next(TomlTableIter* self)
|
||||
{
|
||||
if (self->_keyval < self->_table->_keyvals + self->_table->len) {
|
||||
self->_keyval++;
|
||||
}
|
||||
|
||||
if (self->_keyval >= self->_table->_keyvals + self->_table->len) {
|
||||
self->_keyval = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
TomlArray *toml_array_new(void)
|
||||
{
|
||||
TomlArray* self = toml_malloc(sizeof(TomlArray));
|
||||
self->elements = NULL;
|
||||
self->len = 0;
|
||||
self->_capacity = 0;
|
||||
return self;
|
||||
TomlArray* array = toml_malloc(sizeof(TomlArray));
|
||||
array->elements = NULL;
|
||||
array->len = 0;
|
||||
array->_capacity = 0;
|
||||
return array;
|
||||
}
|
||||
|
||||
void toml_array_free(TomlArray* self)
|
||||
{
|
||||
if (self != NULL) {
|
||||
for (u64 i = 0; i < self->len; i++) {
|
||||
toml_value_free(self->elements[i]);
|
||||
TomlValue_destroy(&self->elements[i]);
|
||||
}
|
||||
free(self->elements);
|
||||
free(self);
|
||||
@ -259,107 +202,111 @@ void toml_array_expand_if_necessary(TomlArray* self)
|
||||
{
|
||||
if (self->len + 1 > self->_capacity) {
|
||||
u64 new_capacity = self->_capacity > 0 ? self->_capacity * 2 : 8;
|
||||
void* p = toml_realloc(self->elements, sizeof(TomlValue*) * new_capacity);
|
||||
void* p = toml_realloc(self->elements, sizeof(TomlValue) * new_capacity);
|
||||
self->elements = p;
|
||||
self->_capacity = new_capacity;
|
||||
}
|
||||
}
|
||||
|
||||
void toml_array_append(TomlArray* self, TomlValue* value)
|
||||
void toml_array_append(TomlArray* self, TomlValue value)
|
||||
{
|
||||
toml_array_expand_if_necessary(self);
|
||||
self->elements[self->len++] = value;
|
||||
}
|
||||
|
||||
TomlValue* toml_value_new(TomlType type)
|
||||
TomlValue TomlValue_new(TomlType type)
|
||||
{
|
||||
TomlValue* self = toml_malloc(sizeof(TomlValue));
|
||||
self->type = type;
|
||||
TomlValue value = {0};
|
||||
value.type = type;
|
||||
switch (type) {
|
||||
default:
|
||||
assert(false && "invalid type");
|
||||
break;
|
||||
case TOML_TABLE:
|
||||
self->value.table = NULL;
|
||||
value.value.table = NULL;
|
||||
break;
|
||||
case TOML_ARRAY:
|
||||
self->value.array = NULL;
|
||||
value.value.array = NULL;
|
||||
break;
|
||||
case TOML_STRING:
|
||||
self->value.s = str_null;
|
||||
value.value.s = str_null;
|
||||
break;
|
||||
case TOML_INTEGER:
|
||||
self->value.i = 0;
|
||||
value.value.i = 0;
|
||||
break;
|
||||
case TOML_FLOAT:
|
||||
self->value.f = 0.0;
|
||||
value.value.f = 0.0;
|
||||
break;
|
||||
case TOML_BOOLEAN:
|
||||
self->value.b = false;
|
||||
value.value.b = false;
|
||||
break;
|
||||
case TOML_DATETIME:
|
||||
memset(&self->value.dt, 0, sizeof(TomlDateTime));
|
||||
value.value.dt = (TomlDateTime*)toml_malloc(sizeof(TomlDateTime));
|
||||
memset(value.value.dt, 0, sizeof(TomlDateTime));
|
||||
break;
|
||||
}
|
||||
return self;
|
||||
return value;
|
||||
}
|
||||
|
||||
TomlValue* toml_value_from_str(str s)
|
||||
TomlValue TomlValue_from_str(str s)
|
||||
{
|
||||
TomlValue* self = toml_malloc(sizeof(TomlValue));
|
||||
self->value.s = str_copy(s);
|
||||
self->type = TOML_STRING;
|
||||
return self;
|
||||
TomlValue value = {0};
|
||||
value.value.s = str_copy(s);
|
||||
value.type = TOML_STRING;
|
||||
return value;
|
||||
}
|
||||
|
||||
TomlValue* toml_value_new_table(void)
|
||||
TomlValue TomlValue_new_table(void)
|
||||
{
|
||||
TomlValue* self = toml_malloc(sizeof(TomlValue));
|
||||
self->value.table = toml_table_new();
|
||||
self->type = TOML_TABLE;
|
||||
return self;
|
||||
TomlValue value = {0};
|
||||
value.value.table = toml_table_new();
|
||||
value.type = TOML_TABLE;
|
||||
return value;
|
||||
}
|
||||
|
||||
TomlValue* toml_value_new_array(void)
|
||||
TomlValue TomlValue_new_array(void)
|
||||
{
|
||||
TomlValue* self = toml_malloc(sizeof(TomlValue));
|
||||
self->value.array = toml_array_new();
|
||||
self->type = TOML_ARRAY;
|
||||
return self;
|
||||
TomlValue value = {0};
|
||||
value.value.array = toml_array_new();
|
||||
value.type = TOML_ARRAY;
|
||||
return value;
|
||||
}
|
||||
|
||||
TomlValue* toml_value_new_integer(i64 integer)
|
||||
TomlValue TomlValue_new_integer(i64 integer)
|
||||
{
|
||||
TomlValue* self = toml_malloc(sizeof(TomlValue));
|
||||
self->value.i = integer;
|
||||
self->type = TOML_INTEGER;
|
||||
return self;
|
||||
TomlValue value = {0};
|
||||
value.value.i = integer;
|
||||
value.type = TOML_INTEGER;
|
||||
return value;
|
||||
}
|
||||
|
||||
TomlValue* toml_value_new_float(f64 float_)
|
||||
TomlValue TomlValue_new_float(f64 float_)
|
||||
{
|
||||
TomlValue* self = toml_malloc(sizeof(TomlValue));
|
||||
self->value.f = float_;
|
||||
self->type = TOML_FLOAT;
|
||||
return self;
|
||||
TomlValue value = {0};
|
||||
value.value.f = float_;
|
||||
value.type = TOML_FLOAT;
|
||||
return value;
|
||||
}
|
||||
|
||||
TomlValue* toml_value_new_datetime(void)
|
||||
TomlValue TomlValue_new_datetime(void)
|
||||
{
|
||||
return toml_value_new(TOML_DATETIME);
|
||||
return TomlValue_new(TOML_BOOLEAN);
|
||||
}
|
||||
|
||||
TomlValue* toml_value_new_bool(bool b)
|
||||
TomlValue TomlValue_new_bool(bool b)
|
||||
{
|
||||
TomlValue* self = toml_malloc(sizeof(TomlValue));
|
||||
self->value.b = b;
|
||||
self->type = TOML_BOOLEAN;
|
||||
return self;
|
||||
TomlValue value = {0};
|
||||
value.value.b = b;
|
||||
value.type = TOML_BOOLEAN;
|
||||
return value;
|
||||
}
|
||||
|
||||
void toml_value_free(TomlValue* self)
|
||||
void TomlValue_destroy(TomlValue* self)
|
||||
{
|
||||
if (self != NULL) {
|
||||
switch (self->type) {
|
||||
case TOML_STRING:
|
||||
str_free(self->value.s);
|
||||
str_destroy(self->value.s);
|
||||
break;
|
||||
case TOML_TABLE:
|
||||
toml_table_free(self->value.table);
|
||||
@ -368,12 +315,11 @@ void toml_value_free(TomlValue* self)
|
||||
toml_array_free(self->value.array);
|
||||
break;
|
||||
case TOML_DATETIME:
|
||||
memset(&self->value.dt, 0, sizeof(TomlDateTime));
|
||||
free(self->value.dt);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
free(self);
|
||||
}
|
||||
}
|
||||
|
||||
@ -388,15 +334,15 @@ typedef struct _TomlParser {
|
||||
|
||||
TomlParser* toml_parser_new(str s, cstr filename)
|
||||
{
|
||||
TomlParser* self = toml_malloc(sizeof(TomlParser));
|
||||
self->begin = s.data;
|
||||
self->end = s.data + s.size;
|
||||
self->ptr = s.data;
|
||||
self->lineno = 1;
|
||||
self->colno = 1;
|
||||
TomlParser* parser = toml_malloc(sizeof(TomlParser));
|
||||
parser->begin = s.data;
|
||||
parser->end = s.data + s.size;
|
||||
parser->ptr = s.data;
|
||||
parser->lineno = 1;
|
||||
parser->colno = 1;
|
||||
// TODO: remove copy filename?
|
||||
self->filename = str_copy(str_from_cstr(filename)).data;
|
||||
return self;
|
||||
parser->filename = str_copy(str_from_cstr(filename)).data;
|
||||
return parser;
|
||||
}
|
||||
|
||||
void toml_parser_free(TomlParser* self)
|
||||
@ -540,7 +486,7 @@ i32 toml_encode_unicode_scalar(StringBuilder* sb_ptr, TomlParser* parser, i32 n)
|
||||
|
||||
str toml_parse_basic_string(TomlParser* self)
|
||||
{
|
||||
StringBuilder sb = StringBuilder_alloc(64);
|
||||
StringBuilder sb = StringBuilder_alloc(0);
|
||||
|
||||
while (self->ptr < self->end &&* self->ptr != '\"' &&* self->ptr != '\n') {
|
||||
char ch1 = *self->ptr;
|
||||
@ -609,7 +555,7 @@ str toml_parse_basic_string(TomlParser* self)
|
||||
|
||||
str toml_parse_literal_string(TomlParser* self)
|
||||
{
|
||||
StringBuilder sb = StringBuilder_alloc(64);
|
||||
StringBuilder sb = StringBuilder_alloc(0);
|
||||
|
||||
while (self->ptr < self->end &&* self->ptr != '\'' &&* self->ptr != '\n') {
|
||||
StringBuilder_append_char(&sb,* self->ptr);
|
||||
@ -628,31 +574,31 @@ str toml_parse_literal_string(TomlParser* self)
|
||||
return StringBuilder_getStr(&sb);
|
||||
}
|
||||
|
||||
TomlValue* toml_parse_basic_string_value(TomlParser* self)
|
||||
TomlValue toml_parse_basic_string_value(TomlParser* self)
|
||||
{
|
||||
str s = toml_parse_basic_string(self);
|
||||
if (s.data == NULL)
|
||||
return NULL;
|
||||
//TODO: error handling
|
||||
assert(s.data != NULL);
|
||||
|
||||
TomlValue* value = toml_value_new(TOML_STRING);
|
||||
value->value.s = s;
|
||||
TomlValue value = TomlValue_new(TOML_STRING);
|
||||
value.value.s = s;
|
||||
return value;
|
||||
}
|
||||
|
||||
TomlValue* toml_parse_literal_string_value(TomlParser* self)
|
||||
TomlValue toml_parse_literal_string_value(TomlParser* self)
|
||||
{
|
||||
str s = toml_parse_literal_string(self);
|
||||
if (s.data == NULL)
|
||||
return NULL;
|
||||
//TODO: error handling
|
||||
assert(s.data != NULL);
|
||||
|
||||
TomlValue* value = toml_value_new(TOML_STRING);
|
||||
value->value.s = s;
|
||||
TomlValue value = TomlValue_new(TOML_STRING);
|
||||
value.value.s = s;
|
||||
return value;
|
||||
}
|
||||
|
||||
TomlValue* toml_parse_multi_line_basic_string(TomlParser* self)
|
||||
TomlValue toml_parse_multi_line_basic_string(TomlParser* self)
|
||||
{
|
||||
StringBuilder sb = StringBuilder_alloc(64);
|
||||
StringBuilder sb = StringBuilder_alloc(0);
|
||||
|
||||
if (*self->ptr == '\n') {
|
||||
toml_move_next(self);
|
||||
@ -693,13 +639,15 @@ TomlValue* toml_parse_multi_line_basic_string(TomlParser* self)
|
||||
toml_move_next(self);
|
||||
if (toml_encode_unicode_scalar(&sb, self, 4) != 0) {
|
||||
StringBuilder_destroy(&sb);
|
||||
return NULL;
|
||||
//TODO: error handling
|
||||
assert(false && "TODO error handling");
|
||||
}
|
||||
} else if (ch2 == 'U') {
|
||||
toml_move_next(self);
|
||||
if (toml_encode_unicode_scalar(&sb, self, 8) != 0) {
|
||||
StringBuilder_destroy(&sb);
|
||||
return NULL;
|
||||
//TODO: error handling
|
||||
assert(false && "TODO error handling");
|
||||
}
|
||||
} else if (ch2 == '\n') {
|
||||
do {
|
||||
@ -709,7 +657,8 @@ TomlValue* toml_parse_multi_line_basic_string(TomlParser* self)
|
||||
toml_err_set(TOML_ERR_SYNTAX, "%s:%d:%d: invalid escape character",
|
||||
self->filename, self->lineno, self->colno);
|
||||
StringBuilder_destroy(&sb);
|
||||
return NULL;
|
||||
//TODO: error handling
|
||||
assert(false && "TODO error handling");
|
||||
}
|
||||
} else {
|
||||
StringBuilder_append_char(&sb, ch1);
|
||||
@ -721,19 +670,20 @@ TomlValue* toml_parse_multi_line_basic_string(TomlParser* self)
|
||||
toml_err_set(TOML_ERR_SYNTAX, "%s:%d:%d: unterminated multi-line basic string",
|
||||
self->filename, self->lineno, self->colno);
|
||||
StringBuilder_destroy(&sb);
|
||||
return NULL;
|
||||
//TODO: error handling
|
||||
assert(false && "TODO error handling");
|
||||
}
|
||||
|
||||
toml_next_n(self, 3);
|
||||
|
||||
TomlValue* value = toml_value_new(TOML_STRING);
|
||||
value->value.s = StringBuilder_getStr(&sb);
|
||||
TomlValue value = TomlValue_new(TOML_STRING);
|
||||
value.value.s = StringBuilder_getStr(&sb);
|
||||
return value;
|
||||
}
|
||||
|
||||
TomlValue* toml_parse_multi_line_literal_string(TomlParser* self)
|
||||
TomlValue toml_parse_multi_line_literal_string(TomlParser* self)
|
||||
{
|
||||
StringBuilder sb = StringBuilder_alloc(64);
|
||||
StringBuilder sb = StringBuilder_alloc(0);
|
||||
|
||||
if (*self->ptr == '\n') {
|
||||
toml_move_next(self);
|
||||
@ -748,31 +698,32 @@ TomlValue* toml_parse_multi_line_literal_string(TomlParser* self)
|
||||
toml_err_set(TOML_ERR_SYNTAX, "%s:%d:%d: unterminated multi-line literal string",
|
||||
self->filename, self->lineno, self->colno);
|
||||
StringBuilder_destroy(&sb);
|
||||
return NULL;
|
||||
//TODO: error handling
|
||||
assert(false && "TODO error handling");
|
||||
}
|
||||
|
||||
toml_next_n(self, 3);
|
||||
|
||||
TomlValue* value = toml_value_new(TOML_STRING);
|
||||
value->value.s = StringBuilder_getStr(&sb);
|
||||
TomlValue value = TomlValue_new(TOML_STRING);
|
||||
value.value.s = StringBuilder_getStr(&sb);
|
||||
return value;
|
||||
}
|
||||
|
||||
TomlValue* toml_parse_datetime(str s)
|
||||
TomlValue toml_parse_datetime(str s)
|
||||
{
|
||||
(void)s;
|
||||
//TODO: parse datetime
|
||||
return toml_value_new(TOML_DATETIME);
|
||||
return TomlValue_new(TOML_DATETIME);
|
||||
}
|
||||
|
||||
TomlValue* toml_parse_int_or_float_or_time(TomlParser* self)
|
||||
TomlValue toml_parse_int_or_float_or_time(TomlParser* self)
|
||||
{
|
||||
TomlValue* result = NULL;
|
||||
TomlValue value = {0};
|
||||
|
||||
char type = 'i';
|
||||
i32 base = 10;
|
||||
|
||||
StringBuilder sb = StringBuilder_alloc(64);
|
||||
StringBuilder sb = StringBuilder_alloc(0);
|
||||
|
||||
// Determine nan and inf type as float, as we cannot determine by dot.
|
||||
// But do not strip it because we will append it to the string later
|
||||
@ -831,21 +782,24 @@ TomlValue* toml_parse_int_or_float_or_time(TomlParser* self)
|
||||
toml_err_set(TOML_ERR_SYNTAX, "%s:%d:%d: invalid float",
|
||||
self->filename, self->lineno, self->colno);
|
||||
StringBuilder_destroy(&sb);
|
||||
return NULL;
|
||||
//TODO: error handling
|
||||
assert(false && "TODO error handling");
|
||||
}
|
||||
} else if (*self->ptr == '_') {
|
||||
if (type == 't') {
|
||||
toml_err_set(TOML_ERR_SYNTAX, "%s:%d:%d: invalid datetime",
|
||||
self->filename, self->lineno, self->colno);
|
||||
StringBuilder_destroy(&sb);
|
||||
return NULL;
|
||||
//TODO: error handling
|
||||
assert(false && "TODO error handling");
|
||||
}
|
||||
|
||||
if (!isalnum(last_char)) {
|
||||
toml_err_set(TOML_ERR_SYNTAX, "%s:%d:%d: invalid integer or float",
|
||||
self->filename, self->lineno, self->colno);
|
||||
StringBuilder_destroy(&sb);
|
||||
return NULL;
|
||||
//TODO: error handling
|
||||
assert(false && "TODO error handling");
|
||||
}
|
||||
} else if (*self->ptr == '-') {
|
||||
type = 't';
|
||||
@ -862,62 +816,70 @@ TomlValue* toml_parse_int_or_float_or_time(TomlParser* self)
|
||||
toml_err_set(TOML_ERR_SYNTAX, "%s:%d:%d: invalid integer or float or datetime",
|
||||
self->filename, self->lineno, self->colno);
|
||||
StringBuilder_destroy(&sb);
|
||||
return NULL;
|
||||
//TODO: error handling
|
||||
assert(false && "TODO error handling");
|
||||
}
|
||||
|
||||
if (type == 'i') {
|
||||
char* end = NULL;
|
||||
i64 n = strtoll(StringBuilder_getStr(&sb).data, &end, base);
|
||||
if (end < (char*)sb.buffer.data + sb.buffer.size) {
|
||||
char* start = StringBuilder_getStr(&sb).data;
|
||||
i64 n = strtoll(start, &end, base);
|
||||
if (end < start + sb.buffer.size) {
|
||||
toml_err_set(TOML_ERR_SYNTAX, "%s:%d:%d: invalid integer",
|
||||
self->filename, self->lineno, self->colno);
|
||||
//TODO: error handling
|
||||
printfe("%i < %u '%s'\n", (i32)(end-start), sb.buffer.size, start);
|
||||
fflush(stderr);
|
||||
StringBuilder_destroy(&sb);
|
||||
return NULL;
|
||||
assert(false && "TODO error handling");
|
||||
}
|
||||
result = toml_value_new_integer(n);
|
||||
value = TomlValue_new_integer(n);
|
||||
} else if (type == 'f') {
|
||||
char* end = NULL;
|
||||
f64 n = strtod(StringBuilder_getStr(&sb).data, &end);
|
||||
if (end < (char*)sb.buffer.data + sb.buffer.size) {
|
||||
char* start = StringBuilder_getStr(&sb).data;
|
||||
f64 n = strtod(start, &end);
|
||||
if (end < start + sb.buffer.size) {
|
||||
toml_err_set(TOML_ERR_SYNTAX, "%s:%d:%d: invalid float",
|
||||
self->filename, self->lineno, self->colno);
|
||||
goto cleanup;
|
||||
}
|
||||
result = toml_value_new_float(n);
|
||||
value = TomlValue_new_float(n);
|
||||
} else if (type == 't') {
|
||||
result = toml_parse_datetime(StringBuilder_getStr(&sb));
|
||||
value = toml_parse_datetime(StringBuilder_getStr(&sb));
|
||||
}
|
||||
|
||||
cleanup:
|
||||
StringBuilder_destroy(&sb);
|
||||
return result;
|
||||
return value;
|
||||
}
|
||||
|
||||
TomlValue* toml_parse_bool(TomlParser* self)
|
||||
TomlValue toml_parse_bool(TomlParser* self)
|
||||
{
|
||||
if (self->ptr + 4 <= self->end && strncmp(self->ptr, "true", 4) == 0 &&
|
||||
(self->ptr + 4 == self->end || isspace(*(self->ptr + 4)) || *(self->ptr + 4) == ',' || *(self->ptr + 4) == ']' || *(self->ptr + 4) == '}')) {
|
||||
toml_next_n(self, 4);
|
||||
return toml_value_new_bool(true);
|
||||
return TomlValue_new_bool(true);
|
||||
}
|
||||
|
||||
if (self->ptr + 5 <= self->end && strncmp(self->ptr, "false", 5) == 0 &&
|
||||
(self->ptr + 5 == self->end || isspace(*(self->ptr + 5)) || *(self->ptr + 5) == ',' || *(self->ptr + 5) == ']' || *(self->ptr + 5) == '}')) {
|
||||
toml_next_n(self, 5);
|
||||
return toml_value_new_bool(false);
|
||||
return TomlValue_new_bool(false);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
//TODO: error handling
|
||||
assert(false && "TODO error handling");
|
||||
return TomlValue_new(TOML_INVALID_TYPE);
|
||||
}
|
||||
|
||||
TomlValue* toml_parse_array(TomlParser* self);
|
||||
TomlValue* toml_parse_inline_table(TomlParser* self);
|
||||
TomlValue toml_parse_array(TomlParser* self);
|
||||
TomlValue toml_parse_inline_table(TomlParser* self);
|
||||
|
||||
TomlValue* toml_parse_value(TomlParser* self)
|
||||
TomlValue toml_parse_value(TomlParser* self)
|
||||
{
|
||||
TomlValue* value = NULL;
|
||||
char ch = *self->ptr;
|
||||
|
||||
TomlValue value;
|
||||
if (strncmp(self->ptr, "\"\"\"", 3) == 0) {
|
||||
toml_next_n(self, 3);
|
||||
value = toml_parse_multi_line_basic_string(self);
|
||||
@ -943,7 +905,8 @@ TomlValue* toml_parse_value(TomlParser* self)
|
||||
} else {
|
||||
toml_err_set(TOML_ERR_SYNTAX, "%s:%d:%d: unexpected token",
|
||||
self->filename, self->lineno, self->colno);
|
||||
return NULL;
|
||||
//TODO: error handling
|
||||
assert(false && "TODO error handling");
|
||||
}
|
||||
|
||||
return value;
|
||||
@ -951,9 +914,6 @@ TomlValue* toml_parse_value(TomlParser* self)
|
||||
|
||||
TomlErrCode toml_parse_key_value(TomlParser* self, TomlTable* table)
|
||||
{
|
||||
str key = str_null;
|
||||
TomlValue* value = NULL;
|
||||
|
||||
while (self->ptr < self->end) {
|
||||
char ch;
|
||||
|
||||
@ -965,6 +925,7 @@ TomlErrCode toml_parse_key_value(TomlParser* self, TomlTable* table)
|
||||
|
||||
if (self->ptr == self->end) break;
|
||||
|
||||
str key;
|
||||
if (isalnum(ch) || ch == '_') {
|
||||
key = toml_parse_bare_key(self);
|
||||
if (key.data == NULL)
|
||||
@ -1026,12 +987,12 @@ TomlErrCode toml_parse_key_value(TomlParser* self, TomlTable* table)
|
||||
return TOML_ERR_SYNTAX;
|
||||
}
|
||||
|
||||
value = toml_parse_value(self);
|
||||
if (value == NULL)
|
||||
TomlValue value = toml_parse_value(self);
|
||||
if (value.type == TOML_INVALID_TYPE)
|
||||
return toml_err()->code;
|
||||
|
||||
toml_table_set(table, key, value);
|
||||
str_free(key);
|
||||
str_destroy(key);
|
||||
|
||||
while (self->ptr < self->end && (*self->ptr == ' ' ||* self->ptr == '\t')) {
|
||||
toml_move_next(self);
|
||||
@ -1062,12 +1023,9 @@ TomlErrCode toml_parse_key_value(TomlParser* self, TomlTable* table)
|
||||
return TOML_OK;
|
||||
}
|
||||
|
||||
TomlValue* toml_parse_array(TomlParser* self)
|
||||
TomlValue toml_parse_array(TomlParser* self)
|
||||
{
|
||||
TomlValue* array = NULL;
|
||||
TomlValue* value = NULL;
|
||||
|
||||
array = toml_value_new_array();
|
||||
TomlValue array_value = TomlValue_new_array();
|
||||
|
||||
while (self->ptr < self->end) {
|
||||
if (isspace(*self->ptr)) {
|
||||
@ -1085,14 +1043,14 @@ TomlValue* toml_parse_array(TomlParser* self)
|
||||
toml_move_next(self);
|
||||
break;
|
||||
} else {
|
||||
value = toml_parse_value(self);
|
||||
if (value == NULL) {
|
||||
goto error;
|
||||
TomlValue value = toml_parse_value(self);
|
||||
if (value.type == TOML_INVALID_TYPE) {
|
||||
TomlValue_destroy(&array_value);
|
||||
//TODO: error handling
|
||||
assert(false && "TODO error handling");
|
||||
}
|
||||
|
||||
toml_array_append(array->value.array, value);
|
||||
|
||||
value = NULL;
|
||||
toml_array_append(array_value.value.array, value);
|
||||
|
||||
while (self->ptr < self->end) {
|
||||
if (isspace(*self->ptr)) {
|
||||
@ -1114,22 +1072,12 @@ TomlValue* toml_parse_array(TomlParser* self)
|
||||
}
|
||||
}
|
||||
|
||||
goto end;
|
||||
|
||||
error:
|
||||
toml_value_free(value);
|
||||
toml_value_free(array);
|
||||
array = NULL;
|
||||
|
||||
end:
|
||||
return array;
|
||||
return array_value;
|
||||
}
|
||||
|
||||
TomlValue* toml_parse_inline_table(TomlParser* self)
|
||||
TomlValue toml_parse_inline_table(TomlParser* self)
|
||||
{
|
||||
TomlValue* table = toml_value_new_table();
|
||||
str key = str_null;
|
||||
TomlValue* value = NULL;
|
||||
TomlValue table_value = TomlValue_new_table();
|
||||
|
||||
while (self->ptr < self->end) {
|
||||
char ch = *self->ptr;
|
||||
@ -1138,6 +1086,7 @@ TomlValue* toml_parse_inline_table(TomlParser* self)
|
||||
ch = *self->ptr;
|
||||
}
|
||||
|
||||
str key;
|
||||
if (isalnum(ch) || ch == '_') {
|
||||
key = toml_parse_bare_key(self);
|
||||
if (key.data == NULL)
|
||||
@ -1192,12 +1141,12 @@ TomlValue* toml_parse_inline_table(TomlParser* self)
|
||||
goto error;
|
||||
}
|
||||
|
||||
value = toml_parse_value(self);
|
||||
if (value == NULL)
|
||||
TomlValue value = toml_parse_value(self);
|
||||
if (value.type == TOML_INVALID_TYPE)
|
||||
goto error;
|
||||
|
||||
toml_table_set(table->value.table, key, value);
|
||||
str_free(key);
|
||||
toml_table_set(table_value.value.table, key, value);
|
||||
str_destroy(key);
|
||||
|
||||
while (self->ptr < self->end && (*self->ptr == ' ' ||* self->ptr == '\t')) {
|
||||
toml_move_next(self);
|
||||
@ -1214,11 +1163,11 @@ TomlValue* toml_parse_inline_table(TomlParser* self)
|
||||
goto end;
|
||||
|
||||
error:
|
||||
toml_value_free(table);
|
||||
table = NULL;
|
||||
|
||||
TomlValue_destroy(&table_value);
|
||||
//TODO: error handling
|
||||
assert(false && "TODO error handling");
|
||||
end:
|
||||
return table;
|
||||
return table_value;
|
||||
}
|
||||
|
||||
TomlTable* toml_walk_table_path(TomlParser* parser, TomlTable* table,
|
||||
@ -1226,20 +1175,17 @@ TomlTable* toml_walk_table_path(TomlParser* parser, TomlTable* table,
|
||||
i32 create_if_not_exist)
|
||||
{
|
||||
TomlTable* real_table = table;
|
||||
TomlValue* new_table = NULL;
|
||||
TomlValue* array = NULL;
|
||||
|
||||
if (is_array) {
|
||||
u64 i = 0;
|
||||
for (; i < key_path->len - 1; i++) {
|
||||
str part = key_path->elements[i]->value.s;
|
||||
str part = key_path->elements[i].value.s;
|
||||
TomlValue* t = toml_table_get(real_table, part);
|
||||
if (t == NULL) {
|
||||
if (create_if_not_exist) {
|
||||
new_table = toml_value_new_table();
|
||||
toml_table_set(real_table, part, new_table);
|
||||
real_table = new_table->value.table;
|
||||
new_table = NULL;
|
||||
TomlValue new_table_value = TomlValue_new_table();
|
||||
toml_table_set(real_table, part, new_table_value);
|
||||
real_table = new_table_value.value.table;
|
||||
} else {
|
||||
real_table = NULL;
|
||||
break;
|
||||
@ -1249,17 +1195,15 @@ TomlTable* toml_walk_table_path(TomlParser* parser, TomlTable* table,
|
||||
}
|
||||
}
|
||||
|
||||
str part = key_path->elements[i]->value.s;
|
||||
str part = key_path->elements[i].value.s;
|
||||
TomlValue* t = toml_table_get(real_table, part);
|
||||
if (t == NULL) {
|
||||
if (create_if_not_exist) {
|
||||
array = toml_value_new_array();
|
||||
new_table = toml_value_new_table();
|
||||
toml_array_append(array->value.array, new_table);
|
||||
toml_table_set(real_table, part, array);
|
||||
real_table = new_table->value.table;
|
||||
array = NULL;
|
||||
new_table = NULL;
|
||||
TomlValue array_value = TomlValue_new_array();
|
||||
TomlValue new_table_value = TomlValue_new_table();
|
||||
toml_array_append(array_value.value.array, new_table_value);
|
||||
toml_table_set(real_table, part, array_value);
|
||||
real_table = new_table_value.value.table;
|
||||
} else {
|
||||
real_table = NULL;
|
||||
}
|
||||
@ -1270,28 +1214,26 @@ TomlTable* toml_walk_table_path(TomlParser* parser, TomlTable* table,
|
||||
goto error;
|
||||
}
|
||||
|
||||
new_table = toml_value_new_table();
|
||||
toml_array_append(t->value.array, new_table);
|
||||
real_table = new_table->value.table;
|
||||
new_table = NULL;
|
||||
TomlValue new_table_value = TomlValue_new_table();
|
||||
toml_array_append(t->value.array, new_table_value);
|
||||
real_table = new_table_value.value.table;
|
||||
}
|
||||
} else {
|
||||
for (u64 i = 0; i < key_path->len; i++) {
|
||||
str part = key_path->elements[i]->value.s;
|
||||
str part = key_path->elements[i].value.s;
|
||||
TomlValue* t = toml_table_get(real_table, part);
|
||||
if (t == NULL) {
|
||||
if (create_if_not_exist) {
|
||||
new_table = toml_value_new_table();
|
||||
toml_table_set(real_table, part, new_table);
|
||||
real_table = new_table->value.table;
|
||||
new_table = NULL;
|
||||
TomlValue new_table_value = TomlValue_new_table();
|
||||
toml_table_set(real_table, part, new_table_value);
|
||||
real_table = new_table_value.value.table;
|
||||
} else {
|
||||
real_table = NULL;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (t->type == TOML_ARRAY) {
|
||||
real_table = t->value.array->elements[t->value.array->len - 1]->value.table;
|
||||
real_table = t->value.array->elements[t->value.array->len - 1].value.table;
|
||||
} else if (t->type == TOML_TABLE) {
|
||||
real_table = t->value.table;
|
||||
}
|
||||
@ -1302,9 +1244,9 @@ TomlTable* toml_walk_table_path(TomlParser* parser, TomlTable* table,
|
||||
goto end;
|
||||
|
||||
error:
|
||||
toml_value_free(new_table);
|
||||
toml_value_free(array);
|
||||
real_table = NULL;
|
||||
//TODO: error handling
|
||||
assert(false && "TODO error handling");
|
||||
|
||||
end:
|
||||
return real_table;
|
||||
@ -1340,9 +1282,7 @@ TomlErrCode toml_parse_table(TomlParser* self, TomlTable* table)
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
str key_part = str_null;
|
||||
TomlValue* key_part_value = NULL;
|
||||
|
||||
str key_part;
|
||||
if (isalnum(*self->ptr) ||* self->ptr == '_') {
|
||||
key_part = toml_parse_bare_key(self);
|
||||
if (key_part.data == NULL)
|
||||
@ -1363,8 +1303,8 @@ TomlErrCode toml_parse_table(TomlParser* self, TomlTable* table)
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
key_part_value = toml_value_new(TOML_STRING);
|
||||
key_part_value->value.s = key_part;
|
||||
TomlValue key_part_value = TomlValue_new(TOML_STRING);
|
||||
key_part_value.value.s = key_part;
|
||||
|
||||
toml_array_append(key_path, key_part_value);
|
||||
|
||||
@ -1485,7 +1425,7 @@ TomlTable* toml_load_file_filename(FILE* file, cstr filename)
|
||||
sb.buffer.size += count;
|
||||
|
||||
if (sb.buffer.size + 1 >= sb.buffer.allocated_size) {
|
||||
StringBuilder_expand(&sb, file_chunk_size);
|
||||
StringBuilder_increaseCapacity(&sb, file_chunk_size);
|
||||
}
|
||||
} while (count == remaining_capacity);
|
||||
|
||||
|
||||
23
tests/main.c
23
tests/main.c
@ -3,6 +3,7 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <assert.h>
|
||||
#include "tlibtoml/toml.h"
|
||||
|
||||
#ifndef PROJECT_SOURCE_DIR
|
||||
@ -19,7 +20,7 @@ void print_array(const TomlArray *array)
|
||||
if (i > 0) {
|
||||
printf(", ");
|
||||
}
|
||||
print_value(array->elements[i]);
|
||||
print_value(&array->elements[i]);
|
||||
}
|
||||
printf("]");
|
||||
}
|
||||
@ -27,6 +28,9 @@ void print_array(const TomlArray *array)
|
||||
void print_value(const TomlValue* value)
|
||||
{
|
||||
switch (value->type) {
|
||||
default:
|
||||
assert(false && "invalid type");
|
||||
break;
|
||||
case TOML_TABLE:
|
||||
print_table(value->value.table);
|
||||
break;
|
||||
@ -51,7 +55,7 @@ void print_value(const TomlValue* value)
|
||||
}
|
||||
}
|
||||
|
||||
void print_keyval(const TomlKeyValue *keyval)
|
||||
void print_keyval(HashMapKeyValue* keyval)
|
||||
{
|
||||
printf("\"%s\": ", keyval->key.data);
|
||||
print_value(keyval->value);
|
||||
@ -59,19 +63,16 @@ void print_keyval(const TomlKeyValue *keyval)
|
||||
|
||||
void print_table(const TomlTable* table)
|
||||
{
|
||||
TomlTableIter it = toml_table_iter_new((TomlTable*)table);
|
||||
HashMapIter it = HashMapIter_create(table);
|
||||
|
||||
printf("{");
|
||||
u64 i = 0;
|
||||
while (toml_table_iter_has_next(&it)) {
|
||||
TomlKeyValue *keyval = toml_table_iter_get(&it);
|
||||
|
||||
if (i > 0) {
|
||||
HashMapKeyValue keyval;
|
||||
while (HashMapIter_moveNext(&it)) {
|
||||
assert(HashMapIter_getCurrent(&it, &keyval));
|
||||
if (i > 0)
|
||||
printf(", ");
|
||||
}
|
||||
print_keyval(keyval);
|
||||
|
||||
toml_table_iter_next(&it);
|
||||
print_keyval(&keyval);
|
||||
i++;
|
||||
}
|
||||
printf("}");
|
||||
|
||||
Loading…
Reference in New Issue
Block a user