Initial commit

This commit is contained in:
2025-09-03 03:20:58 -07:00
commit 1e16b4d34e
20 changed files with 455 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
/build*/
/docs/

40
CMakeLists.txt Normal file
View File

@ -0,0 +1,40 @@
cmake_minimum_required(VERSION 3.11)
set(CMAKE_C_STANDARD 11)
project(
object-lisp
VERSION 1.0
LANGUAGES C)
include(FetchContent)
FetchContent_Declare(
refcount
GIT_REPOSITORY https://git.zander.im/Zander671/refcount.git
GIT_TAG 4efdcc97ae3abbbfc3eb974a7880ff59522b379f)
FetchContent_MakeAvailable(refcount)
if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME)
include(CTest)
endif()
add_compile_options(-fsanitize=address,leak,undefined)
add_link_options(-fsanitize=address,leak,undefined)
add_library(
olisp
src/object.c
src/number.c
src/array.c
src/string.c
src/symbol.c
src/function.c
src/hashtable.c)
target_link_libraries(olisp PUBLIC refcount)
target_include_directories(olisp PUBLIC include/)
target_compile_options(olisp PRIVATE -Wall -Wpedantic)
if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME AND BUILD_TESTING)
add_subdirectory(test/)
endif()

24
include/lisp/array.h Normal file
View File

@ -0,0 +1,24 @@
#ifndef INCLUDED_ARRAY_H
#define INCLUDED_ARRAY_H
#include "lisp/object.h"
#include "lisp/util.h"
LISP_BEGIN_DECLS
DECLARE_CLASS(Array);
struct Array {
Object base;
size_t length;
void *value;
};
struct ArrayClass {
Class base;
Object *(*length)(Object *self);
Object *(*elt)(Object *self, Object *index);
Object *(*aset)(Object *self, Object *index, Object *value);
};
LISP_END_DECLS
#endif

24
include/lisp/function.h Normal file
View File

@ -0,0 +1,24 @@
#ifndef INCLUDED_FUNCTION_H
#define INCLUDED_FUNCTION_H
#include "lisp/hashtable.h"
#include "lisp/object.h"
#include "lisp/util.h"
LISP_BEGIN_DECLS
DECLARE_CLASS(Function);
struct Function {
Object base;
Object *req_args;
Object *opt_args;
Object *kw_args;
Hashtable *arg_props;
};
struct FunctionClass {
Class base;
};
LISP_END_DECLS
#endif

20
include/lisp/hashtable.h Normal file
View File

@ -0,0 +1,20 @@
#ifndef INCLUDED_HASHTABLE_H
#define INCLUDED_HASHTABLE_H
#include "lisp/object.h"
#include "lisp/util.h"
LISP_BEGIN_DECLS
DECLARE_CLASS(Hashtable);
struct Hashtable {
Object base;
HTTable *table;
};
struct HashtableClass {
Class base;
};
LISP_END_DECLS
#endif

139
include/lisp/method_macro.h Normal file
View File

@ -0,0 +1,139 @@
#ifndef INCLUDED_METHOD_MACRO_H
#define INCLUDED_METHOD_MACRO_H
#if __has_attribute(always_inline)
# define always_inline inline __attribute__((always_inline))
#else
# define always_inline inline
#endif
#if __has_attribute(unused)
# define UNUSED __attribute__((unused))
#else
# define UNUSED
#endif
// clang-format off
#define _ELEVENTH(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, ...) a11
#define _COUNT_ARGS(...) _ELEVENTH(__VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
#define _GLUE(a, b) a##b
#define _GLUE2(a, b) _GLUE(a, b)
#define _IGNORE(...)
#define _REMOVE_FIRST(a1, ...) __VA_ARGS__
#define _EVAL(...) __VA_ARGS__
// clang-format on
// This is needed because C11 doesn't allow empty __VA_ARGS__
#define _GET_1_1(a1) a1
#define _GET_1_2(a1, a2) a1
#define _GET_1_3(a1, a2, a3) a1
#define _GET_1_4(a1, a2, a3, a4) a1
#define _GET_1_5(a1, a2, a3, a4, a5) a1
#define _GET_1_6(a1, a2, a3, a4, a5, a6) a1
#define _GET_2_2(a1, a2) a2
#define _GET_2_3(a1, a2, a3) a2
#define _GET_2_4(a1, a2, a3, a4) a2
#define _GET_2_5(a1, a2, a3, a4, a5) a2
#define _GET_2_6(a1, a2, a3, a4, a5, a6) a2
#define _GET_3_3(a1, a2, a3) a3
#define _GET_3_4(a1, a2, a3, a4) a3
#define _GET_3_5(a1, a2, a3, a4, a5) a3
#define _GET_3_6(a1, a2, a3, a4, a5, a6) a3
#define _GET_4_4(a1, a2, a3, a4) a4
#define _GET_4_5(a1, a2, a3, a4, a5) a4
#define _GET_4_6(a1, a2, a3, a4, a5, a6) a4
#define _GET_5_5(a1, a2, a3, a4, a5) a5
#define _GET_5_6(a1, a2, a3, a4, a5, a6) a5
#define _GET_6_6(a1, a2, a3, a4, a5, a6) a6
#define _GET_NTH(n, args) \
_EVAL(_GLUE2(_GLUE2(_GLUE2(_GET_, n), _), _COUNT_ARGS args) args)
#define METHOD_CALLBACK_NAME(name) _##name##__as_callback
#define _CB_DECL_ARGS_1 Object *
#define _CB_DECL_ARGS_2 Object *, _CB_DECL_ARGS_1
#define _CB_DECL_ARGS_3 Object *, _CB_DECL_ARGS_2
#define _CB_DECL_ARGS_4 Object *, _CB_DECL_ARGS_3
#define _CB_DECL_ARGS_5 Object *, _CB_DECL_ARGS_4
#define _CB_DECL_ARGS_6 Object *, _CB_DECL_ARGS_5
#define _CB_DECL_ARGS_N(count) (_GLUE(_CB_DECL_ARGS_, count))
#define _CB_DECL_ARGS_FOR(...) _CB_DECL_ARGS_N(_COUNT_ARGS(__VA_ARGS__))
#define _GEN_CB_DECL(name, args) \
Object *METHOD_CALLBACK_NAME(name) \
_CB_DECL_ARGS_FOR args
#define _ARG_NAME_1(args) _IGNORE _GET_NTH(1, args)
#define _ARG_NAME_2(args) _IGNORE _GET_NTH(2, args)
#define _ARG_NAME_3(args) _IGNORE _GET_NTH(3, args)
#define _ARG_NAME_4(args) _IGNORE _GET_NTH(4, args)
#define _ARG_NAME_5(args) _IGNORE _GET_NTH(5, args)
#define _ARG_NAME_6(args) _IGNORE _GET_NTH(6, args)
#define _ARG_NAME_N(n, args) _EVAL(_GLUE(_ARG_NAME_, n)(args))
#define _VOID_ARG_N(n, args) (void *) _ARG_NAME_N(n, args)
#define _CALL_ARGS_1(args) _VOID_ARG_N(1, args)
#define _CALL_ARGS_2(args) _CALL_ARGS_1(args), _VOID_ARG_N(2, args)
#define _CALL_ARGS_3(args) _CALL_ARGS_2(args), _VOID_ARG_N(3, args)
#define _CALL_ARGS_4(args) _CALL_ARGS_3(args), _VOID_ARG_N(4, args)
#define _CALL_ARGS_5(args) _CALL_ARGS_4(args), _VOID_ARG_N(5, args)
#define _CALL_ARGS_6(args) _CALL_ARGS_5(args), _VOID_ARG_N(6, args)
#define _CALL_ARGS_N(n, args) _GLUE(_CALL_ARGS_, n)(args)
#define _GEN_REAL_CALL(name, args) \
METHOD_CALLBACK_NAME(name)(_CALL_ARGS_N(_COUNT_ARGS args, args))
#define _UNWRAP_TYPE(arg) _EVAL arg
#define _UNWRAP_ARG_N(n, args) _UNWRAP_TYPE(_GET_NTH(n, args))
#define _UNWRAP_ARGS_1(args) _UNWRAP_ARG_N(1, args)
#define _UNWRAP_ARGS_2(args) _UNWRAP_ARGS_1(args), _UNWRAP_ARG_N(2, args)
#define _UNWRAP_ARGS_3(args) _UNWRAP_ARGS_2(args), _UNWRAP_ARG_N(3, args)
#define _UNWRAP_ARGS_4(args) _UNWRAP_ARGS_3(args), _UNWRAP_ARG_N(4, args)
#define _UNWRAP_ARGS_5(args) _UNWRAP_ARGS_4(args), _UNWRAP_ARG_N(5, args)
#define _UNWRAP_ARGS_6(args) _UNWRAP_ARGS_5(args), _UNWRAP_ARG_N(6, args)
#define _UNWRAP_ARGS_N(n, args) _GLUE(_UNWRAP_ARGS_, n)(args)
#define _UNWRAP_ARGS(args) _UNWRAP_ARGS_N(_COUNT_ARGS args, args)
#define _METHOD_RAW(rtype, ret_stmt, name, args) \
_GEN_CB_DECL(name, args); \
static always_inline rtype name(_UNWRAP_ARGS(args)) { \
ret_stmt _GEN_REAL_CALL(name, args); \
} \
struct __dummy_struct
#define METHOD(rtype, name, args) _METHOD_RAW(rtype, return (rtype), name, args)
#define VOID_METHOD(name, args) _METHOD_RAW(void, , name, args)
#define _CB_DEF_ARGS_1 Object *_internal_arg1
#define _CB_DEF_ARGS_2 _CB_DEF_ARGS_1, Object *_internal_arg2
#define _CB_DEF_ARGS_3 _CB_DEF_ARGS_2, Object *_internal_arg3
#define _CB_DEF_ARGS_4 _CB_DEF_ARGS_3, Object *_internal_arg4
#define _CB_DEF_ARGS_5 _CB_DEF_ARGS_4, Object *_internal_arg5
#define _CB_DEF_ARGS_6 _CB_DEF_ARGS_5, Object *_internal_arg6
#define _CB_DEF_ARGS_N(count) (_GLUE(_CB_DEF_ARGS_, count))
#define _CB_DEF_ARGS_FOR(...) _CB_DEF_ARGS_N(_COUNT_ARGS(__VA_ARGS__))
#define _GEN_CB_DEF(name, args) \
Object *METHOD_CALLBACK_NAME(name) \
_CB_DEF_ARGS_FOR args
#define _SET_NTH_ARG(n, args) \
UNUSED _GET_NTH(n, args) = (void *) _internal_arg##n;
#define _SET_ARGS_1(args) _SET_NTH_ARG(1, args)
#define _SET_ARGS_2(args) _SET_ARGS_1(args) _SET_NTH_ARG(2, args)
#define _SET_ARGS_3(args) _SET_ARGS_2(args) _SET_NTH_ARG(3, args)
#define _SET_ARGS_4(args) _SET_ARGS_3(args) _SET_NTH_ARG(4, args)
#define _SET_ARGS_5(args) _SET_ARGS_4(args) _SET_NTH_ARG(5, args)
#define _SET_ARGS_6(args) _SET_ARGS_5(args) _SET_NTH_ARG(6, args)
#define _SET_ARGS_N(n, args) _GLUE(_SET_ARGS_, n)(args)
#define DEFINE_METHOD(rtype, name, args, body) \
_GEN_CB_DEF(name, args) { \
_SET_ARGS_N(_COUNT_ARGS args, args) \
body \
}
#endif

42
include/lisp/number.h Normal file
View File

@ -0,0 +1,42 @@
#ifndef INCLUDED_NUMBER_H
#define INCLUDED_NUMBER_H
#include "lisp/object.h"
#include "lisp/util.h"
LISP_BEGIN_DECLS
DECLARE_CLASS(Number);
DECLARE_CLASS(Float);
DECLARE_CLASS(Integer);
struct Number {
Object base;
};
struct NumberClass {
Class base;
Object *(*add)(Object *self, Object *other);
Object *(*sub)(Object *self, Object *other);
};
struct Float {
Number base;
double value;
};
struct FloatClass {
NumberClass base;
};
struct Integer {
Number base;
int64_t value;
};
struct IntegerClass {
NumberClass base;
};
LISP_END_DECLS
#endif

73
include/lisp/object.h Normal file
View File

@ -0,0 +1,73 @@
#ifndef INCLUDED_OBJECT_H
#define INCLUDED_OBJECT_H
#include "lisp/method_macro.h"
#include "lisp/util.h"
#include <ht.h>
#include <refcount/refcount.h>
#include <stddef.h>
LISP_BEGIN_DECLS
#define DECLARE_CLASS(Name) \
typedef struct Name Name; \
typedef struct Name##Class Name##Class
// clang-format off
#define ELEVENTH(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, ...) a11
#define COUNT_ARGS(...) ELLEVENTH(__VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1)
// clang-format on
#undef COUNT_ARGS
#undef TENTH
typedef struct Object Object;
typedef struct Class Class;
struct Object {
RefcountEntry refcount;
Class *class;
Object **slots;
};
struct Class {
Object base;
Class *superclass;
HTTable *subclasses;
size_t object_size;
HTTable *slots_indicies;
uint64_t nslots;
HTTable *methods;
Object *(*construct)(Object *self, Object *args);
};
Object *make_object(Object *class, Object *args);
DECLARE_CLASS(Pair);
struct Pair {
Object base;
Object *head;
Object *tail;
};
struct PairClass {
Class base;
Object *(*head)(Object *self);
Object *(*sethead)(Object *self, Object *new_head);
Object *(*tail)(Object *self);
Object *(*settail)(Object *self, Object *new_tail);
};
METHOD(Object *, head, ((Pair *) self));
VOID_METHOD(sethead, ((Pair *) self));
METHOD(Object *, tail, ((Pair *) self));
VOID_METHOD(settail, ((Pair *) self));
LISP_END_DECLS
#endif

20
include/lisp/string.h Normal file
View File

@ -0,0 +1,20 @@
#ifndef INCLUDED_STRING_H
#define INCLUDED_STRING_H
#include "lisp/array.h"
#include "lisp/util.h"
LISP_BEGIN_DECLS
DECLARE_CLASS(String);
struct String {
Array base;
bool borrowed;
};
struct StringClass {
ArrayClass base;
};
LISP_END_DECLS
#endif

32
include/lisp/symbol.h Normal file
View File

@ -0,0 +1,32 @@
#ifndef INCLUDED_SYMBOL_H
#define INCLUDED_SYMBOL_H
#include "lisp/function.h"
#include "lisp/object.h"
#include "lisp/string.h"
#include "lisp/util.h"
LISP_BEGIN_DECLS
DECLARE_CLASS(Symbol);
struct Symbol {
Object base;
String *name;
Object *value;
Class *class;
Function *func;
Object *plist;
};
struct SymbolClass {
Class base;
Object *(*value)(Object *self);
Object *(*class)(Object *self);
Object *(*function)(Object *self);
Object *(*plist)(Object *self);
};
LISP_END_DECLS
#endif

12
include/lisp/util.h Normal file
View File

@ -0,0 +1,12 @@
#ifndef INCLUDED_UTIL_H
#define INCLUDED_UTIL_H
#ifdef __cplusplus
# define LISP_BEGIN_DECLS extern "C" {
# define LISP_END_DECLS }
#else
# define LISP_BEGIN_DECLS
# define LISP_END_DECLS
#endif
#endif

1
src/array.c Normal file
View File

@ -0,0 +1 @@
#include "lisp/array.h"

1
src/function.c Normal file
View File

@ -0,0 +1 @@
#include "lisp/function.h"

1
src/hashtable.c Normal file
View File

@ -0,0 +1 @@
#include "lisp/hashtable.h"

1
src/number.c Normal file
View File

@ -0,0 +1 @@
#include "lisp/number.h"

11
src/object.c Normal file
View File

@ -0,0 +1,11 @@
#include "lisp/object.h"
#include "lisp/symbol.h"
Object *make_object(Object *class, Object *args) {
return NULL;
}
DEFINE_METHOD(Object *, head, (Pair * self), {
return NULL; //
})

1
src/string.c Normal file
View File

@ -0,0 +1 @@
#include "lisp/string.h"

1
src/symbol.c Normal file
View File

@ -0,0 +1 @@
#include "lisp/symbol.h"

5
test/CMakeLists.txt Normal file
View File

@ -0,0 +1,5 @@
add_compile_options(-Wall -Wpedantic)
link_libraries(olisp)
add_executable(test_object test_object.c)
add_test(NAME object COMMAND test_object)

5
test/test_object.c Normal file
View File

@ -0,0 +1,5 @@
#include <lisp/object.h>
int main(int argc, const char **argv) {
return 0;
}