.
This commit is contained in:
175
CMakeLists.txt
Normal file
175
CMakeLists.txt
Normal file
@@ -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
|
||||
"$<$<CONFIG:Debug>:-O0>"
|
||||
"$<$<CONFIG:Debug>:-g3>"
|
||||
"$<$<CONFIG:Debug>:-fno-omit-frame-pointer>"
|
||||
"$<$<CONFIG:Debug>:-fsanitize=address>"
|
||||
"$<$<CONFIG:Debug>:-fsanitize=undefined>"
|
||||
)
|
||||
target_link_options(project_options INTERFACE
|
||||
"$<$<CONFIG:Debug>:-fsanitize=address>"
|
||||
"$<$<CONFIG:Debug>:-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
|
||||
"$<$<CONFIG:Debug>:-fsanitize=leak>"
|
||||
)
|
||||
target_link_options(project_options INTERFACE
|
||||
"$<$<CONFIG:Debug>:-fsanitize=leak>"
|
||||
)
|
||||
endif()
|
||||
|
||||
target_compile_definitions(project_options INTERFACE
|
||||
"$<$<CONFIG:Debug>:DEBUG_BUILD=1>"
|
||||
)
|
||||
|
||||
# Release-only flags
|
||||
target_compile_options(project_options INTERFACE
|
||||
"$<$<CONFIG:Release>:-O3>"
|
||||
"$<$<CONFIG:Release>:-DNDEBUG>"
|
||||
)
|
||||
target_link_options(project_options INTERFACE
|
||||
"$<$<CONFIG:Release>:-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
|
||||
"$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/include>"
|
||||
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>"
|
||||
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
|
||||
)
|
||||
14
Makefile
14
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)
|
||||
27
lib/heap.c
27
lib/heap.c
@@ -1,13 +1,10 @@
|
||||
#include "stack.c"
|
||||
#include "priv.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#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 <stdio.h>
|
||||
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
|
||||
|
||||
75
lib/priv.h
Normal file
75
lib/priv.h
Normal file
@@ -0,0 +1,75 @@
|
||||
#ifndef TYCHE_PRIV_H
|
||||
#define TYCHE_PRIV_H
|
||||
|
||||
#include "tyche.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
//
|
||||
// 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
|
||||
38
lib/stack.c
38
lib/stack.c
@@ -1,20 +1,21 @@
|
||||
#include "value.c"
|
||||
#include "priv.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
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;
|
||||
}
|
||||
30
lib/value.c
30
lib/value.c
@@ -1,25 +1,15 @@
|
||||
#include "tyche.h"
|
||||
#include "priv.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
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);
|
||||
}
|
||||
148
test/tests.c
148
test/tests.c
@@ -1,4 +1,4 @@
|
||||
#include "../lib/vm.c"
|
||||
#include "../lib/priv.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user