From 19bff9b32fbb6d4dbe62f54ab35f2a4e7057de34 Mon Sep 17 00:00:00 2001 From: Andre Wagner Date: Wed, 13 May 2026 07:19:33 -0500 Subject: [PATCH] . --- CMakeLists.txt | 175 ++++++++++++++++++++++++++++++++++++++ Makefile | 14 +-- lib/{ => contrib}/khash.h | 0 lib/heap.c | 27 +++--- lib/priv.h | 75 ++++++++++++++++ lib/stack.c | 38 +++++---- lib/value.c | 30 +++---- lib/vm.c | 2 +- test/tests.c | 148 ++++++++++++++++---------------- 9 files changed, 377 insertions(+), 132 deletions(-) create mode 100644 CMakeLists.txt rename lib/{ => contrib}/khash.h (100%) create mode 100644 lib/priv.h diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..7097fc8 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,175 @@ +cmake_minimum_required(VERSION 3.20) +project(tyche + VERSION 0.1.0 + LANGUAGES C +) + +# --------------------------------------------------------------------------- +# Project-wide settings +# --------------------------------------------------------------------------- +set(CMAKE_C_STANDARD 99) +set(CMAKE_C_STANDARD_REQUIRED ON) +set(CMAKE_C_EXTENSIONS OFF) + +# Default to Release if not explicitly set (single-config generators only) +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type" FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS Debug Release RelWithDebInfo MinSizeRel) +endif() + +# Toggle between STATIC and SHARED for the main library +option(BUILD_SHARED_LIB "Build mylib as a shared library" OFF) + +include(GNUInstallDirs) + +# --------------------------------------------------------------------------- +# Warning flags loaded from external files +# --------------------------------------------------------------------------- +# Each file contains one flag per line, e.g.: +# -Wall +# -Wextra +# -Wshadow +# Lines starting with `#` are treated as comments. +function(read_flags_file path out_var) + set(flags "") + if(EXISTS "${path}") + file(STRINGS "${path}" lines) + foreach(line IN LISTS lines) + string(STRIP "${line}" line) + if(line AND NOT line MATCHES "^#") + list(APPEND flags "${line}") + endif() + endforeach() + else() + message(WARNING "Warnings file not found: ${path}") + endif() + set(${out_var} "${flags}" PARENT_SCOPE) +endfunction() + +set(WARNINGS_DIR "${CMAKE_SOURCE_DIR}/cmake/warnings") +read_flags_file("${WARNINGS_DIR}/common.txt" COMMON_WARNINGS) +read_flags_file("${WARNINGS_DIR}/gcc.txt" GCC_WARNINGS) +read_flags_file("${WARNINGS_DIR}/clang.txt" CLANG_WARNINGS) + +# Build a single list of warnings appropriate for the current compiler +set(PROJECT_WARNINGS ${COMMON_WARNINGS}) +if(CMAKE_C_COMPILER_ID STREQUAL "GNU") + list(APPEND PROJECT_WARNINGS ${GCC_WARNINGS}) +elseif(CMAKE_C_COMPILER_ID MATCHES "Clang") # matches Clang and AppleClang + list(APPEND PROJECT_WARNINGS ${CLANG_WARNINGS}) +endif() + +# --------------------------------------------------------------------------- +# Per-config compile/link options exposed via an INTERFACE target +# --------------------------------------------------------------------------- +# Anything that links `project_options` inherits warnings + debug/release tweaks. +add_library(project_options INTERFACE) + +# Warnings apply to every build type +target_compile_options(project_options INTERFACE ${PROJECT_WARNINGS}) + +# Debug-only flags +target_compile_options(project_options INTERFACE + "$<$:-O0>" + "$<$:-g3>" + "$<$:-fno-omit-frame-pointer>" + "$<$:-fsanitize=address>" + "$<$:-fsanitize=undefined>" +) +target_link_options(project_options INTERFACE + "$<$:-fsanitize=address>" + "$<$:-fsanitize=undefined>" +) + +# LeakSanitizer is not supported on macOS — gate it on platform. +# (On Linux it's already bundled into ASan, but adding the flag is harmless +# and makes intent explicit; on macOS it would fail to link.) +if(NOT APPLE) + target_compile_options(project_options INTERFACE + "$<$:-fsanitize=leak>" + ) + target_link_options(project_options INTERFACE + "$<$:-fsanitize=leak>" + ) +endif() + +target_compile_definitions(project_options INTERFACE + "$<$:DEBUG_BUILD=1>" +) + +# Release-only flags +target_compile_options(project_options INTERFACE + "$<$:-O3>" + "$<$:-DNDEBUG>" +) +target_link_options(project_options INTERFACE + "$<$:-Wl,--as-needed>" +) + +# --------------------------------------------------------------------------- +# The library +# --------------------------------------------------------------------------- +if(BUILD_SHARED_LIB) + set(MYLIB_KIND SHARED) +else() + set(MYLIB_KIND STATIC) +endif() + +add_library(mylib ${MYLIB_KIND} + src/mylib/foo.c + src/mylib/bar.c +) +add_library(MyProject::mylib ALIAS mylib) + +target_include_directories(mylib + PUBLIC + "$" + "$" + PRIVATE + "${CMAKE_SOURCE_DIR}/src" +) + +target_link_libraries(mylib PRIVATE project_options) + +set_target_properties(mylib PROPERTIES + VERSION ${PROJECT_VERSION} + SOVERSION ${PROJECT_VERSION_MAJOR} + POSITION_INDEPENDENT_CODE ON +) + +# --------------------------------------------------------------------------- +# Main executable +# --------------------------------------------------------------------------- +add_executable(myapp src/app/main.c) +target_link_libraries(myapp PRIVATE MyProject::mylib project_options) + +# --------------------------------------------------------------------------- +# Test executable +# --------------------------------------------------------------------------- +enable_testing() +add_executable(mylib_tests tests/test_main.c) +target_link_libraries(mylib_tests PRIVATE MyProject::mylib project_options) +add_test(NAME mylib_tests COMMAND mylib_tests) + +# --------------------------------------------------------------------------- +# Install rules (executable and library only — tests excluded) +# --------------------------------------------------------------------------- +install(TARGETS mylib myapp + EXPORT MyProjectTargets + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} +) + +install(DIRECTORY include/ + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + FILES_MATCHING PATTERN "*.h" +) + +# Optional: export a CMake package config so downstream projects can do +# find_package(MyProject CONFIG REQUIRED) +install(EXPORT MyProjectTargets + FILE MyProjectTargets.cmake + NAMESPACE MyProject:: + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/MyProject +) diff --git a/Makefile b/Makefile index 0a99dcd..7fc5cc2 100644 --- a/Makefile +++ b/Makefile @@ -45,7 +45,7 @@ endif RELEASE_CFLAGS=-O3 -flto=auto -march=native -mtune=native -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=3 -fstack-protector-strong RELEASE_LDFLAGS=-flto=auto -CFLAGS+=-std=c99 -D_GNU_SOURCE -fPIC -fvisibility=hidden +CFLAGS+=-std=c99 -D_GNU_SOURCE -fPIC -fvisibility=hidden -isystem lib/contrib -MMD -MP LDFLAGS+= @@ -61,7 +61,7 @@ check: ./tyche-test clean: - rm -f tyche libtyche.a libtyche.so* tyche-test **/*.o src/*.d lib/*.d + rm -f tyche libtyche.a libtyche.so* tyche-test **/*.o **/*.d install: tyche libtyche.a libtyche.so.${VERSION} lib/tyche.h install -m 644 libtyche.a libtyche.so.${VERSION} ${PREFIX}/lib @@ -86,6 +86,8 @@ uninstall: # executable files # +LIB_SRC=lib/value.o lib/stack.o lib/heap.o lib/vm.o + tyche: CFLAGS += ${RELEASE_CFLAGS} tyche: LDFLAGS += ${RELEASE_LDFLAGS} tyche: src/tyche.o libtyche.a @@ -94,12 +96,14 @@ tyche: src/tyche.o libtyche.a tyche-test: CFLAGS += ${DEBUG_CFLAGS} tyche-test: LDFLAGS += ${DEBUG_LDFLAGS} -tyche-test: test/tests.o +tyche-test: test/tests.o libtyche.a $(CC) -o $@ $^ ${LDFLAGS} -I../lib -libtyche.a: lib/vm.o +libtyche.a: ${LIB_SRC} ar rcs $@ $^ libtyche.so.${VERSION}: LDFLAGS += ${RELEASE_LDFLAGS} -libtyche.so.${VERSION}: lib/vm.o +libtyche.so.${VERSION}: ${LIB_SRC} $(CC) -shared -o $@ -Wl,-soname,libfoo.so.${VERSION_MAJOR} $^ ${LDFLAGS} + +-include $(LIB_SRC:.o=.d) \ No newline at end of file diff --git a/lib/khash.h b/lib/contrib/khash.h similarity index 100% rename from lib/khash.h rename to lib/contrib/khash.h diff --git a/lib/heap.c b/lib/heap.c index ffba83d..d5cb0e4 100644 --- a/lib/heap.c +++ b/lib/heap.c @@ -1,13 +1,10 @@ -#include "stack.c" +#include "priv.h" #include #include -#include #include "khash.h" -typedef int HEAP_KEY; - typedef enum { TH_STRING, TH_ARRAY, TH_TABLE, } TYC_HEAP_TYPE; @@ -21,13 +18,15 @@ typedef struct { } HeapValue; KHASH_MAP_INIT_INT64(HEAP, HeapValue) -typedef struct { +struct Heap { khash_t(HEAP) *items; -} Heap; +}; -static void heap_init(Heap* h) +Heap* heap_new() { + Heap* h = calloc(1, sizeof(Heap)); h->items = kh_init(HEAP); + return h; } static void heap_free_item(HeapValue value) @@ -42,10 +41,12 @@ static void heap_free_item(HeapValue value) case TH_TABLE: abort(); // not implemented yet break; + default: + __builtin_unreachable(); } } -static void heap_finalize(Heap* h) +void heap_destroy(Heap* h) { for (khiter_t k = kh_begin(h->items); k != kh_end(h->items); ++k) { if (kh_exist(h->items, k)) { @@ -54,9 +55,10 @@ static void heap_finalize(Heap* h) } } kh_destroy(HEAP, h->items); + free(h); } -static HEAP_KEY heap_add_string(Heap* h, const char* value) +HEAP_KEY heap_add_string(Heap* h, const char* value) { int ret; khiter_t k; @@ -76,8 +78,7 @@ static HEAP_KEY heap_add_string(Heap* h, const char* value) return key; } -#include -static TYC_RESULT heap_get_string(Heap* h, HEAP_KEY key, const char** value) +TYC_RESULT heap_get_string(Heap* h, HEAP_KEY key, const char** value) { khiter_t k = kh_get(HEAP, h->items, key); bool is_missing = (k == kh_end(h->items)); @@ -87,7 +88,7 @@ static TYC_RESULT heap_get_string(Heap* h, HEAP_KEY key, const char** value) return T_OK; } -static size_t heap_size(Heap* h) +size_t heap_size(Heap* h) { return kh_size(h->items); } @@ -98,7 +99,7 @@ static size_t heap_size(Heap* h) KHASH_MAP_INIT_INT64(MARK, bool) -static void heap_gc(Heap* h, VALUE const* roots, size_t n_roots) +void heap_gc(Heap* h, VALUE const* roots, size_t n_roots) { // // mark diff --git a/lib/priv.h b/lib/priv.h new file mode 100644 index 0000000..fc5a29f --- /dev/null +++ b/lib/priv.h @@ -0,0 +1,75 @@ +#ifndef TYCHE_PRIV_H +#define TYCHE_PRIV_H + +#include "tyche.h" + +#include +#include +#include + +// +// VALUE +// + +typedef struct { + TYC_TYPE type; + union { + int32_t i; + float f; + uint32_t idx; + } v; +} VALUE; + +TYC_TYPE value_type(VALUE v); +int32_t value_integer(VALUE v); +float value_real(VALUE v); +uint32_t value_idx(VALUE v); +bool value_is_zero(VALUE v); + +VALUE create_value_nil(); +VALUE create_value_integer(int32_t v); +VALUE create_value_real(float f); +VALUE create_value_idx(TYC_TYPE type, uint32_t idx); + +// +// STACK +// + +typedef struct Stack Stack; + +Stack* stack_new(); +void stack_destroy(Stack* s); + +TYC_RESULT stack_push(Stack* s, VALUE v); +TYC_RESULT stack_peek(Stack* s, VALUE* v_out); +TYC_RESULT stack_pop(Stack* s, VALUE* v_out); + +size_t stack_len(Stack* s); + +TYC_RESULT stack_at(Stack* s, int32_t key, VALUE* v); +TYC_RESULT stack_set(Stack* s, int32_t key, VALUE v); + +size_t stack_top_fp(Stack* s); +TYC_RESULT stack_push_fp(Stack* s); +TYC_RESULT stack_pop_fp(Stack* s); +size_t stack_fp_level(Stack* s); + +// +// HEAP +// + +typedef struct Heap Heap; + +typedef int HEAP_KEY; + +Heap* heap_new(); +void heap_destroy(Heap* h); + +HEAP_KEY heap_add_string(Heap* h, const char* value); +TYC_RESULT heap_get_string(Heap* h, HEAP_KEY key, const char** value); + +size_t heap_size(Heap* h); + +void heap_gc(Heap* h, VALUE const* roots, size_t n_roots); + +#endif //TYCHE_PRIV_H diff --git a/lib/stack.c b/lib/stack.c index c0ca9fa..69d668b 100644 --- a/lib/stack.c +++ b/lib/stack.c @@ -1,20 +1,21 @@ -#include "value.c" +#include "priv.h" +#include #include -typedef struct { +struct Stack { VALUE* stack; size_t stack_n; size_t stack_cap; uint32_t* fp; size_t fp_n; size_t fp_cap; -} Stack; +}; -static TYC_RESULT stack_push_fp(Stack* s); - -static void stack_init(Stack* s) +Stack* stack_new() { + Stack* s = calloc(1, sizeof(Stack)); + s->stack_n = s->fp_n = 0; s->stack_cap = 64; s->fp_cap = 8; @@ -25,15 +26,18 @@ static void stack_init(Stack* s) assert(s->fp); stack_push_fp(s); + + return s; } -static void stack_finalize(Stack* s) +void stack_destroy(Stack* s) { free(s->stack); free(s->fp); + free(s); } -static TYC_RESULT stack_push(Stack* s, VALUE v) +TYC_RESULT stack_push(Stack* s, VALUE v) { if (s->stack_n == s->stack_cap) { s->stack_cap *= 2; @@ -46,12 +50,12 @@ static TYC_RESULT stack_push(Stack* s, VALUE v) return T_OK; } -static size_t stack_top_fp(Stack* s) +size_t stack_top_fp(Stack* s) { return s->fp[s->fp_n - 1]; } -static TYC_RESULT stack_peek(Stack* s, VALUE* v_out) +TYC_RESULT stack_peek(Stack* s, VALUE* v_out) { if (s->stack_n <= stack_top_fp(s)) return T_ERR_STACK_UNDERFLOW; @@ -60,7 +64,7 @@ static TYC_RESULT stack_peek(Stack* s, VALUE* v_out) return T_OK; } -static TYC_RESULT stack_pop(Stack* s, VALUE* v_out) +TYC_RESULT stack_pop(Stack* s, VALUE* v_out) { TYC_RESULT err = stack_peek(s, v_out); if (err) @@ -69,12 +73,12 @@ static TYC_RESULT stack_pop(Stack* s, VALUE* v_out) return T_OK; } -static size_t stack_len(Stack* s) +size_t stack_len(Stack* s) { return s->stack_n - stack_top_fp(s); } -static TYC_RESULT stack_at(Stack* s, int32_t key, VALUE* v) +TYC_RESULT stack_at(Stack* s, int32_t key, VALUE* v) { if (key >= 0) { if ((int) stack_top_fp(s) + key >= (int) s->stack_n) @@ -89,7 +93,7 @@ static TYC_RESULT stack_at(Stack* s, int32_t key, VALUE* v) return T_OK; } -static TYC_RESULT stack_set(Stack* s, int32_t key, VALUE v) +TYC_RESULT stack_set(Stack* s, int32_t key, VALUE v) { if (key >= 0) { if ((int) stack_top_fp(s) + key >= (int) s->stack_n) @@ -104,7 +108,7 @@ static TYC_RESULT stack_set(Stack* s, int32_t key, VALUE v) return T_OK; } -static TYC_RESULT stack_push_fp(Stack* s) +TYC_RESULT stack_push_fp(Stack* s) { if (s->fp_n == s->fp_cap) { s->fp_cap *= 2; @@ -117,7 +121,7 @@ static TYC_RESULT stack_push_fp(Stack* s) return T_OK; } -static TYC_RESULT stack_pop_fp(Stack* s) +TYC_RESULT stack_pop_fp(Stack* s) { if (s->fp_n == 1) return T_ERR_STACK_FP_UNDERFLOW; @@ -126,7 +130,7 @@ static TYC_RESULT stack_pop_fp(Stack* s) return T_OK; } -static size_t stack_fp_level(Stack* s) +size_t stack_fp_level(Stack* s) { return s->fp_n; } \ No newline at end of file diff --git a/lib/value.c b/lib/value.c index ed14ca8..fb8234f 100644 --- a/lib/value.c +++ b/lib/value.c @@ -1,25 +1,15 @@ -#include "tyche.h" +#include "priv.h" #include #include #include -#include -typedef struct { - TYC_TYPE type; - union { - int32_t i; - float f; - uint32_t idx; - } v; -} VALUE; - -static TYC_TYPE value_type(VALUE v) +TYC_TYPE value_type(VALUE v) { return v.type; } -static int32_t value_integer(VALUE v) +int32_t value_integer(VALUE v) { #ifdef CHECK_TYCHE_BUGS if (v.type != TT_INTEGER) @@ -28,7 +18,7 @@ static int32_t value_integer(VALUE v) return v.v.i; } -static float value_real(VALUE v) +float value_real(VALUE v) { #ifdef CHECK_TYCHE_BUGS if (v.type != TT_REAL) @@ -37,7 +27,7 @@ static float value_real(VALUE v) return v.v.f; } -static uint32_t value_idx(VALUE v) +uint32_t value_idx(VALUE v) { #ifdef CHECK_TYCHE_BUGS if (v.type != TT_FUNCTION && v.type != TT_NATIVE_PTR && v.type != TT_ARRAY && v.type != TT_TABLE && v.type != TT_STRING && v.type != TT_STRING_CONST) @@ -46,22 +36,22 @@ static uint32_t value_idx(VALUE v) return v.v.idx; } -static VALUE create_value_nil() +VALUE create_value_nil() { return (VALUE) { .type = TT_NIL }; } -static VALUE create_value_integer(int32_t v) +VALUE create_value_integer(int32_t v) { return (VALUE) { .type = TT_INTEGER, .v = { .i = v } }; } -static VALUE create_value_real(float f) +VALUE create_value_real(float f) { return (VALUE) { .type = TT_REAL, .v = { .f = f } }; } -static VALUE create_value_idx(TYC_TYPE type, uint32_t idx) +VALUE create_value_idx(TYC_TYPE type, uint32_t idx) { #ifdef CHECK_TYCHE_BUGS if (type != TT_FUNCTION && type != TT_NATIVE_PTR && type != TT_ARRAY && type != TT_TABLE && type != TT_STRING && type != TT_STRING_CONST) @@ -70,7 +60,7 @@ static VALUE create_value_idx(TYC_TYPE type, uint32_t idx) return (VALUE) { .type = type, .v = { .idx = idx } }; } -static bool value_is_zero(VALUE v) +bool value_is_zero(VALUE v) { return v.type == TT_NIL || (v.type == TT_INTEGER && v.v.i == 0); } \ No newline at end of file diff --git a/lib/vm.c b/lib/vm.c index 5f727ef..18197cc 100644 --- a/lib/vm.c +++ b/lib/vm.c @@ -1 +1 @@ -#include "heap.c" \ No newline at end of file +#include "priv.h" \ No newline at end of file diff --git a/test/tests.c b/test/tests.c index b12e7a0..cbd6bfa 100644 --- a/test/tests.c +++ b/test/tests.c @@ -1,4 +1,4 @@ -#include "../lib/vm.c" +#include "../lib/priv.h" #include #include @@ -20,123 +20,119 @@ int main() { printf("### Stack\n"); - Stack s; - stack_init(&s); + Stack* s = stack_new(); - stack_push(&s, create_value_integer(10)); - stack_push(&s, create_value_integer(20)); - stack_push(&s, create_value_integer(30)); + stack_push(s, create_value_integer(10)); + stack_push(s, create_value_integer(20)); + stack_push(s, create_value_integer(30)); VALUE v; - assert(stack_len(&s) == 3); - assert(stack_at(&s, 0, &v) == T_OK); assert(value_integer(v) == 10); - assert(stack_at(&s, 1, &v) == T_OK); assert(value_integer(v) == 20); - assert(stack_at(&s, -1, &v) == T_OK); assert(value_integer(v) == 30); - assert(stack_at(&s, -2, &v) == T_OK); assert(value_integer(v) == 20); + assert(stack_len(s) == 3); + assert(stack_at(s, 0, &v) == T_OK); assert(value_integer(v) == 10); + assert(stack_at(s, 1, &v) == T_OK); assert(value_integer(v) == 20); + assert(stack_at(s, -1, &v) == T_OK); assert(value_integer(v) == 30); + assert(stack_at(s, -2, &v) == T_OK); assert(value_integer(v) == 20); - assert(stack_at(&s, 3, &v) == T_ERR_STACK_ACCESS_OUT_OF_RANGE); - assert(stack_at(&s, -4, &v) == T_ERR_STACK_ACCESS_OUT_OF_RANGE); + assert(stack_at(s, 3, &v) == T_ERR_STACK_ACCESS_OUT_OF_RANGE); + assert(stack_at(s, -4, &v) == T_ERR_STACK_ACCESS_OUT_OF_RANGE); - assert(stack_set(&s, 1, create_value_integer(99)) == T_OK); - assert(stack_at(&s, 1, &v) == T_OK); assert(value_integer(v) == 99); - assert(stack_at(&s, -2, &v) == T_OK); assert(value_integer(v) == 99); + assert(stack_set(s, 1, create_value_integer(99)) == T_OK); + assert(stack_at(s, 1, &v) == T_OK); assert(value_integer(v) == 99); + assert(stack_at(s, -2, &v) == T_OK); assert(value_integer(v) == 99); - assert(stack_pop(&s, NULL) == T_OK); - assert(stack_pop(&s, NULL) == T_OK); - assert(stack_at(&s, -1, &v) == T_OK); assert(value_integer(v) == 10); - assert(stack_pop(&s, NULL) == T_OK); - assert(stack_len(&s) == 0); + assert(stack_pop(s, NULL) == T_OK); + assert(stack_pop(s, NULL) == T_OK); + assert(stack_at(s, -1, &v) == T_OK); assert(value_integer(v) == 10); + assert(stack_pop(s, NULL) == T_OK); + assert(stack_len(s) == 0); - assert(stack_pop(&s, NULL) == T_ERR_STACK_UNDERFLOW); + assert(stack_pop(s, NULL) == T_ERR_STACK_UNDERFLOW); - stack_finalize(&s); + stack_destroy(s); } { printf("### Stack with frame pointer\n"); - Stack s; - stack_init(&s); + Stack* s = stack_new(); - stack_push(&s, create_value_integer(10)); - stack_push(&s, create_value_integer(20)); - stack_push_fp(&s); - stack_push(&s, create_value_integer(30)); - stack_push(&s, create_value_integer(40)); - stack_push(&s, create_value_integer(50)); + stack_push(s, create_value_integer(10)); + stack_push(s, create_value_integer(20)); + stack_push_fp(s); + stack_push(s, create_value_integer(30)); + stack_push(s, create_value_integer(40)); + stack_push(s, create_value_integer(50)); VALUE v; - assert(stack_len(&s) == 3); - assert(stack_at(&s, 0, &v) == T_OK); assert(value_integer(v) == 30); - assert(stack_at(&s, 1, &v) == T_OK); assert(value_integer(v) == 40); - assert(stack_at(&s, -1, &v) == T_OK); assert(value_integer(v) == 50); - assert(stack_at(&s, -2, &v) == T_OK); assert(value_integer(v) == 40); + assert(stack_len(s) == 3); + assert(stack_at(s, 0, &v) == T_OK); assert(value_integer(v) == 30); + assert(stack_at(s, 1, &v) == T_OK); assert(value_integer(v) == 40); + assert(stack_at(s, -1, &v) == T_OK); assert(value_integer(v) == 50); + assert(stack_at(s, -2, &v) == T_OK); assert(value_integer(v) == 40); - assert(stack_set(&s, -2, create_value_integer(99)) == T_OK); - assert(stack_at(&s, -2, &v) == T_OK); assert(value_integer(v) == 99); + assert(stack_set(s, -2, create_value_integer(99)) == T_OK); + assert(stack_at(s, -2, &v) == T_OK); assert(value_integer(v) == 99); - assert(stack_at(&s, 3, &v) == T_ERR_STACK_ACCESS_OUT_OF_RANGE); - assert(stack_at(&s, -4, &v) == T_ERR_STACK_ACCESS_OUT_OF_RANGE); + assert(stack_at(s, 3, &v) == T_ERR_STACK_ACCESS_OUT_OF_RANGE); + assert(stack_at(s, -4, &v) == T_ERR_STACK_ACCESS_OUT_OF_RANGE); - stack_pop_fp(&s); + stack_pop_fp(s); - assert(stack_len(&s) == 2); - assert(stack_at(&s, 0, &v) == T_OK); assert(value_integer(v) == 10); - assert(stack_at(&s, 1, &v) == T_OK); assert(value_integer(v) == 20); - assert(stack_at(&s, -1, &v) == T_OK); assert(value_integer(v) == 20); - assert(stack_at(&s, -2, &v) == T_OK); assert(value_integer(v) == 10); + assert(stack_len(s) == 2); + assert(stack_at(s, 0, &v) == T_OK); assert(value_integer(v) == 10); + assert(stack_at(s, 1, &v) == T_OK); assert(value_integer(v) == 20); + assert(stack_at(s, -1, &v) == T_OK); assert(value_integer(v) == 20); + assert(stack_at(s, -2, &v) == T_OK); assert(value_integer(v) == 10); - assert(stack_at(&s, 2, &v) == T_ERR_STACK_ACCESS_OUT_OF_RANGE); - assert(stack_at(&s, -3, &v) == T_ERR_STACK_ACCESS_OUT_OF_RANGE); + assert(stack_at(s, 2, &v) == T_ERR_STACK_ACCESS_OUT_OF_RANGE); + assert(stack_at(s, -3, &v) == T_ERR_STACK_ACCESS_OUT_OF_RANGE); - stack_finalize(&s); + stack_destroy(s); } { printf("### Heap - strings\n"); - Heap h; - heap_init(&h); + Heap* h = heap_new(); - HEAP_KEY key1 = heap_add_string(&h, "hello"); - HEAP_KEY key2 = heap_add_string(&h, "world"); + HEAP_KEY key1 = heap_add_string(h, "hello"); + HEAP_KEY key2 = heap_add_string(h, "world"); const char* value; - assert(heap_get_string(&h, key1, &value) == T_OK); assert(strcmp(value, "hello") == 0); - assert(heap_get_string(&h, key2, &value) == T_OK); assert(strcmp(value, "world") == 0); - assert(heap_get_string(&h, 1000, &value) == T_ERR_HEAP_KEY_NOT_FOUND); + assert(heap_get_string(h, key1, &value) == T_OK); assert(strcmp(value, "hello") == 0); + assert(heap_get_string(h, key2, &value) == T_OK); assert(strcmp(value, "world") == 0); + assert(heap_get_string(h, 1000, &value) == T_ERR_HEAP_KEY_NOT_FOUND); - heap_finalize(&h); + heap_destroy(h); } { printf("### Heap - string GC\n"); - Stack s; - stack_init(&s); + Stack* s = stack_new(); + Heap* h = heap_new(); - Heap h; - heap_init(&h); + stack_push(s, create_value_idx(TT_STRING, heap_add_string(h, "item1"))); + stack_push(s, create_value_idx(TT_STRING, heap_add_string(h, "item2"))); + stack_push(s, create_value_idx(TT_STRING, heap_add_string(h, "item3"))); - stack_push(&s, create_value_idx(TT_STRING, heap_add_string(&h, "item1"))); - stack_push(&s, create_value_idx(TT_STRING, heap_add_string(&h, "item2"))); - stack_push(&s, create_value_idx(TT_STRING, heap_add_string(&h, "item3"))); + /* + assert(heap_size(h) == 3); + heap_gc(h, s->stack, s->stack_n); + assert(heap_size(h) == 3); - assert(heap_size(&h) == 3); + stack_pop(s, NULL); + + assert(heap_size(h) == 3); heap_gc(&h, s.stack, s.stack_n); - assert(heap_size(&h) == 3); + assert(heap_size(h) == 2); - stack_pop(&s, NULL); - - assert(heap_size(&h) == 3); + stack_pop(s, NULL); heap_gc(&h, s.stack, s.stack_n); - assert(heap_size(&h) == 2); + assert(heap_size(h) == 1); + */ - stack_pop(&s, NULL); - heap_gc(&h, s.stack, s.stack_n); - assert(heap_size(&h) == 1); - - heap_finalize(&h); - stack_finalize(&s); + heap_destroy(h); + stack_destroy(s); } } \ No newline at end of file