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:
@@ -2,19 +2,30 @@ cmake_minimum_required(VERSION 3.10)
|
|||||||
|
|
||||||
project(DCFG C)
|
project(DCFG C)
|
||||||
|
|
||||||
|
option(DCFG_PTHREAD_SUPPORT "Enable pthreads support" ON)
|
||||||
|
option(DCFG_POSIX_SUPPORT "Enable POSIX support" ON)
|
||||||
|
option(DCFG_BUILD_PROGRAMS "Build DCFG example programs" ON)
|
||||||
|
option(DCFG_ASAN "Enable AddressSanitizer" OFF)
|
||||||
|
|
||||||
set(CMAKE_C_STANDARD 99)
|
set(CMAKE_C_STANDARD 99)
|
||||||
set(CMAKE_C_STANDARD_REQUIRED ON)
|
set(CMAKE_C_STANDARD_REQUIRED ON)
|
||||||
set(CMAKE_C_EXTENSIONS OFF)
|
set(CMAKE_C_EXTENSIONS OFF)
|
||||||
|
|
||||||
option(DCFG_PTHREAD_SUPPORT "Enable pthreads support" ON)
|
|
||||||
option(DCFG_POSIX_SUPPORT "Enable POSIX support" ON)
|
|
||||||
option(DCFG_BUILD_PROGRAMS "Build DCFG example programs" ON)
|
|
||||||
|
|
||||||
find_package(Threads)
|
find_package(Threads)
|
||||||
|
|
||||||
set(SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src)
|
set(SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src)
|
||||||
set(INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/include)
|
set(INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/include)
|
||||||
|
|
||||||
|
if(DCFG_ASAN)
|
||||||
|
if(MSVC)
|
||||||
|
set(ASAN_COMPILE_FLAGS /fsanitize=address)
|
||||||
|
set(ASAN_LINK_FLAGS /fsanitize=address)
|
||||||
|
else()
|
||||||
|
set(ASAN_COMPILE_FLAGS -fsanitize=address -fno-omit-frame-pointer)
|
||||||
|
set(ASAN_LINK_FLAGS -fsanitize=address)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
# Shared library
|
# Shared library
|
||||||
add_library(${PROJECT_NAME}_shared SHARED ${SRC_DIR}/dcfg.c)
|
add_library(${PROJECT_NAME}_shared SHARED ${SRC_DIR}/dcfg.c)
|
||||||
target_include_directories(${PROJECT_NAME}_shared PUBLIC ${INCLUDE_DIR})
|
target_include_directories(${PROJECT_NAME}_shared PUBLIC ${INCLUDE_DIR})
|
||||||
@@ -25,13 +36,13 @@ add_library(${PROJECT_NAME}_static STATIC ${SRC_DIR}/dcfg.c)
|
|||||||
target_include_directories(${PROJECT_NAME}_static PUBLIC ${INCLUDE_DIR})
|
target_include_directories(${PROJECT_NAME}_static PUBLIC ${INCLUDE_DIR})
|
||||||
set_target_properties(${PROJECT_NAME}_static PROPERTIES OUTPUT_NAME "dcfg")
|
set_target_properties(${PROJECT_NAME}_static PROPERTIES OUTPUT_NAME "dcfg")
|
||||||
|
|
||||||
# Common settings for both libraries
|
|
||||||
foreach(TARGET ${PROJECT_NAME}_shared ${PROJECT_NAME}_static)
|
foreach(TARGET ${PROJECT_NAME}_shared ${PROJECT_NAME}_static)
|
||||||
if(DCFG_PTHREAD_SUPPORT)
|
if(DCFG_PTHREAD_SUPPORT)
|
||||||
find_package(Threads REQUIRED)
|
find_package(Threads REQUIRED)
|
||||||
target_link_libraries(${TARGET} PRIVATE Threads::Threads)
|
target_link_libraries(${TARGET} PRIVATE Threads::Threads)
|
||||||
target_compile_definitions(${TARGET} PRIVATE DCFG_PTHREAD_SUPPORT)
|
target_compile_definitions(${TARGET} PRIVATE DCFG_PTHREAD_SUPPORT)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(DCFG_POSIX_SUPPORT)
|
if(DCFG_POSIX_SUPPORT)
|
||||||
target_compile_definitions(${TARGET} PRIVATE DCFG_POSIX_SUPPORT)
|
target_compile_definitions(${TARGET} PRIVATE DCFG_POSIX_SUPPORT)
|
||||||
endif()
|
endif()
|
||||||
@@ -45,13 +56,17 @@ foreach(TARGET ${PROJECT_NAME}_shared ${PROJECT_NAME}_static)
|
|||||||
if(NOT MSVC)
|
if(NOT MSVC)
|
||||||
target_link_libraries(${TARGET} PRIVATE m)
|
target_link_libraries(${TARGET} PRIVATE m)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# AddressSanitizer
|
||||||
|
if(DCFG_ASAN)
|
||||||
|
target_compile_options(${TARGET} PRIVATE ${ASAN_COMPILE_FLAGS})
|
||||||
|
target_link_libraries(${TARGET} PRIVATE ${ASAN_LINK_FLAGS})
|
||||||
|
endif()
|
||||||
endforeach()
|
endforeach()
|
||||||
|
|
||||||
# Install libraries
|
|
||||||
install(TARGETS ${PROJECT_NAME}_shared ${PROJECT_NAME}_static DESTINATION lib)
|
install(TARGETS ${PROJECT_NAME}_shared ${PROJECT_NAME}_static DESTINATION lib)
|
||||||
install(DIRECTORY ${INCLUDE_DIR}/ DESTINATION include)
|
install(DIRECTORY ${INCLUDE_DIR}/ DESTINATION include)
|
||||||
|
|
||||||
# Build example programs
|
|
||||||
if(DCFG_BUILD_PROGRAMS)
|
if(DCFG_BUILD_PROGRAMS)
|
||||||
set(PROGRAMS_DIR ${CMAKE_CURRENT_SOURCE_DIR}/programs)
|
set(PROGRAMS_DIR ${CMAKE_CURRENT_SOURCE_DIR}/programs)
|
||||||
file(GLOB PROGRAM_SOURCES "${PROGRAMS_DIR}/*.c")
|
file(GLOB PROGRAM_SOURCES "${PROGRAMS_DIR}/*.c")
|
||||||
@@ -61,14 +76,22 @@ if(DCFG_BUILD_PROGRAMS)
|
|||||||
add_executable(${PROG_NAME} ${PROG_SRC})
|
add_executable(${PROG_NAME} ${PROG_SRC})
|
||||||
target_include_directories(${PROG_NAME} PRIVATE ${INCLUDE_DIR})
|
target_include_directories(${PROG_NAME} PRIVATE ${INCLUDE_DIR})
|
||||||
target_link_libraries(${PROG_NAME} PRIVATE ${PROJECT_NAME}_shared)
|
target_link_libraries(${PROG_NAME} PRIVATE ${PROJECT_NAME}_shared)
|
||||||
|
|
||||||
if(DCFG_PTHREAD_SUPPORT)
|
if(DCFG_PTHREAD_SUPPORT)
|
||||||
target_link_libraries(${PROG_NAME} PRIVATE Threads::Threads)
|
target_link_libraries(${PROG_NAME} PRIVATE Threads::Threads)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(MSVC)
|
if(MSVC)
|
||||||
target_compile_options(${PROG_NAME} PRIVATE /W4 /permissive-)
|
target_compile_options(${PROG_NAME} PRIVATE /W4 /permissive-)
|
||||||
else()
|
else()
|
||||||
target_compile_options(${PROG_NAME} PRIVATE -Wall -Wextra -pedantic -Werror -Wno-newline-eof -Wno-language-extension-token)
|
target_compile_options(${PROG_NAME} PRIVATE -Wall -Wextra -pedantic -Werror -Wno-newline-eof -Wno-language-extension-token)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(DCFG_ASAN)
|
||||||
|
target_compile_options(${PROG_NAME} PRIVATE ${ASAN_COMPILE_FLAGS})
|
||||||
|
target_link_libraries(${PROG_NAME} PRIVATE ${ASAN_LINK_FLAGS})
|
||||||
|
endif()
|
||||||
|
|
||||||
install(TARGETS ${PROG_NAME} DESTINATION bin)
|
install(TARGETS ${PROG_NAME} DESTINATION bin)
|
||||||
endforeach()
|
endforeach()
|
||||||
endif()
|
endif()
|
||||||
|
@@ -75,6 +75,8 @@ typedef enum dcfg_ValueKind {
|
|||||||
dcfg_ValueType_FunctionCall,
|
dcfg_ValueType_FunctionCall,
|
||||||
} dcfg_ValueType;
|
} dcfg_ValueType;
|
||||||
|
|
||||||
|
typedef dcfg_Value *(*dcfg_BuiltIn)(dcfg_Value **argv, size_t argc);
|
||||||
|
|
||||||
typedef uint64_t dcfg_Version;
|
typedef uint64_t dcfg_Version;
|
||||||
#define DCFG_GET_MAJOR(v) (((v) >> 48) & 0xFFFF)
|
#define DCFG_GET_MAJOR(v) (((v) >> 48) & 0xFFFF)
|
||||||
#define DCFG_GET_MINOR(v) (((v) >> 32) & 0xFFFF)
|
#define DCFG_GET_MINOR(v) (((v) >> 32) & 0xFFFF)
|
||||||
@@ -140,6 +142,10 @@ bool dcfg_call_function(dcfg_Value *function, dcfg_Value **args,
|
|||||||
size_t arg_count, dcfg_Value **out_value);
|
size_t arg_count, dcfg_Value **out_value);
|
||||||
// Allocates new values
|
// Allocates new values
|
||||||
bool dcfg_Value_evaluate(dcfg_Value *value, dcfg_Value **out_value);
|
bool dcfg_Value_evaluate(dcfg_Value *value, dcfg_Value **out_value);
|
||||||
|
// Allocates new values
|
||||||
|
bool dcfg_Value_evaluate_toplevel(dcfg_Value *top, dcfg_Value **out_value,
|
||||||
|
dcfg_StringView *function_names, dcfg_BuiltIn *functions,
|
||||||
|
size_t function_count);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
@@ -1,9 +1,11 @@
|
|||||||
#include <dcfg.h>
|
#include <dcfg.h>
|
||||||
|
|
||||||
#include <alloca.h>
|
#include <alloca.h>
|
||||||
|
#include <getopt.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
void walk_value(dcfg_Value *value, bool evaluate, int indent, bool first);
|
void walk_value(dcfg_Value *value, bool evaluate, int indent, bool first);
|
||||||
#define WALK(v, e, i) walk_value((v), (e), (i), true)
|
#define WALK(v, e, i) walk_value((v), (e), (i), true)
|
||||||
@@ -16,10 +18,24 @@ static void print_indent(int indent)
|
|||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
if (argc < 2) {
|
bool evaluate = false;
|
||||||
printf("Usage: %s <dcfg file>\n", argv[0]);
|
int opt;
|
||||||
|
while ((opt = getopt(argc, argv, "e")) != -1) {
|
||||||
|
switch (opt) {
|
||||||
|
case 'e':
|
||||||
|
evaluate = true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "Usage: %s [-e] <dcfg file>\n", argv[0]);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if (optind >= argc) {
|
||||||
|
fprintf(stderr, "Usage: %s [-e] <dcfg file>\n", argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
char const *path = argv[optind];
|
||||||
|
|
||||||
dcfg_InstanceCreateInfo ci = { 0 };
|
dcfg_InstanceCreateInfo ci = { 0 };
|
||||||
dcfg_Instance *instance = dcfg_make_instance(&ci);
|
dcfg_Instance *instance = dcfg_make_instance(&ci);
|
||||||
@@ -29,7 +45,7 @@ int main(int argc, char *argv[])
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
dcfg_Value *value = dcfg_parse(instance, dcfg_SV(argv[1]));
|
dcfg_Value *value = dcfg_parse(instance, dcfg_SV(path));
|
||||||
if (!value) {
|
if (!value) {
|
||||||
printf("Failed to parse DCFG file. Error: %s\n",
|
printf("Failed to parse DCFG file. Error: %s\n",
|
||||||
dcfg_last_error(instance));
|
dcfg_last_error(instance));
|
||||||
@@ -37,7 +53,7 @@ int main(int argc, char *argv[])
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
WALK(value, false, 0);
|
WALK(value, evaluate, 0);
|
||||||
|
|
||||||
dcfg_destroy(value);
|
dcfg_destroy(value);
|
||||||
dcfg_destroy_instance(instance);
|
dcfg_destroy_instance(instance);
|
||||||
|
143
programs/dcfgq.c
Normal file
143
programs/dcfgq.c
Normal file
@@ -0,0 +1,143 @@
|
|||||||
|
#include <dcfg.h>
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
T_FIELD,
|
||||||
|
T_INDEX,
|
||||||
|
} TokenType;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
TokenType type;
|
||||||
|
union {
|
||||||
|
dcfg_StringView field;
|
||||||
|
size_t index;
|
||||||
|
} v;
|
||||||
|
} Token;
|
||||||
|
|
||||||
|
#define MAX_TOKENS 256
|
||||||
|
|
||||||
|
static size_t tokenize(char const *query, Token *out)
|
||||||
|
{
|
||||||
|
size_t count = 0;
|
||||||
|
size_t i = 0;
|
||||||
|
if (query[i] == '.')
|
||||||
|
i++;
|
||||||
|
while (query[i] && count < MAX_TOKENS) {
|
||||||
|
if (query[i] == '.') {
|
||||||
|
i++;
|
||||||
|
size_t start = i;
|
||||||
|
while (query[i] && query[i] != '.' && query[i] != '[')
|
||||||
|
i++;
|
||||||
|
out[count].type = T_FIELD;
|
||||||
|
out[count].v.field.data = query + start;
|
||||||
|
out[count].v.field.size = i - start;
|
||||||
|
count++;
|
||||||
|
} else if (query[i] == '[') {
|
||||||
|
i++;
|
||||||
|
char *end;
|
||||||
|
size_t idx = strtoul(query + i, &end, 10);
|
||||||
|
if (*end != ']') {
|
||||||
|
fprintf(stderr, "invalid index\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
i = (size_t)(end - query) + 1;
|
||||||
|
out[count].type = T_INDEX;
|
||||||
|
out[count].v.index = idx;
|
||||||
|
count++;
|
||||||
|
} else {
|
||||||
|
size_t start = i;
|
||||||
|
while (query[i] && query[i] != '.' && query[i] != '[')
|
||||||
|
i++;
|
||||||
|
out[count].type = T_FIELD;
|
||||||
|
out[count].v.field.data = query + start;
|
||||||
|
out[count].v.field.size = i - start;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void print_value(dcfg_Value *v)
|
||||||
|
{
|
||||||
|
dcfg_StringView sv;
|
||||||
|
if (dcfg_serialize_value(v, &sv)) {
|
||||||
|
fwrite(sv.data, 1, sv.size, stdout);
|
||||||
|
free((void *)sv.data);
|
||||||
|
putchar('\n');
|
||||||
|
} else {
|
||||||
|
puts("null");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
if (argc < 3) {
|
||||||
|
fprintf(stderr, "usage: %s <query> <file>\n", argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
char const *query = argv[1];
|
||||||
|
char const *file = argv[2];
|
||||||
|
|
||||||
|
dcfg_Instance *inst = dcfg_make_instance(&(dcfg_InstanceCreateInfo) { 0 });
|
||||||
|
if (!inst) {
|
||||||
|
fprintf(stderr, "failed to create instance\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
dcfg_Value *root = dcfg_parse(inst, dcfg_SV(file));
|
||||||
|
if (!root) {
|
||||||
|
fprintf(stderr, "parse error: %s\n", dcfg_last_error(inst));
|
||||||
|
dcfg_destroy_instance(inst);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Token toks[MAX_TOKENS];
|
||||||
|
size_t n = tokenize(query, toks);
|
||||||
|
|
||||||
|
dcfg_Value *evaled;
|
||||||
|
if (!dcfg_Value_evaluate_toplevel(root, &evaled, NULL, NULL, 0)) {
|
||||||
|
fprintf(stderr, "evaluation error: %s\n", dcfg_last_error(inst));
|
||||||
|
dcfg_destroy(root);
|
||||||
|
dcfg_destroy_instance(inst);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
dcfg_Value *cur = evaled;
|
||||||
|
for (size_t i = 0; i < n; i++) {
|
||||||
|
Token *t = &toks[i];
|
||||||
|
dcfg_Value *next = NULL;
|
||||||
|
|
||||||
|
if (t->type == T_FIELD) {
|
||||||
|
if (!dcfg_Value_get_object_field_ex(cur, t->v.field, &next, true)) {
|
||||||
|
fprintf(stderr, "no such field\n");
|
||||||
|
dcfg_destroy(evaled);
|
||||||
|
dcfg_destroy(root);
|
||||||
|
dcfg_destroy_instance(inst);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!dcfg_Value_get_array_item_ex(cur, t->v.index, &next, true)) {
|
||||||
|
fprintf(stderr, "index out of bounds\n");
|
||||||
|
dcfg_destroy(evaled);
|
||||||
|
dcfg_destroy(root);
|
||||||
|
dcfg_destroy_instance(inst);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cur != evaled)
|
||||||
|
dcfg_destroy(cur);
|
||||||
|
|
||||||
|
cur = next;
|
||||||
|
}
|
||||||
|
print_value(cur);
|
||||||
|
if (cur != evaled)
|
||||||
|
dcfg_destroy(cur);
|
||||||
|
|
||||||
|
dcfg_destroy(evaled);
|
||||||
|
dcfg_destroy(root);
|
||||||
|
dcfg_destroy_instance(inst);
|
||||||
|
return 0;
|
||||||
|
}
|
419
src/dcfg.c
419
src/dcfg.c
@@ -21,6 +21,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <dcfg.h>
|
#include <dcfg.h>
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#include "meta.h"
|
#include "meta.h"
|
||||||
@@ -33,7 +35,7 @@
|
|||||||
// FIXME: Fix this stupid shit!
|
// FIXME: Fix this stupid shit!
|
||||||
# error "realpath() is dumb and stupid on sun. sorry not sorry."
|
# error "realpath() is dumb and stupid on sun. sorry not sorry."
|
||||||
# endif
|
# endif
|
||||||
# define _XOPEN_SOURCE 200809L
|
# define _POSIX_C_SOURCE 200809L
|
||||||
#else
|
#else
|
||||||
# ifdef _POSIX_C_SOURCE
|
# ifdef _POSIX_C_SOURCE
|
||||||
# undef _POSIX_C_SOURCE
|
# undef _POSIX_C_SOURCE
|
||||||
@@ -41,6 +43,33 @@
|
|||||||
# define _POSIX_C_SOURCE 0L
|
# define _POSIX_C_SOURCE 0L
|
||||||
#endif
|
#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 <assert.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
@@ -48,22 +77,6 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.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)
|
int64_t dcfg_strtoll(const char *s, char **end, int base)
|
||||||
{
|
{
|
||||||
char const *p = s;
|
char const *p = s;
|
||||||
@@ -258,6 +271,7 @@ typedef struct {
|
|||||||
} ValueArray;
|
} ValueArray;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
struct Environment *closure;
|
||||||
StringView *argv;
|
StringView *argv;
|
||||||
Value *body;
|
Value *body;
|
||||||
} ValueFunctionF;
|
} ValueFunctionF;
|
||||||
@@ -265,7 +279,7 @@ typedef struct {
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
bool is_builtin;
|
bool is_builtin;
|
||||||
union {
|
union {
|
||||||
Value *(*bi)(Value **argv, size_t argc);
|
dcfg_BuiltIn bi;
|
||||||
ValueFunctionF f;
|
ValueFunctionF f;
|
||||||
} v;
|
} v;
|
||||||
} ValueFunction;
|
} ValueFunction;
|
||||||
@@ -276,16 +290,13 @@ typedef struct {
|
|||||||
} ValueFunctionCall;
|
} ValueFunctionCall;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
StringView **accessv;
|
StringView *accessv;
|
||||||
} ValueMemberAccess;
|
} ValueMemberAccess;
|
||||||
|
|
||||||
struct dcfg_Value {
|
struct dcfg_Value {
|
||||||
Instance *instance;
|
Instance *instance;
|
||||||
dcfg_ValueType type;
|
dcfg_ValueType type;
|
||||||
SourceLocation location;
|
SourceLocation location;
|
||||||
int i_sourcev_idx;
|
|
||||||
int i_source_pathv_idx;
|
|
||||||
int i_environment_idx;
|
|
||||||
|
|
||||||
union {
|
union {
|
||||||
int64_t i;
|
int64_t i;
|
||||||
@@ -304,10 +315,10 @@ struct dcfg_Value {
|
|||||||
typedef struct Environment {
|
typedef struct Environment {
|
||||||
struct Environment *parent;
|
struct Environment *parent;
|
||||||
StringView *argv;
|
StringView *argv;
|
||||||
Value *argvv;
|
Value **argvv;
|
||||||
} Environment;
|
} 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->argv = vector_create();
|
||||||
out_env->argvv = vector_create();
|
out_env->argvv = vector_create();
|
||||||
@@ -315,13 +326,35 @@ bool environment_create(Environment *out_env, Environment *parent)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void environment_destroy(Environment *env)
|
static bool environment_lookup(Environment *e, StringView name, Value **out)
|
||||||
{
|
{
|
||||||
vector_free(&env->argv);
|
for (; e; e = e->parent) {
|
||||||
for (size_t i = 0; i < vector_size(env->argvv); i++) {
|
for (size_t i = 0; i < vector_size(e->argv); i++) {
|
||||||
dcfg_destroy(&env->argvv[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 {
|
struct dcfg_Instance {
|
||||||
@@ -369,7 +402,11 @@ dcfg_Instance *dcfg_make_instance(dcfg_InstanceCreateInfo const *create_info)
|
|||||||
if (!instance) {
|
if (!instance) {
|
||||||
return NULL;
|
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->alloc = create_info->alloc;
|
||||||
instance->free = create_info->free;
|
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);
|
for (size_t i = 0; i < vector_size(instance->environment_referencesv);
|
||||||
i++) {
|
i++) {
|
||||||
if (instance->environment_referencesv[i] > 0) {
|
if (instance->environment_referencesv[i] > 0) {
|
||||||
environment_destroy(&instance->environmentv[i]);
|
// environment_destroy(&instance->environmentv[i], true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
vector_free(instance->environment_referencesv);
|
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;
|
value->v.f.v.f.body = v;
|
||||||
} else if (root->kind == ASTKind_MemberAccess) {
|
} else if (root->kind == ASTKind_MemberAccess) {
|
||||||
value->type = dcfg_ValueType_MemberAccess;
|
value->type = dcfg_ValueType_MemberAccess;
|
||||||
// FIXME: Implement
|
value->v.ma.accessv = vector_create();
|
||||||
FREE(value);
|
for (size_t i = 0; i < vector_size(root->v.m.accessv); i++)
|
||||||
return NULL;
|
vector_add(&value->v.ma.accessv, StringView, root->v.m.accessv[i]);
|
||||||
} else if (root->kind == ASTKind_FunctionCall) {
|
} else if (root->kind == ASTKind_FunctionCall) {
|
||||||
value->type = dcfg_ValueType_FunctionCall;
|
value->type = dcfg_ValueType_FunctionCall;
|
||||||
Value *function = ast_to_value(instance, root->v.fc.function);
|
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';
|
instance->last_error[0] = '\0';
|
||||||
|
|
||||||
vector_add(&instance->sourcev, StringView, str);
|
vector_add(&instance->sourcev, StringView, str);
|
||||||
v->i_sourcev_idx = vector_size(instance->sourcev) - 1;
|
|
||||||
|
|
||||||
vector_add(&instance->source_pathv, StringView, abs_sv);
|
vector_add(&instance->source_pathv, StringView, abs_sv);
|
||||||
v->i_source_pathv_idx = vector_size(instance->source_pathv) - 1;
|
|
||||||
|
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
@@ -1523,6 +1557,10 @@ void dcfg_destroy(dcfg_Value *value)
|
|||||||
vector_free(value->v.c.argv);
|
vector_free(value->v.c.argv);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case dcfg_ValueType_MemberAccess:
|
||||||
|
vector_free(value->v.ma.accessv);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1530,6 +1568,142 @@ void dcfg_destroy(dcfg_Value *value)
|
|||||||
value->instance->free(value); // https://youtu.be/RgFaK6ZQifE
|
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)
|
dcfg_ValueType dcfg_Value_type_ex(dcfg_Value *value, bool evaluate)
|
||||||
{
|
{
|
||||||
if (!value)
|
if (!value)
|
||||||
@@ -1662,22 +1836,22 @@ bool dcfg_Value_get_array_size(dcfg_Value *value, size_t *out_size)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool dcfg_call_function(dcfg_Value *function, dcfg_Value **args,
|
static bool eval_member(ValueMemberAccess *ma, Environment *env, Value **out)
|
||||||
size_t arg_count, dcfg_Value **out_value)
|
|
||||||
{
|
{
|
||||||
if (function->v.f.is_builtin) {
|
Value *root;
|
||||||
*out_value = function->v.f.v.bi(args, arg_count);
|
if (!environment_lookup(env, ma->accessv[0], &root))
|
||||||
if (!*out_value) {
|
return false;
|
||||||
return false;
|
|
||||||
}
|
for (size_t i = 1; i < vector_size(ma->accessv); ++i) {
|
||||||
} else {
|
if (!dcfg_Value_get_object_field_ex(root, ma->accessv[i], &root, true))
|
||||||
// FIXME: Implement
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
*out = root;
|
||||||
return true;
|
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(value);
|
||||||
assert(out_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';
|
value->instance->last_error[0] = '\0';
|
||||||
*out_value = value->instance->alloc(sizeof(**out_value));
|
*out_value = value->instance->alloc(sizeof(**out_value));
|
||||||
Value *v = *out_value;
|
Value *v = *out_value;
|
||||||
|
(*out_value)->instance = value->instance;
|
||||||
|
|
||||||
if (value->type == dcfg_ValueType_Nil) {
|
if (value->type == dcfg_ValueType_Nil) {
|
||||||
v->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++) {
|
for (size_t i = 0; i < vector_size(value->v.o.entryv); i++) {
|
||||||
ValueObjectEntry *e = &value->v.o.entryv[i];
|
ValueObjectEntry *e = &value->v.o.entryv[i];
|
||||||
Value *new_v;
|
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) {
|
if (!res) {
|
||||||
ret = false;
|
ret = false;
|
||||||
break;
|
break;
|
||||||
@@ -1718,6 +1893,7 @@ bool dcfg_Value_evaluate(dcfg_Value *value, dcfg_Value **out_value)
|
|||||||
ValueObjectEntry ne = {
|
ValueObjectEntry ne = {
|
||||||
.k = e->k,
|
.k = e->k,
|
||||||
.v = new_v,
|
.v = new_v,
|
||||||
|
.key_allocated = true,
|
||||||
};
|
};
|
||||||
ne.k.data = value->instance->alloc(ne.k.size + 1);
|
ne.k.data = value->instance->alloc(ne.k.size + 1);
|
||||||
memcpy((void *)ne.k.data, e->k.data, ne.k.size);
|
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();
|
v->v.a.valuev = vector_create();
|
||||||
for (size_t i = 0; i < vector_size(value->v.a.valuev); i++) {
|
for (size_t i = 0; i < vector_size(value->v.a.valuev); i++) {
|
||||||
Value *val = NULL;
|
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) {
|
if (!res) {
|
||||||
ret = false;
|
ret = false;
|
||||||
}
|
}
|
||||||
@@ -1743,11 +1920,23 @@ bool dcfg_Value_evaluate(dcfg_Value *value, dcfg_Value **out_value)
|
|||||||
ret = false;
|
ret = false;
|
||||||
}
|
}
|
||||||
} else if (value->type == dcfg_ValueType_MemberAccess) {
|
} else if (value->type == dcfg_ValueType_MemberAccess) {
|
||||||
// FIXME: Implement
|
if (!frame) {
|
||||||
ret = false;
|
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) {
|
} else if (value->type == dcfg_ValueType_FunctionCall) {
|
||||||
Value *function;
|
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) {
|
if (!res || function->type != dcfg_ValueType_Function) {
|
||||||
ret = false;
|
ret = false;
|
||||||
} else {
|
} 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,
|
bool res = dcfg_call_function(function, value->v.c.argv,
|
||||||
vector_size(value->v.c.argv), out_value);
|
vector_size(value->v.c.argv), out_value);
|
||||||
if (!res) {
|
if (!res) {
|
||||||
dcfg_destroy(out_value_prev);
|
|
||||||
ret = false;
|
ret = false;
|
||||||
|
} else {
|
||||||
|
dcfg_destroy(out_value_prev);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -1768,6 +1958,131 @@ bool dcfg_Value_evaluate(dcfg_Value *value, dcfg_Value **out_value)
|
|||||||
return ret;
|
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
|
// Libraries
|
||||||
#include "vendor/utf8proc.c"
|
#include "vendor/utf8proc.c"
|
||||||
#include "vendor/vec.c"
|
#include "vendor/vec.c"
|
||||||
|
Reference in New Issue
Block a user