Files
glisp/src/base.h
T
2026-07-19 02:23:10 -07:00

386 lines
12 KiB
C

#ifndef INCLUDED_TYPES_H
#define INCLUDED_TYPES_H
#include "argcountmacro.h"
#include "gc.h"
#include "memory.h"
#include <assert.h>
#include <stdnoreturn.h>
// ###################
// # Base value type #
// ###################
typedef void LispVal;
// ##########################
// # Fixnum and float stuff #
// ##########################
typedef intptr_t fixnum_t;
#if LISP_WORD_BITS == 32
# define LISP_FLOAT_SCANF "f"
typedef lisp_float32_t lisp_float_t;
#else
# define LISP_FLOAT_SCANF "lf"
typedef lisp_float64_t lisp_float_t;
#endif
#define MOST_POSITIVE_FIXNUM ((intptr_t) ((INTPTR_MAX & ~(intptr_t) 3) >> 2))
#define MOST_NEGATIVE_FIXNUM ((intptr_t) ((INTPTR_MIN & ~(intptr_t) 3) >> 2))
static ALWAYS_INLINE uintptr_t EXTRACT_TAG(LispVal *val) {
uintptr_t iv = (uintptr_t) val;
return iv & (uintptr_t) 3;
}
#define LISP_TAG_BITS 2
#define LISP_OBJECT_TAG ((uintptr_t) 0)
// 0b01
#define FIXNUM_TAG ((uintptr_t) 1)
// 0b10
#define LISP_FLOAT_TAG ((uintptr_t) 2)
static ALWAYS_INLINE bool LISP_OBJECT_P(LispVal *val) {
return EXTRACT_TAG(val) == LISP_OBJECT_TAG;
}
static ALWAYS_INLINE bool FIXNUMP(LispVal *val) {
return EXTRACT_TAG(val) == FIXNUM_TAG;
}
static ALWAYS_INLINE fixnum_t XFIXNUM(LispVal *val) {
assert(FIXNUMP(val));
return ((fixnum_t) val) >> 2;
}
static ALWAYS_INLINE LispVal *MAKE_FIXNUM(fixnum_t fn) {
return (LispVal *) ((((uintptr_t) fn) << 2) | FIXNUM_TAG);
}
static ALWAYS_INLINE bool LISP_FLOAT_P(LispVal *val) {
return EXTRACT_TAG(val) == LISP_FLOAT_TAG;
}
static ALWAYS_INLINE lisp_float_t XLISP_FLOAT(LispVal *val) {
assert(LISP_FLOAT_P(val));
uintptr_t iv = (uintptr_t) val;
iv &= ~(uintptr_t) 3;
return INT_TO_FLOAT_BITS(iv);
}
static ALWAYS_INLINE LispVal *MAKE_LISP_FLOAT(lisp_float_t flt) {
uintptr_t bits = FLOAT_TO_INT_BITS(flt);
return (LispVal *) ((bits & ~(uintptr_t) 3) | LISP_FLOAT_TAG);
}
// ###############
// # Other types #
// ###############
typedef enum {
TYPE_FIXNUM = 0,
TYPE_FLOAT = 1,
TYPE_CONS = 2,
TYPE_STRING = 3,
TYPE_SYMBOL = 4,
TYPE_VECTOR = 5,
TYPE_HASH_TABLE = 6,
TYPE_FUNCTION = 7,
N_LISP_TYPES,
} LispValType;
extern const char *LISP_TYPE_NAMES[N_LISP_TYPES];
typedef struct {
LispValType type;
ObjectGCInfo gc;
} LispObject;
extern bool lisp_gc_on_alloc;
#define LISP_OBJECT_ALIGNMENT (1 << LISP_TAG_BITS)
LispVal *lisp_alloc_object_no_gc(size_t size, LispValType type);
LispVal *lisp_alloc_object(size_t size, LispValType type);
void lisp_release_object(LispVal *val);
static ALWAYS_INLINE bool OBJECTP(LispVal *val) {
return EXTRACT_TAG(val) == LISP_OBJECT_TAG;
}
static ALWAYS_INLINE ObjectGCSet OBJECT_GET_GC_SET(LispVal *val) {
assert(OBJECTP(val));
return ((LispObject *) val)->gc.set;
}
static ALWAYS_INLINE bool OBJECT_GC_SET_P(LispVal *val, ObjectGCSet set) {
return OBJECT_GET_GC_SET(val) == set;
}
static ALWAYS_INLINE bool OBJECT_STATIC_P(LispVal *val) {
assert(OBJECTP(val));
return ((LispObject *) val)->gc.is_static;
}
static inline void MARK_OBJECT_ADDED(LispVal *val, LispVal *into) {
if (OBJECTP(val) && OBJECTP(into) && OBJECT_GC_SET_P(into, GC_BLACK)
&& OBJECT_GC_SET_P(val, GC_WHITE)) {
gc_move_to_set(val, GC_GREY);
}
}
static ALWAYS_INLINE LispValType TYPE_OF(LispVal *val) {
if (FIXNUMP(val)) {
return TYPE_FIXNUM;
} else if (LISP_FLOAT_P(val)) {
return TYPE_FLOAT;
} else {
return ((LispObject *) val)->type;
}
}
static ALWAYS_INLINE bool LISP_TYPEP(LispVal *val, LispValType type) {
if (FIXNUMP(val)) {
return type == TYPE_FIXNUM;
} else if (LISP_FLOAT_P(val)) {
return type == TYPE_FLOAT;
} else {
return ((LispObject *) val)->type == type;
}
}
noreturn void
internal_CHECK_TYPE_signal_type_error(LispVal *obj, size_t count,
const LispValType types[count]);
static ALWAYS_INLINE void internal_CHECK_TYPE(LispVal *obj, size_t count,
LispValType v1, LispValType v2,
LispValType v3, LispValType v4,
LispValType v5, LispValType v6) {
const LispValType types[] = {v1, v2, v3, v4, v5, v6};
for (size_t i = 0; i < count; ++i) {
if (LISP_TYPEP(obj, types[i])) {
return;
}
}
// Failed
internal_CHECK_TYPE_signal_type_error(obj, count, types);
}
#define internal_CHECK_TYPE_SUB(obj, count, a1, a2, a3, a4, a5, a6, ...) \
internal_CHECK_TYPE((obj), count, a1, a2, a3, a4, a5, a6)
#define CHECK_TYPE(obj, ...) \
internal_CHECK_TYPE_SUB((obj), COUNT_ARGS(__VA_ARGS__), __VA_ARGS__, \
TYPE_FIXNUM, TYPE_FIXNUM, TYPE_FIXNUM, \
TYPE_FIXNUM, TYPE_FIXNUM, TYPE_FIXNUM)
noreturn void signal_type_error(LispVal *obj, LispVal *typespec);
#define DEFOBJTYPE(Name, NAME, NAME_P, body) \
typedef struct { \
LispObject header; \
struct body; \
} Lisp##Name; \
static ALWAYS_INLINE bool NAME_P(LispVal *val) { \
return LISP_TYPEP(val, TYPE_##NAME); \
} \
struct __ignored
DEFOBJTYPE(String, STRING, STRINGP, {
size_t length;
char *data;
bool owned;
});
enum SymbolValueType {
SYMBOL_NORMAL,
SYMBOL_NATIVE,
};
enum SymbolFlags {
SYMBOL_DYNAMIC = 1,
SYMBOL_CONST_VALUE = 2,
SYMBOL_CONST_FUNCTION = 4,
};
DEFOBJTYPE(Symbol, SYMBOL, SYMBOLP, {
LispVal *name; // string
enum SymbolValueType value_type : 1;
enum SymbolFlags flags : 7;
LispVal *function;
union {
LispVal *normal;
LispVal **native;
} value;
LispVal *plist;
});
static ALWAYS_INLINE bool KEYWORDP(LispVal *val) {
if (!SYMBOLP(val)) {
return false;
}
LispString *sym = (LispString *) ((LispSymbol *) val)->name;
return sym->length && *sym->data == ':';
}
DEFOBJTYPE(Vector, VECTOR, VECTORP, {
size_t length;
LispVal **data;
});
// Defined here instead of in function.h so that headers don't have to include
// it just to define functions
#define DECLARE_SYMBOL(cname) \
extern const char *internal_Q##cname##_name; \
extern const size_t internal_Q##cname##_name_len; \
extern LispVal *Q##cname
#define DECLARE_VARIABLE(cname) \
DECLARE_SYMBOL(cname); \
extern LispVal *internal_V##cname##_init(void); \
extern LispVal *V##cname
#define DECLARE_FUNCTION(cname, cargs) \
DECLARE_SYMBOL(cname); \
extern const char *internal_F##cname##_argstr; \
extern const size_t internal_F##cname##_argstr_len; \
extern const char *internal_F##cname##_docstr; \
extern const size_t internal_F##cname##_docstr_len; \
LispVal *F##cname cargs
#define DEFINE_SYMBOL(cname, lisp_name) \
const char *internal_Q##cname##_name = lisp_name; \
const size_t internal_Q##cname##_name_len = sizeof(lisp_name) - 1; \
LispVal *Q##cname
#define DEFVAR(cname, lisp_name, doc, init_val) \
DEFINE_SYMBOL(cname, lisp_name); \
LispVal *internal_V##cname##_init(void) { \
return (init_val); \
} \
LispVal *V##cname
#define DEFUN(cname, lisp_name, cargs, lisp_args, doc) \
DEFINE_SYMBOL(cname, lisp_name); \
const char *internal_F##cname##_argstr = lisp_args; \
const size_t internal_F##cname##_argstr_len = sizeof(lisp_args) - 1; \
const char *internal_F##cname##_docstr = doc; \
const size_t internal_F##cname##_docstr_len = sizeof(doc) - 1; \
LispVal *Q##cname; \
LispVal *F##cname cargs
#define DEFSPECIAL(cname, lisp_name, cargs, lisp_args, doc) \
DEFUN(cname, lisp_name, cargs, lisp_args, doc)
#define REGISTER_GLOBAL_SYMBOL(cname) \
{ \
Q##cname = Fintern(make_lisp_string(internal_Q##cname##_name, \
internal_Q##cname##_name_len, \
false, false)); \
((LispSymbol *) Q##cname)->value_type = SYMBOL_NORMAL; \
lisp_gc_register_static_object(Q##cname); \
}
#define REGISTER_GLOBAL_VARIABLE(cname) \
REGISTER_GLOBAL_SYMBOL(cname); \
{ \
V##cname = internal_V##cname##_init(); \
((LispSymbol *) Q##cname)->value_type = SYMBOL_NATIVE; \
((LispSymbol *) Q##cname)->value.native = &V##cname; \
((LispSymbol *) Q##cname)->flags |= SYMBOL_DYNAMIC; \
}
#define REGISTER_GLOBAL_FUNCTION(cname) \
{ \
REGISTER_GLOBAL_SYMBOL(cname); \
((LispSymbol *) Q##cname)->function = BUILTIN_FUNCTION_OBJ(cname); \
}
#define REGISTER_GLOBAL_SPECIAL(cname) \
{ \
REGISTER_GLOBAL_SYMBOL(cname); \
((LispSymbol *) Q##cname)->function = BUILTIN_FUNCTION_OBJ(cname); \
((LispFunction *) ((LispSymbol *) Q##cname)->function) \
->impl.native.no_eval_args = true; \
}
DECLARE_SYMBOL(nil);
DECLARE_SYMBOL(t);
DECLARE_SYMBOL(unbound);
DECLARE_VARIABLE(lexical_environment);
extern LispVal *Vlexical_environment;
static ALWAYS_INLINE bool NILP(LispVal *val) {
return val == Qnil;
}
static ALWAYS_INLINE bool EQ(LispVal *val1, LispVal *val2) {
return val1 == val2;
}
// Some core functions
DECLARE_FUNCTION(id, (LispVal * obj));
DECLARE_FUNCTION(eq, (LispVal * obj1, LispVal *obj2));
DECLARE_FUNCTION(quote, (LispVal * form));
// TODO probably move these to another file
LispVal *make_vector(LispVal **data, size_t length, bool take);
DECLARE_FUNCTION(make_symbol, (LispVal * name));
DECLARE_FUNCTION(intern, (LispVal * name));
DECLARE_FUNCTION(symbol_value, (LispVal * sym));
DECLARE_FUNCTION(symbol_function, (LispVal * sym, LispVal *resolve));
DECLARE_FUNCTION(symbol_plist, (LispVal * sym));
DECLARE_FUNCTION(set, (LispVal * sym, LispVal *value));
DECLARE_FUNCTION(fset, (LispVal * sym, LispVal *value));
DECLARE_FUNCTION(setplist, (LispVal * sym, LispVal *plist));
DECLARE_FUNCTION(get, (LispVal * sym, LispVal *key, LispVal *def));
DECLARE_FUNCTION(put, (LispVal * sym, LispVal *key, LispVal *val));
static ALWAYS_INLINE LispVal *SYMBOL_VALUE(LispVal *sym) {
assert(SYMBOLP(sym));
LispSymbol *s = (LispSymbol *) sym;
switch (s->value_type) {
case SYMBOL_NORMAL:
return s->value.normal;
case SYMBOL_NATIVE:
return *s->value.native;
}
}
static ALWAYS_INLINE bool CONST_VALUE_P(LispVal *sym) {
assert(SYMBOLP(sym));
return ((LispSymbol *) sym)->flags & SYMBOL_CONST_VALUE;
}
static ALWAYS_INLINE bool CONST_FUNCTION_P(LispVal *sym) {
assert(SYMBOLP(sym));
return ((LispSymbol *) sym)->flags & SYMBOL_CONST_FUNCTION;
}
static ALWAYS_INLINE bool DYNAMIC_SYMBOL_P(LispVal *sym) {
assert(SYMBOLP(sym));
return ((LispSymbol *) sym)->flags & SYMBOL_DYNAMIC;
}
static ALWAYS_INLINE void SET_SYMBOL_VALUE(LispVal *sym, LispVal *value) {
assert(SYMBOLP(sym));
LispSymbol *s = (LispSymbol *) sym;
if (CONST_VALUE_P(sym)) {
// TODO throw
abort();
}
switch (s->value_type) {
case SYMBOL_NORMAL:
s->value.normal = value;
break;
case SYMBOL_NATIVE:
*s->value.native = value;
break;
}
}
// condition stuff
DECLARE_SYMBOL(condition_class);
DECLARE_FUNCTION(condition_class_p, (LispVal * val));
DECLARE_FUNCTION(condition_subclass_p, (LispVal * child, LispVal *parent));
// Defined in lisp code (eventually) but used in read.c
DECLARE_SYMBOL(backquote);
DECLARE_SYMBOL(comma);
DECLARE_SYMBOL(comma_at);
#endif