Add dump
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) Successful in 16s
CMake / ubuntu-latest - shared=OFF, pthread=OFF, posix=ON (push) Failing after 14s
CMake / ubuntu-latest - shared=ON, pthread=OFF, posix=ON (push) Successful in 17s
CMake / ubuntu-latest - shared=OFF, pthread=ON, posix=ON (push) Failing after 18s
CMake / ubuntu-latest - shared=ON, pthread=ON, posix=ON (push) Successful in 15s

Signed-off-by: Slendi <slendi@socopon.com>
This commit is contained in:
2025-07-26 23:41:34 +03:00
parent 0b5c556f84
commit e49654efb1
6 changed files with 411 additions and 24 deletions

View File

@@ -9,6 +9,7 @@ set(CMAKE_C_EXTENSIONS ON) # Would've done OFF but I need typeof (for now)
option(DCFG_BUILD_SHARED "Build DCFG as a shared library" ON)
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)
@@ -54,3 +55,24 @@ if(MSVC)
else()
target_compile_options(${PROJECT_NAME} PRIVATE -Wall -Wextra -pedantic -Werror -Wno-newline-eof -Wno-language-extension-token)
endif()
if(DCFG_BUILD_PROGRAMS)
set(PROGRAMS_DIR ${CMAKE_CURRENT_SOURCE_DIR}/programs)
file(GLOB PROGRAM_SOURCES "${PROGRAMS_DIR}/*.c")
foreach(PROG_SRC ${PROGRAM_SOURCES})
get_filename_component(PROG_NAME ${PROG_SRC} NAME_WE)
add_executable(${PROG_NAME} ${PROG_SRC})
target_include_directories(${PROG_NAME} PRIVATE ${INCLUDE_DIR})
target_link_libraries(${PROG_NAME} PRIVATE ${PROJECT_NAME})
if(DCFG_PTHREAD_SUPPORT)
target_link_libraries(${PROG_NAME} PRIVATE Threads::Threads)
endif()
if(MSVC)
target_compile_options(${PROG_NAME} PRIVATE /W4 /permissive-)
else()
target_compile_options(${PROG_NAME} PRIVATE -Wall -Wextra -pedantic -Werror -Wno-newline-eof -Wno-language-extension-token)
endif()
install(TARGETS ${PROG_NAME} DESTINATION bin)
endforeach()
endif()

View File

@@ -1,4 +1,5 @@
#!/bin/sh
set -e
BUILD_DIR="BUILD"
@@ -7,8 +8,10 @@ CFLAGS="-std=gnu99 -Wall -Wextra -pedantic -Werror -Wno-newline-eof -Wno-languag
BUILD_SHARED=1
PTHREAD_SUPPORT=1
POSIX_SUPPORT=1
BUILD_PROGRAMS=0
SRC_DIR="src"
INCLUDE_DIR="include"
PROGRAMS_DIR="programs"
OUTPUT_NAME="libdcfg"
for arg in "$@"; do
@@ -17,12 +20,13 @@ for arg in "$@"; do
--release) CFLAGS="$CFLAGS -O2" ;;
--no-pthread) PTHREAD_SUPPORT=0 ;;
--no-posix) POSIX_SUPPORT=0 ;;
--with-programs) BUILD_PROGRAMS=1 ;;
--clean) rm -rf "$BUILD_DIR" "$INSTALL_DIR"; echo "Cleaned."; exit 0 ;;
esac
done
# Setup directories
mkdir -p "$BUILD_DIR" "$INSTALL_DIR/lib" "$INSTALL_DIR/include"
mkdir -p "$BUILD_DIR" "$INSTALL_DIR/lib" "$INSTALL_DIR/include" "$INSTALL_DIR/bin"
# Compiler and linker
CC=${CC:-cc}
@@ -39,16 +43,28 @@ echo "Building DCFG..."
cd "$BUILD_DIR"
set -x
# Shared library
$CC $CFLAGS -fPIC -shared "../$SRC_DIR/dcfg.c" -I"../$INCLUDE_DIR" -o "$OUTPUT_NAME.so" $LIBS
# Static library
$CC $CFLAGS -c "../$SRC_DIR/dcfg.c" -I"../$INCLUDE_DIR"
ar rcs "$OUTPUT_NAME.a" dcfg.o
set +x
echo "Installing..."
echo "Installing library..."
cp -r "../$INCLUDE_DIR/"* "$INSTALL_DIR/include/"
cp "$OUTPUT_NAME.so" "$INSTALL_DIR/lib/"
cp "$OUTPUT_NAME.a" "$INSTALL_DIR/lib/"
# Build programs if requested
if [ "$BUILD_PROGRAMS" -eq 1 ]; then
echo "Building example programs..."
for src in "../$PROGRAMS_DIR"/*.c; do
prog=$(basename "$src" .c)
echo "Building $prog..."
$CC $CFLAGS "$src" -I"../$INCLUDE_DIR" "$OUTPUT_NAME.a" $LIBS -o "$prog"
cp "$prog" "$INSTALL_DIR/bin/"
done
fi
echo "Done. Installed to $INSTALL_DIR"

View File

@@ -4,6 +4,7 @@
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#ifdef __cplusplus
extern "C" {
@@ -17,6 +18,7 @@ typedef struct dcfg_StringView {
char const *data;
size_t size;
} dcfg_StringView;
#define dcfg_SV(cstr) ((dcfg_StringView) { .data = cstr, .size = strlen(cstr) })
typedef void *(*dcfg_AllocFn)(size_t); // This should automatically zero memory.
typedef void (*dcfg_FreeFn)(void *);
@@ -75,6 +77,8 @@ bool dcfg_Value_get_object_field_ex(dcfg_Value *value,
dcfg_StringView const key, dcfg_Value **out_value, bool const evaluate);
bool dcfg_Value_get_array_item_ex(dcfg_Value *value, size_t const index,
dcfg_Value **out_value, bool const evaluate);
bool dcfg_Value_get_function_body_ex(
dcfg_Value *value, dcfg_Value **out_value, bool evaluate);
bool dcfg_Value_get_boolean(dcfg_Value *value, bool *out_value);
bool dcfg_Value_get_integer(dcfg_Value *value, int64_t *out_value);
@@ -95,6 +99,10 @@ static inline bool dcfg_Value_get_array_item(
{
return dcfg_Value_get_array_item_ex(value, index, out_value, true);
}
bool dcfg_Value_get_function_body(dcfg_Value *value, dcfg_Value **out_value)
{
return dcfg_Value_get_function_body_ex(value, out_value, true);
}
bool dcfg_call_function(dcfg_Value *function, dcfg_Value **args,
size_t arg_count, dcfg_Value **out_value);

159
programs/dcfg_dump.c Normal file
View File

@@ -0,0 +1,159 @@
#include <dcfg.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
void walk_value(dcfg_Value *value, bool evaluate, int indent);
int main(int argc, char *argv[])
{
if (argc < 2) {
printf("Usage: %s <dcfg file>\n", argv[0]);
return 1;
}
dcfg_InstanceCreateInfo ci = { 0 };
dcfg_Instance *instance = dcfg_make_instance(&ci);
if (!instance) {
printf("Failed to create DCFG instance. Error: %s\n",
dcfg_last_error(instance));
return 1;
}
dcfg_Value *value = dcfg_parse(instance, dcfg_SV(argv[1]));
if (!value) {
printf("Failed to parse DCFG file. Error: %s\n",
dcfg_last_error(instance));
return 1;
}
walk_value(value, false, 0);
dcfg_destroy(value);
dcfg_destroy_instance(instance);
}
static void print_indent(int indent)
{
for (int i = 0; i < indent; ++i)
putchar('\t');
}
void walk_value(dcfg_Value *value, bool evaluate, int indent)
{
print_indent(indent);
dcfg_ValueType type = dcfg_Value_type_ex(value, evaluate);
switch (type) {
case dcfg_ValueType_Nil:
printf("null");
break;
case dcfg_ValueType_Boolean: {
bool b;
dcfg_Value_get_boolean(value, &b);
printf("%s", b ? "true" : "false");
} break;
case dcfg_ValueType_Integer: {
int64_t v;
dcfg_Value_get_integer(value, &v);
printf("%" PRId64, v);
} break;
case dcfg_ValueType_Real: {
double v;
dcfg_Value_get_real(value, &v);
printf("%g", v);
} break;
case dcfg_ValueType_String: {
dcfg_StringView sv;
dcfg_Value_get_string(value, &sv);
printf("\"%.*s\"", (int)sv.size, sv.data);
} break;
case dcfg_ValueType_Path: {
dcfg_StringView sv;
dcfg_Value_get_path(value, &sv);
printf("<path \"%.*s\">", (int)sv.size, sv.data);
} break;
case dcfg_ValueType_Object: {
size_t n = 0;
dcfg_Value_get_object_keys(value, 0, &n, NULL);
dcfg_StringView *keys
= n ? (dcfg_StringView *)alloca(n * sizeof(*keys)) : NULL;
dcfg_Value_get_object_keys(value, n, &n, keys);
printf("{\n");
for (size_t i = 0; i < n; ++i) {
dcfg_Value *child;
if (!dcfg_Value_get_object_field_ex(
value, keys[i], &child, evaluate))
continue;
print_indent(indent + 1);
printf("\"%.*s\": ", (int)keys[i].size, keys[i].data);
walk_value(child, evaluate, indent + 1);
if (i + 1 < n)
printf(",");
printf("\n");
}
print_indent(indent);
printf("}");
} break;
case dcfg_ValueType_Array: {
size_t sz = 0;
dcfg_Value_get_array_size(value, &sz);
printf("[\n");
for (size_t i = 0; i < sz; ++i) {
dcfg_Value *item;
if (!dcfg_Value_get_array_item_ex(value, i, &item, evaluate))
continue;
walk_value(item, evaluate, indent + 1);
if (i + 1 < sz)
printf(",");
printf("\n");
}
print_indent(indent);
printf("]");
} break;
case dcfg_ValueType_Function: {
dcfg_Value *body = NULL;
if (dcfg_Value_get_function_body_ex(value, &body, evaluate) && body) {
printf("<fn> ");
walk_value(body, evaluate, indent + 1);
} else {
printf("<builtinfn>");
}
} break;
case dcfg_ValueType_FunctionCall:
if (evaluate) {
dcfg_Value *res;
if (dcfg_Value_evaluate(value, &res))
walk_value(res, evaluate, indent);
else
printf("<errorevaluatingcall>");
} else {
printf("<functioncall>");
}
break;
default:
printf("<unknown>");
break;
}
if (indent == 0) {
putchar('\n');
}
}

2
samples/testing.dcfg Normal file
View File

@@ -0,0 +1,2 @@
fn lib = [ 123 "string" ./path 80085.3 ]

View File

@@ -343,8 +343,18 @@ static inline int32_t decode_cp(StringView src, int pos, int *len)
*len = 0;
return -1;
}
return (int32_t)utf8proc_iterate(
(uint8_t const *)src.data + pos, (int)(src.size - pos), len);
int32_t cp;
int bytes = utf8proc_iterate(
(uint8_t const *)src.data + pos, (int)(src.size - pos), &cp);
if (bytes < 0) {
*len = 0;
return -1;
}
*len = bytes;
return cp;
}
static inline bool is_space_cp(int32_t cp)
@@ -625,13 +635,18 @@ typedef struct {
AST **argv;
} ASTFunctionCall;
typedef struct {
bool is_str;
StringView s;
} ASTKey;
struct AST {
ASTKind kind;
SourceLocation location;
union {
int64_t i;
double r;
StringView s;
ASTKey s;
StringView p;
bool b;
ASTFunction f;
@@ -653,20 +668,18 @@ bool Parser_next(Parser *parser)
{
parser->cur = parser->next;
parser->next = Lexer_next(parser->lexer);
bool ret = parser->next.type != TokenType_Error;
if (!ret) {
if (parser->next.type == TokenType_Error) {
strcpy(parser->instance->last_error, "Failed to get parser token");
}
return ret;
return true;
}
bool Parser_init(Parser *out_parser, Lexer *lexer, Instance *instance)
{
memset(out_parser, 0, sizeof(*out_parser));
out_parser->lexer = lexer;
out_parser->instance = instance;
if (!Parser_next(out_parser)) {
return false;
}
out_parser->next = Lexer_next(lexer);
if (!Parser_next(out_parser)) {
return false;
}
@@ -781,7 +794,7 @@ AST *parser_parse_dot_access(Parser *parser, StringView *current)
if (vector_size(accessv) == 1) {
ast->kind = ASTKind_Key;
ast->v.s = accessv[0];
ast->v.s.s = accessv[0];
vector_free(accessv);
}
return ast;
@@ -800,13 +813,14 @@ AST *parser_parse_value(Parser *parser)
} else if (parser->cur.type == TokenType_String
|| parser->cur.type == TokenType_Identifier) {
ast->kind = ASTKind_Key;
ast->v.s = parser->cur.v.s;
ast->v.s.s = parser->cur.v.s;
ast->v.s.is_str = parser->cur.type == TokenType_String;
if (parser->next.type == TokenType_Dot) {
FREE(ast);
return parser_parse_dot_access(parser, NULL);
} else if (parser->cur.type == TokenType_Identifier) {
if (sv_eq(ast->v.s, SV("fn"))) {
if (sv_eq(ast->v.s.s, SV("fn"))) {
if (!Parser_next(parser)) {
strcpy(parser->instance->last_error,
"Failed to advance fn keyword");
@@ -837,6 +851,11 @@ AST *parser_parse_value(Parser *parser)
}
vector_add(&ast->v.f.argv, parser->cur.v.s);
if (!Parser_next(parser)) {
vector_free(ast->v.f.argv);
FREE(ast);
return NULL;
}
}
ast->v.f.body = parser_parse_value(parser);
@@ -847,12 +866,12 @@ AST *parser_parse_value(Parser *parser)
}
ast->location.range.end = ast->v.f.body->location.range.end;
return ast;
} else if (sv_eq(ast->v.s, SV("on"))
|| sv_eq(ast->v.s, SV("true"))) {
} else if (sv_eq(ast->v.s.s, SV("on"))
|| sv_eq(ast->v.s.s, SV("true"))) {
ast->kind = ASTKind_Boolean;
ast->v.b = true;
} else if (sv_eq(ast->v.s, SV("off"))
|| sv_eq(ast->v.s, SV("false"))) {
} else if (sv_eq(ast->v.s.s, SV("off"))
|| sv_eq(ast->v.s.s, SV("false"))) {
ast->kind = ASTKind_Boolean;
ast->v.b = false;
}
@@ -1000,9 +1019,14 @@ Value *ast_to_value(dcfg_Instance *instance, AST *root)
Value *value = ALLOC(sizeof(*value));
value->instance = instance;
if (root->kind == ASTKind_Key) {
// FIXME: Implement
FREE(value);
return NULL;
if (root->v.s.is_str) {
value->type = dcfg_ValueType_String;
value->v.s = root->v.s.s;
} else {
// FIXME: Implement
FREE(value);
return NULL;
}
} else if (root->kind == ASTKind_Path) {
value->type = dcfg_ValueType_Path;
value->v.p = root->v.p;
@@ -1089,6 +1113,7 @@ dcfg_Value *dcfg_parse(dcfg_Instance *instance, dcfg_StringView const file_path)
if (!abs) {
snprintf(instance->last_error, sizeof(instance->last_error) - 1,
"realpath: %s", strerror(errno));
return NULL;
}
StringView abs_sv = SV(abs);
@@ -1146,25 +1171,33 @@ dcfg_Value *dcfg_parse(dcfg_Instance *instance, dcfg_StringView const file_path)
AST *ast = Parser_parse(&parser);
if (!ast) {
if (!*instance->last_error) {
strcpy(instance->last_error, "Could not parse file");
}
FREE(abs);
FREE((void *)str.data);
fclose(fp);
return NULL;
}
instance->last_error[0] = '\0';
Value *v = ast_to_value(instance, ast);
if (!v) {
if (!*instance->last_error) {
strcpy(instance->last_error, "Could not get Value tree from AST");
}
dcfg_destroy(v);
FREE(abs);
FREE((void *)str.data);
fclose(fp);
return NULL;
}
instance->last_error[0] = '\0';
vector_add(&instance->sourcev, str);
vector_add(&instance->source_pathv, abs_sv);
v->i_sourcev_idx = vector_size(instance->sourcev) - 1;
vector_add(&instance->source_pathv, abs_sv);
v->i_source_pathv_idx = vector_size(instance->source_pathv) - 1;
return v;
@@ -1176,6 +1209,153 @@ void dcfg_destroy(dcfg_Value *value)
// FIXME: Implement
}
dcfg_ValueType dcfg_Value_type_ex(dcfg_Value *value, bool evaluate)
{
if (!value)
return dcfg_ValueType_Nil;
(void)evaluate; /* eval ignored for now */
return value->type;
}
bool dcfg_Value_get_object_field_ex(dcfg_Value *value, dcfg_StringView key,
dcfg_Value **out_value, bool evaluate)
{
if (!value || value->type != dcfg_ValueType_Object)
return false;
ValueObject *obj = &value->v.o;
for (size_t i = 0; i < vector_size(obj->entryv); ++i) {
ValueObjectEntry *entry = &obj->entryv[i];
if (sv_eq(entry->k, key)) {
*out_value = entry->v;
if (evaluate)
dcfg_Value_evaluate(*out_value, out_value);
return true;
}
}
return false;
}
bool dcfg_Value_get_array_item_ex(
dcfg_Value *value, size_t index, dcfg_Value **out_value, bool evaluate)
{
if (!value || value->type != dcfg_ValueType_Array)
return false;
ValueArray *arr = &value->v.a;
if (index >= vector_size(arr->valuev))
return false;
*out_value = arr->valuev[index];
if (evaluate)
dcfg_Value_evaluate(*out_value, out_value);
return true;
}
bool dcfg_Value_get_function_body_ex(
dcfg_Value *value, dcfg_Value **out_value, bool evaluate)
{
if (!value || value->type != dcfg_ValueType_Function
|| value->v.f.is_builtin)
return false;
if (out_value)
*out_value = value->v.f.v.f.body;
if (evaluate && out_value && *out_value)
dcfg_Value_evaluate(*out_value, out_value);
return true;
}
bool dcfg_Value_get_boolean(dcfg_Value *value, bool *out_value)
{
if (!value || value->type != dcfg_ValueType_Boolean)
return false;
if (out_value)
*out_value = value->v.b;
return true;
}
bool dcfg_Value_get_integer(dcfg_Value *value, int64_t *out_value)
{
if (!value || value->type != dcfg_ValueType_Integer)
return false;
if (out_value)
*out_value = value->v.i;
return true;
}
bool dcfg_Value_get_real(dcfg_Value *value, double *out_value)
{
if (!value || value->type != dcfg_ValueType_Real)
return false;
if (out_value)
*out_value = value->v.r;
return true;
}
bool dcfg_Value_get_string(dcfg_Value *value, dcfg_StringView *out_sv)
{
if (!value || value->type != dcfg_ValueType_String)
return false;
if (out_sv)
*out_sv = value->v.s;
return true;
}
bool dcfg_Value_get_path(dcfg_Value *value, dcfg_StringView *out_sv)
{
if (!value || value->type != dcfg_ValueType_Path)
return false;
if (out_sv)
*out_sv = value->v.p;
return true;
}
bool dcfg_Value_get_object_keys(dcfg_Value *value, size_t capacity,
size_t *out_count, dcfg_StringView *out_keys)
{
if (!value || value->type != dcfg_ValueType_Object)
return false;
ValueObject *obj = &value->v.o;
size_t count = vector_size(obj->entryv);
if (out_count)
*out_count = count;
if (out_keys) {
size_t n = capacity < count ? capacity : count;
for (size_t i = 0; i < n; ++i)
out_keys[i] = obj->entryv[i].k;
}
return true;
}
bool dcfg_Value_get_array_size(dcfg_Value *value, size_t *out_size)
{
if (!value || value->type != dcfg_ValueType_Array)
return false;
if (out_size)
*out_size = vector_size(value->v.a.valuev);
return true;
}
bool dcfg_call_function(dcfg_Value *function, dcfg_Value **args,
size_t arg_count, dcfg_Value **out_value)
{
(void)function, (void)args, (void)arg_count, (void)out_value;
// FIXME: Implement
return false;
}
bool dcfg_Value_evaluate(dcfg_Value *value, dcfg_Value **out_value)
{
(void)value, (void)out_value;
// FIXME: Implement
return false;
}
// Libraries
#include "vendor/utf8proc.c"
#include "vendor/vec.c"