Get something working
Some checks failed
CMake / ubuntu-latest - shared=OFF, pthread=OFF, posix=OFF (push) Failing after 13s
CMake / ubuntu-latest - shared=ON, pthread=OFF, posix=OFF (push) Failing after 16s
CMake / ubuntu-latest - shared=OFF, pthread=OFF, posix=ON (push) Failing after 12s
CMake / ubuntu-latest - shared=ON, pthread=OFF, posix=ON (push) Failing after 14s
CMake / ubuntu-latest - shared=OFF, pthread=ON, posix=ON (push) Failing after 16s
CMake / ubuntu-latest - shared=ON, pthread=ON, posix=ON (push) Failing after 13s
Some checks failed
CMake / ubuntu-latest - shared=OFF, pthread=OFF, posix=OFF (push) Failing after 13s
CMake / ubuntu-latest - shared=ON, pthread=OFF, posix=OFF (push) Failing after 16s
CMake / ubuntu-latest - shared=OFF, pthread=OFF, posix=ON (push) Failing after 12s
CMake / ubuntu-latest - shared=ON, pthread=OFF, posix=ON (push) Failing after 14s
CMake / ubuntu-latest - shared=OFF, pthread=ON, posix=ON (push) Failing after 16s
CMake / ubuntu-latest - shared=ON, pthread=ON, posix=ON (push) Failing after 13s
Signed-off-by: Slendi <slendi@socopon.com>
This commit is contained in:
421
src/dcfg.c
421
src/dcfg.c
@@ -21,6 +21,8 @@
|
||||
*/
|
||||
|
||||
#include <dcfg.h>
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "meta.h"
|
||||
@@ -33,7 +35,7 @@
|
||||
// FIXME: Fix this stupid shit!
|
||||
# error "realpath() is dumb and stupid on sun. sorry not sorry."
|
||||
# endif
|
||||
# define _XOPEN_SOURCE 200809L
|
||||
# define _POSIX_C_SOURCE 200809L
|
||||
#else
|
||||
# ifdef _POSIX_C_SOURCE
|
||||
# undef _POSIX_C_SOURCE
|
||||
@@ -41,6 +43,33 @@
|
||||
# define _POSIX_C_SOURCE 0L
|
||||
#endif
|
||||
|
||||
#ifdef DCFG_PTHREAD_SUPPORT
|
||||
# ifdef _POSIX_C_SOURCE
|
||||
# undef _POSIX_C_SOURCE
|
||||
# endif
|
||||
# define _POSIX_C_SOURCE 200809L
|
||||
# include <pthread.h>
|
||||
extern int pthread_mutexattr_settype(pthread_mutexattr_t *, int);
|
||||
#else
|
||||
# if defined __USE_POSIX199506 || defined __USE_UNIX98
|
||||
# else
|
||||
typedef struct {
|
||||
int unused;
|
||||
} pthread_mutex_t;
|
||||
typedef struct {
|
||||
int unused;
|
||||
} pthread_mutexattr_t;
|
||||
# define PTHREAD_MUTEX_RECURSIVE_NP 0
|
||||
# endif
|
||||
|
||||
static void pthread_mutex_init(pthread_mutex_t *, void *) { }
|
||||
static void pthread_mutex_destroy(pthread_mutex_t *) { }
|
||||
static void pthread_mutex_lock(pthread_mutex_t *) { }
|
||||
static void pthread_mutex_unlock(pthread_mutex_t *) { }
|
||||
pthread_mutexattr_init(pthread_mutexattr_t *);
|
||||
static void pthread_mutexattr_settype(pthread_mutexattr_t *, int) { }
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
@@ -48,22 +77,6 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef DCFG_PTHREAD_SUPPORT
|
||||
# include <pthread.h>
|
||||
#else
|
||||
# if defined __USE_POSIX199506 || defined __USE_UNIX98
|
||||
# else
|
||||
typedef struct {
|
||||
int unused;
|
||||
} pthread_mutex_t;
|
||||
# endif
|
||||
|
||||
void pthread_mutex_init(pthread_mutex_t *, void *);
|
||||
void pthread_mutex_destroy(pthread_mutex_t *);
|
||||
void pthread_mutex_lock(pthread_mutex_t *);
|
||||
void pthread_mutex_unlock(pthread_mutex_t *);
|
||||
#endif
|
||||
|
||||
int64_t dcfg_strtoll(const char *s, char **end, int base)
|
||||
{
|
||||
char const *p = s;
|
||||
@@ -258,6 +271,7 @@ typedef struct {
|
||||
} ValueArray;
|
||||
|
||||
typedef struct {
|
||||
struct Environment *closure;
|
||||
StringView *argv;
|
||||
Value *body;
|
||||
} ValueFunctionF;
|
||||
@@ -265,7 +279,7 @@ typedef struct {
|
||||
typedef struct {
|
||||
bool is_builtin;
|
||||
union {
|
||||
Value *(*bi)(Value **argv, size_t argc);
|
||||
dcfg_BuiltIn bi;
|
||||
ValueFunctionF f;
|
||||
} v;
|
||||
} ValueFunction;
|
||||
@@ -276,16 +290,13 @@ typedef struct {
|
||||
} ValueFunctionCall;
|
||||
|
||||
typedef struct {
|
||||
StringView **accessv;
|
||||
StringView *accessv;
|
||||
} ValueMemberAccess;
|
||||
|
||||
struct dcfg_Value {
|
||||
Instance *instance;
|
||||
dcfg_ValueType type;
|
||||
SourceLocation location;
|
||||
int i_sourcev_idx;
|
||||
int i_source_pathv_idx;
|
||||
int i_environment_idx;
|
||||
|
||||
union {
|
||||
int64_t i;
|
||||
@@ -304,10 +315,10 @@ struct dcfg_Value {
|
||||
typedef struct Environment {
|
||||
struct Environment *parent;
|
||||
StringView *argv;
|
||||
Value *argvv;
|
||||
Value **argvv;
|
||||
} Environment;
|
||||
|
||||
bool environment_create(Environment *out_env, Environment *parent)
|
||||
static bool environment_create(Environment *out_env, Environment *parent)
|
||||
{
|
||||
out_env->argv = vector_create();
|
||||
out_env->argvv = vector_create();
|
||||
@@ -315,13 +326,35 @@ bool environment_create(Environment *out_env, Environment *parent)
|
||||
return true;
|
||||
}
|
||||
|
||||
void environment_destroy(Environment *env)
|
||||
static bool environment_lookup(Environment *e, StringView name, Value **out)
|
||||
{
|
||||
vector_free(&env->argv);
|
||||
for (size_t i = 0; i < vector_size(env->argvv); i++) {
|
||||
dcfg_destroy(&env->argvv[i]);
|
||||
for (; e; e = e->parent) {
|
||||
for (size_t i = 0; i < vector_size(e->argv); i++) {
|
||||
if (sv_eq(e->argv[i], name)) {
|
||||
*out = e->argvv[i];
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void environment_destroy(Environment *env, bool destroy_values)
|
||||
{
|
||||
assert(env);
|
||||
if (env->argv) {
|
||||
vector_free(env->argv);
|
||||
env->argv = NULL;
|
||||
}
|
||||
if (env->argvv) {
|
||||
if (destroy_values) {
|
||||
for (size_t i = 0; i < vector_size(env->argvv); i++) {
|
||||
dcfg_destroy(env->argvv[i]);
|
||||
}
|
||||
}
|
||||
vector_free(env->argvv);
|
||||
env->argvv = NULL;
|
||||
}
|
||||
vector_free(&env->argvv);
|
||||
}
|
||||
|
||||
struct dcfg_Instance {
|
||||
@@ -369,7 +402,11 @@ dcfg_Instance *dcfg_make_instance(dcfg_InstanceCreateInfo const *create_info)
|
||||
if (!instance) {
|
||||
return NULL;
|
||||
}
|
||||
pthread_mutex_init(&instance->mtx, NULL);
|
||||
|
||||
pthread_mutexattr_t attr;
|
||||
pthread_mutexattr_init(&attr);
|
||||
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE_NP);
|
||||
pthread_mutex_init(&instance->mtx, &attr);
|
||||
|
||||
instance->alloc = create_info->alloc;
|
||||
instance->free = create_info->free;
|
||||
@@ -416,7 +453,7 @@ void dcfg_destroy_instance(dcfg_Instance *instance)
|
||||
for (size_t i = 0; i < vector_size(instance->environment_referencesv);
|
||||
i++) {
|
||||
if (instance->environment_referencesv[i] > 0) {
|
||||
environment_destroy(&instance->environmentv[i]);
|
||||
// environment_destroy(&instance->environmentv[i], true);
|
||||
}
|
||||
}
|
||||
vector_free(instance->environment_referencesv);
|
||||
@@ -1346,9 +1383,9 @@ Value *ast_to_value(dcfg_Instance *instance, AST *root)
|
||||
value->v.f.v.f.body = v;
|
||||
} else if (root->kind == ASTKind_MemberAccess) {
|
||||
value->type = dcfg_ValueType_MemberAccess;
|
||||
// FIXME: Implement
|
||||
FREE(value);
|
||||
return NULL;
|
||||
value->v.ma.accessv = vector_create();
|
||||
for (size_t i = 0; i < vector_size(root->v.m.accessv); i++)
|
||||
vector_add(&value->v.ma.accessv, StringView, root->v.m.accessv[i]);
|
||||
} else if (root->kind == ASTKind_FunctionCall) {
|
||||
value->type = dcfg_ValueType_FunctionCall;
|
||||
Value *function = ast_to_value(instance, root->v.fc.function);
|
||||
@@ -1477,10 +1514,7 @@ dcfg_Value *dcfg_parse(dcfg_Instance *instance, dcfg_StringView const file_path)
|
||||
instance->last_error[0] = '\0';
|
||||
|
||||
vector_add(&instance->sourcev, StringView, str);
|
||||
v->i_sourcev_idx = vector_size(instance->sourcev) - 1;
|
||||
|
||||
vector_add(&instance->source_pathv, StringView, abs_sv);
|
||||
v->i_source_pathv_idx = vector_size(instance->source_pathv) - 1;
|
||||
|
||||
return v;
|
||||
}
|
||||
@@ -1523,6 +1557,10 @@ void dcfg_destroy(dcfg_Value *value)
|
||||
vector_free(value->v.c.argv);
|
||||
break;
|
||||
|
||||
case dcfg_ValueType_MemberAccess:
|
||||
vector_free(value->v.ma.accessv);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -1530,6 +1568,142 @@ void dcfg_destroy(dcfg_Value *value)
|
||||
value->instance->free(value); // https://youtu.be/RgFaK6ZQifE
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
dcfg_Instance *inst;
|
||||
char *buf;
|
||||
size_t len, cap;
|
||||
} StrBld;
|
||||
|
||||
static bool sb_reserve(StrBld *sb, size_t more)
|
||||
{
|
||||
if (sb->len + more <= sb->cap)
|
||||
return true;
|
||||
size_t ncap = sb->cap ? sb->cap * 2 : 128;
|
||||
while (ncap < sb->len + more)
|
||||
ncap *= 2;
|
||||
char *nbuf = sb->inst->alloc(ncap);
|
||||
if (!nbuf)
|
||||
return false;
|
||||
if (sb->buf) {
|
||||
memcpy(nbuf, sb->buf, sb->len);
|
||||
sb->inst->free(sb->buf);
|
||||
}
|
||||
sb->buf = nbuf;
|
||||
sb->cap = ncap;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool sb_put(StrBld *sb, char const *s, size_t n)
|
||||
{
|
||||
if (!sb_reserve(sb, n))
|
||||
return false;
|
||||
memcpy(sb->buf + sb->len, s, n);
|
||||
sb->len += n;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool sb_put_sv(StrBld *sb, StringView sv)
|
||||
{
|
||||
return sb_put(sb, sv.data, sv.size);
|
||||
}
|
||||
|
||||
static bool sb_put_char(StrBld *sb, char c) { return sb_put(sb, &c, 1); }
|
||||
|
||||
static bool ser_value(dcfg_Value *v, StrBld *sb)
|
||||
{
|
||||
switch (v->type) {
|
||||
case dcfg_ValueType_Nil:
|
||||
return sb_put(sb, "nil", 3);
|
||||
case dcfg_ValueType_Boolean:
|
||||
return sb_put(sb, v->v.b ? "true" : "false", v->v.b ? 4 : 5);
|
||||
case dcfg_ValueType_Integer: {
|
||||
char tmp[64];
|
||||
int n = snprintf(tmp, sizeof tmp, "%" PRId64, v->v.i);
|
||||
return sb_put(sb, tmp, (size_t)n);
|
||||
}
|
||||
case dcfg_ValueType_Real: {
|
||||
char tmp[64];
|
||||
int n = snprintf(tmp, sizeof tmp, "%.17g", v->v.r);
|
||||
return sb_put(sb, tmp, (size_t)n);
|
||||
}
|
||||
case dcfg_ValueType_String: {
|
||||
if (!sb_put_char(sb, '"'))
|
||||
return false;
|
||||
for (size_t i = 0; i < v->v.s.size; ++i) {
|
||||
char c = v->v.s.data[i];
|
||||
if (c == '"' || c == '\\') {
|
||||
if (!sb_put_char(sb, '\\'))
|
||||
return false;
|
||||
}
|
||||
if (!sb_put_char(sb, c))
|
||||
return false;
|
||||
}
|
||||
return sb_put_char(sb, '"');
|
||||
}
|
||||
case dcfg_ValueType_Path:
|
||||
return sb_put_sv(sb, v->v.p);
|
||||
case dcfg_ValueType_Array: {
|
||||
if (!sb_put_char(sb, '['))
|
||||
return false;
|
||||
for (size_t i = 0; i < vector_size(v->v.a.valuev); ++i) {
|
||||
if (i && !sb_put(sb, ", ", 2))
|
||||
return false;
|
||||
if (!ser_value(v->v.a.valuev[i], sb))
|
||||
return false;
|
||||
}
|
||||
return sb_put_char(sb, ']');
|
||||
}
|
||||
case dcfg_ValueType_Object: {
|
||||
if (!sb_put_char(sb, '{'))
|
||||
return false;
|
||||
for (size_t i = 0; i < vector_size(v->v.o.entryv); ++i) {
|
||||
ValueObjectEntry *e = &v->v.o.entryv[i];
|
||||
if (i && !sb_put(sb, ", ", 2))
|
||||
return false;
|
||||
if (!sb_put_sv(sb, e->k) || !sb_put(sb, " = ", 3))
|
||||
return false;
|
||||
if (!ser_value(e->v, sb))
|
||||
return false;
|
||||
}
|
||||
return sb_put_char(sb, '}');
|
||||
}
|
||||
case dcfg_ValueType_Function:
|
||||
return sb_put(sb, "<function>", 10);
|
||||
case dcfg_ValueType_FunctionCall:
|
||||
return sb_put(sb, "<call>", 6);
|
||||
case dcfg_ValueType_MemberAccess:
|
||||
return sb_put(sb, "<member>", 8);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool dcfg_serialize_value(dcfg_Value *value, dcfg_StringView *out_sv)
|
||||
{
|
||||
if (!value || !out_sv)
|
||||
return false;
|
||||
|
||||
StrBld sb = { .inst = value->instance };
|
||||
if (!ser_value(value, &sb)) {
|
||||
if (sb.buf)
|
||||
value->instance->free(sb.buf);
|
||||
return false;
|
||||
}
|
||||
|
||||
char *final = value->instance->alloc(sb.len + 1);
|
||||
if (!final) {
|
||||
value->instance->free(sb.buf);
|
||||
return false;
|
||||
}
|
||||
memcpy(final, sb.buf, sb.len);
|
||||
final[sb.len] = '\0';
|
||||
value->instance->free(sb.buf);
|
||||
|
||||
out_sv->data = final;
|
||||
out_sv->size = sb.len;
|
||||
return true;
|
||||
}
|
||||
|
||||
dcfg_ValueType dcfg_Value_type_ex(dcfg_Value *value, bool evaluate)
|
||||
{
|
||||
if (!value)
|
||||
@@ -1662,22 +1836,22 @@ bool dcfg_Value_get_array_size(dcfg_Value *value, size_t *out_size)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool dcfg_call_function(dcfg_Value *function, dcfg_Value **args,
|
||||
size_t arg_count, dcfg_Value **out_value)
|
||||
static bool eval_member(ValueMemberAccess *ma, Environment *env, Value **out)
|
||||
{
|
||||
if (function->v.f.is_builtin) {
|
||||
*out_value = function->v.f.v.bi(args, arg_count);
|
||||
if (!*out_value) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// FIXME: Implement
|
||||
Value *root;
|
||||
if (!environment_lookup(env, ma->accessv[0], &root))
|
||||
return false;
|
||||
|
||||
for (size_t i = 1; i < vector_size(ma->accessv); ++i) {
|
||||
if (!dcfg_Value_get_object_field_ex(root, ma->accessv[i], &root, true))
|
||||
return false;
|
||||
}
|
||||
*out = root;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool dcfg_Value_evaluate(dcfg_Value *value, dcfg_Value **out_value)
|
||||
bool dcfg_Value_evaluate_in_env(
|
||||
dcfg_Value *value, Environment *frame, dcfg_Value **out_value)
|
||||
{
|
||||
assert(value);
|
||||
assert(out_value);
|
||||
@@ -1686,6 +1860,7 @@ bool dcfg_Value_evaluate(dcfg_Value *value, dcfg_Value **out_value)
|
||||
value->instance->last_error[0] = '\0';
|
||||
*out_value = value->instance->alloc(sizeof(**out_value));
|
||||
Value *v = *out_value;
|
||||
(*out_value)->instance = value->instance;
|
||||
|
||||
if (value->type == dcfg_ValueType_Nil) {
|
||||
v->type = dcfg_ValueType_Nil;
|
||||
@@ -1710,7 +1885,7 @@ bool dcfg_Value_evaluate(dcfg_Value *value, dcfg_Value **out_value)
|
||||
for (size_t i = 0; i < vector_size(value->v.o.entryv); i++) {
|
||||
ValueObjectEntry *e = &value->v.o.entryv[i];
|
||||
Value *new_v;
|
||||
bool res = dcfg_Value_evaluate(e->v, &new_v);
|
||||
bool res = dcfg_Value_evaluate_in_env(e->v, frame, &new_v);
|
||||
if (!res) {
|
||||
ret = false;
|
||||
break;
|
||||
@@ -1718,6 +1893,7 @@ bool dcfg_Value_evaluate(dcfg_Value *value, dcfg_Value **out_value)
|
||||
ValueObjectEntry ne = {
|
||||
.k = e->k,
|
||||
.v = new_v,
|
||||
.key_allocated = true,
|
||||
};
|
||||
ne.k.data = value->instance->alloc(ne.k.size + 1);
|
||||
memcpy((void *)ne.k.data, e->k.data, ne.k.size);
|
||||
@@ -1729,7 +1905,8 @@ bool dcfg_Value_evaluate(dcfg_Value *value, dcfg_Value **out_value)
|
||||
v->v.a.valuev = vector_create();
|
||||
for (size_t i = 0; i < vector_size(value->v.a.valuev); i++) {
|
||||
Value *val = NULL;
|
||||
bool res = dcfg_Value_evaluate(value->v.a.valuev[i], &val);
|
||||
bool res
|
||||
= dcfg_Value_evaluate_in_env(value->v.a.valuev[i], frame, &val);
|
||||
if (!res) {
|
||||
ret = false;
|
||||
}
|
||||
@@ -1743,11 +1920,23 @@ bool dcfg_Value_evaluate(dcfg_Value *value, dcfg_Value **out_value)
|
||||
ret = false;
|
||||
}
|
||||
} else if (value->type == dcfg_ValueType_MemberAccess) {
|
||||
// FIXME: Implement
|
||||
ret = false;
|
||||
if (!frame) {
|
||||
ret = false;
|
||||
strcpy(value->instance->last_error,
|
||||
"Cannot use member access outside of function");
|
||||
} else {
|
||||
Value *out_value_prev = *out_value;
|
||||
bool ok = eval_member(&value->v.ma, frame, out_value);
|
||||
if (!ok) {
|
||||
ret = false;
|
||||
} else {
|
||||
dcfg_destroy(out_value_prev);
|
||||
}
|
||||
}
|
||||
} else if (value->type == dcfg_ValueType_FunctionCall) {
|
||||
Value *function;
|
||||
bool res = dcfg_Value_evaluate(value->v.c.function, &function);
|
||||
bool res
|
||||
= dcfg_Value_evaluate_in_env(value->v.c.function, frame, &function);
|
||||
if (!res || function->type != dcfg_ValueType_Function) {
|
||||
ret = false;
|
||||
} else {
|
||||
@@ -1755,8 +1944,9 @@ bool dcfg_Value_evaluate(dcfg_Value *value, dcfg_Value **out_value)
|
||||
bool res = dcfg_call_function(function, value->v.c.argv,
|
||||
vector_size(value->v.c.argv), out_value);
|
||||
if (!res) {
|
||||
dcfg_destroy(out_value_prev);
|
||||
ret = false;
|
||||
} else {
|
||||
dcfg_destroy(out_value_prev);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -1768,6 +1958,131 @@ bool dcfg_Value_evaluate(dcfg_Value *value, dcfg_Value **out_value)
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool dcfg_call_function(
|
||||
dcfg_Value *fn, dcfg_Value **args, size_t argc, dcfg_Value **out_value)
|
||||
{
|
||||
pthread_mutex_lock(&fn->instance->mtx);
|
||||
if (fn->v.f.is_builtin) {
|
||||
*out_value = fn->v.f.v.bi(args, argc);
|
||||
pthread_mutex_unlock(&fn->instance->mtx);
|
||||
return *out_value != NULL;
|
||||
}
|
||||
|
||||
Environment frame;
|
||||
if (!environment_create(&frame, fn->v.f.v.f.closure)) {
|
||||
pthread_mutex_unlock(&fn->instance->mtx);
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t nform = vector_size(fn->v.f.v.f.argv);
|
||||
if (argc != nform) {
|
||||
strcpy(fn->instance->last_error, "Invalid argument count");
|
||||
environment_destroy(&frame, false);
|
||||
pthread_mutex_unlock(&fn->instance->mtx);
|
||||
return false;
|
||||
}
|
||||
for (size_t i = 0; i < nform; i++) {
|
||||
vector_add(&frame.argv, StringView, fn->v.f.v.f.argv[i]);
|
||||
vector_add(&frame.argvv, Value *, args[i]);
|
||||
}
|
||||
|
||||
bool ok = dcfg_Value_evaluate_in_env(fn->v.f.v.f.body, &frame, out_value);
|
||||
environment_destroy(&frame, false);
|
||||
pthread_mutex_unlock(&fn->instance->mtx);
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool dcfg_Value_evaluate(dcfg_Value *value, dcfg_Value **out_value)
|
||||
{
|
||||
bool ret;
|
||||
pthread_mutex_lock(&value->instance->mtx);
|
||||
{
|
||||
ret = dcfg_Value_evaluate_in_env(value, NULL, out_value);
|
||||
}
|
||||
pthread_mutex_unlock(&value->instance->mtx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool dcfg_Value_evaluate_toplevel(dcfg_Value *top, dcfg_Value **out_value,
|
||||
dcfg_StringView *function_names, dcfg_BuiltIn *functions,
|
||||
size_t function_count)
|
||||
{
|
||||
if (!top)
|
||||
return false;
|
||||
if (top->type != dcfg_ValueType_Function)
|
||||
return dcfg_Value_evaluate(top, out_value);
|
||||
|
||||
Instance *inst = top->instance;
|
||||
|
||||
Value *lib = inst->alloc(sizeof *lib);
|
||||
if (!lib)
|
||||
return false;
|
||||
lib->instance = inst;
|
||||
lib->type = dcfg_ValueType_Object;
|
||||
lib->v.o.entryv = vector_create();
|
||||
if (!lib->v.o.entryv) {
|
||||
inst->free(lib);
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < function_count; ++i) {
|
||||
Value *fn = inst->alloc(sizeof *fn);
|
||||
if (!fn) {
|
||||
dcfg_destroy(lib);
|
||||
return false;
|
||||
}
|
||||
fn->instance = inst;
|
||||
fn->type = dcfg_ValueType_Function;
|
||||
fn->v.f.is_builtin = true;
|
||||
fn->v.f.v.bi = functions[i];
|
||||
|
||||
StringView name = function_names[i];
|
||||
Value *target = lib;
|
||||
size_t start = 0;
|
||||
for (size_t pos = 0; pos <= name.size; ++pos) {
|
||||
bool end = (pos == name.size);
|
||||
if (end || name.data[pos] == '.') {
|
||||
StringView seg
|
||||
= { .data = name.data + start, .size = pos - start };
|
||||
|
||||
if (end) {
|
||||
ValueObject *obj = &target->v.o;
|
||||
bool replaced = false;
|
||||
for (size_t j = 0; j < vector_size(obj->entryv); ++j) {
|
||||
if (sv_eq(obj->entryv[j].k, seg)) {
|
||||
dcfg_destroy(obj->entryv[j].v);
|
||||
obj->entryv[j].v = fn;
|
||||
replaced = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!replaced) {
|
||||
ValueObjectEntry e
|
||||
= { .k = seg, .v = fn, .key_allocated = false };
|
||||
vector_add(&obj->entryv, ValueObjectEntry, e);
|
||||
}
|
||||
} else {
|
||||
target = ensure_child_obj(inst, target, seg);
|
||||
if (target->type != dcfg_ValueType_Object) {
|
||||
dcfg_destroy(fn);
|
||||
dcfg_destroy(lib);
|
||||
strcpy(inst->last_error,
|
||||
"Function name clashes with non-object field");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
start = pos + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Value *argv[1] = { lib };
|
||||
bool ok = dcfg_call_function(top, argv, 1, out_value);
|
||||
vector_free(lib->v.o.entryv);
|
||||
inst->free(lib);
|
||||
return ok;
|
||||
}
|
||||
|
||||
// Libraries
|
||||
#include "vendor/utf8proc.c"
|
||||
#include "vendor/vec.c"
|
||||
|
Reference in New Issue
Block a user