Type errors
This commit is contained in:
@ -9,6 +9,8 @@
|
|||||||
// return the arg count - 1, allowing for a dummy value to be passed
|
// return the arg count - 1, allowing for a dummy value to be passed
|
||||||
#define COUNT_ARGS_SAFE(...) \
|
#define COUNT_ARGS_SAFE(...) \
|
||||||
internal_TENTH(__VA_ARGS__, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0)
|
internal_TENTH(__VA_ARGS__, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0)
|
||||||
|
#define MAX_COUNTED_ARGS 9
|
||||||
|
#define MAX_COUNTED_SAFE_ARGS 8
|
||||||
|
|
||||||
#define MACRO_EVAL(a) a
|
#define MACRO_EVAL(a) a
|
||||||
#define MACRO_GLUE(a, b) a##b
|
#define MACRO_GLUE(a, b) a##b
|
||||||
|
|||||||
27
src/base.c
27
src/base.c
@ -3,6 +3,7 @@
|
|||||||
#include "hashtable.h"
|
#include "hashtable.h"
|
||||||
#include "lisp.h"
|
#include "lisp.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
const char *LISP_TYPE_NAMES[N_LISP_TYPES] = {
|
const char *LISP_TYPE_NAMES[N_LISP_TYPES] = {
|
||||||
@ -27,6 +28,18 @@ void *lisp_alloc_object(size_t size, LispValType type) {
|
|||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void signal_type_error(LispVal *obj, size_t count,
|
||||||
|
const LispValType types[count]) {
|
||||||
|
// TODO actually throw an error
|
||||||
|
fprintf(stderr, "Type error! Got: %s | Expected: (or ",
|
||||||
|
LISP_TYPE_NAMES[TYPE_OF(obj)]);
|
||||||
|
for (size_t i = 0; i < count; ++i) {
|
||||||
|
fprintf(stderr, "%s%s", LISP_TYPE_NAMES[i],
|
||||||
|
i < count - 1 ? " " : ")\n");
|
||||||
|
}
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
DEFINE_SYMBOL(nil, "nil");
|
DEFINE_SYMBOL(nil, "nil");
|
||||||
DEFINE_SYMBOL(t, "t");
|
DEFINE_SYMBOL(t, "t");
|
||||||
DEFINE_SYMBOL(unbound, "unbound");
|
DEFINE_SYMBOL(unbound, "unbound");
|
||||||
@ -71,7 +84,7 @@ DEFUN(make_symbol, "make-symbol", (LispVal * name), "(name)",
|
|||||||
}
|
}
|
||||||
|
|
||||||
DEFUN(intern, "intern", (LispVal * name), "(name)", "") {
|
DEFUN(intern, "intern", (LispVal * name), "(name)", "") {
|
||||||
// TODO type checking
|
CHECK_TYPE(name, TYPE_STRING);
|
||||||
LispVal *res = Fgethash(obarray, name, Qunbound);
|
LispVal *res = Fgethash(obarray, name, Qunbound);
|
||||||
if (res != Qunbound) {
|
if (res != Qunbound) {
|
||||||
return res;
|
return res;
|
||||||
@ -80,3 +93,15 @@ DEFUN(intern, "intern", (LispVal * name), "(name)", "") {
|
|||||||
Fputhash(obarray, name, newsym);
|
Fputhash(obarray, name, newsym);
|
||||||
return newsym;
|
return newsym;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DEFUN(symbol_function, "symbol-function", (LispVal * sym, LispVal *resolve),
|
||||||
|
"(sym &optional resolve)", "") {
|
||||||
|
CHECK_TYPE(sym, TYPE_SYMBOL);
|
||||||
|
if (NILP(resolve)) {
|
||||||
|
return ((LispSymbol *) sym)->function;
|
||||||
|
}
|
||||||
|
while (!NILP(sym) && SYMBOLP(sym)) {
|
||||||
|
sym = ((LispSymbol *) sym)->function;
|
||||||
|
}
|
||||||
|
return sym;
|
||||||
|
}
|
||||||
|
|||||||
26
src/base.h
26
src/base.h
@ -1,10 +1,12 @@
|
|||||||
#ifndef INCLUDED_TYPES_H
|
#ifndef INCLUDED_TYPES_H
|
||||||
#define INCLUDED_TYPES_H
|
#define INCLUDED_TYPES_H
|
||||||
|
|
||||||
|
#include "argcountmacro.h"
|
||||||
#include "gc.h"
|
#include "gc.h"
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <stdnoreturn.h>
|
||||||
|
|
||||||
// ###################
|
// ###################
|
||||||
// # Base value type #
|
// # Base value type #
|
||||||
@ -119,6 +121,29 @@ static ALWAYS_INLINE bool LISP_TYPEP(LispVal *val, LispValType type) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
noreturn void 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
|
||||||
|
signal_type_error(obj, count, types);
|
||||||
|
}
|
||||||
|
#define internal_CHECK_TYPE1(obj, type) internal_CHECK_TYPE(obj, v1, )
|
||||||
|
#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)
|
||||||
|
|
||||||
#define DEFOBJTYPE(Name, NAME, NAME_P, body) \
|
#define DEFOBJTYPE(Name, NAME, NAME_P, body) \
|
||||||
typedef struct { \
|
typedef struct { \
|
||||||
LispObject header; \
|
LispObject header; \
|
||||||
@ -186,6 +211,7 @@ DECLARE_FUNCTION(eq, (LispVal * obj1, LispVal *obj2));
|
|||||||
LispVal *make_vector(LispVal **data, size_t length, bool take);
|
LispVal *make_vector(LispVal **data, size_t length, bool take);
|
||||||
DECLARE_FUNCTION(make_symbol, (LispVal * name));
|
DECLARE_FUNCTION(make_symbol, (LispVal * name));
|
||||||
DECLARE_FUNCTION(intern, (LispVal * name));
|
DECLARE_FUNCTION(intern, (LispVal * name));
|
||||||
|
DECLARE_FUNCTION(symbol_function, (LispVal * sym, LispVal *resolve));
|
||||||
|
|
||||||
// TODO these are actually special-forms
|
// TODO these are actually special-forms
|
||||||
DECLARE_SYMBOL(quote);
|
DECLARE_SYMBOL(quote);
|
||||||
|
|||||||
@ -157,7 +157,8 @@ LispVal *make_builtin_function(LispVal *name, LispVal *(*cfunc)(),
|
|||||||
LispVal *docstr) {
|
LispVal *docstr) {
|
||||||
LispFunction *obj = lisp_alloc_object(sizeof(LispFunction), TYPE_FUNCTION);
|
LispFunction *obj = lisp_alloc_object(sizeof(LispFunction), TYPE_FUNCTION);
|
||||||
obj->name = name;
|
obj->name = name;
|
||||||
obj->is_native = true;
|
obj->flags.type = FUNCTION_NATIVE;
|
||||||
|
obj->flags.no_eval_args = false;
|
||||||
obj->docstr = docstr;
|
obj->docstr = docstr;
|
||||||
obj->impl.native.zero = cfunc;
|
obj->impl.native.zero = cfunc;
|
||||||
ReadStream stream;
|
ReadStream stream;
|
||||||
@ -182,3 +183,31 @@ LispVal *make_builtin_function(LispVal *name, LispVal *(*cfunc)(),
|
|||||||
}
|
}
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Calling functions
|
||||||
|
static ALWAYS_INLINE LispVal *call_native(LispVal *orig_func,
|
||||||
|
LispFunction *fobj, LispVal *args) {
|
||||||
|
return Qnil;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFUN(funcall, "funcall", (LispVal * func, LispVal *args), "(func &rest args)",
|
||||||
|
"") {
|
||||||
|
CHECK_TYPE(func, TYPE_FUNCTION, TYPE_SYMBOL);
|
||||||
|
LispFunction *fobj = func;
|
||||||
|
if (SYMBOLP(func)) {
|
||||||
|
fobj = Fsymbol_function(func, Qt);
|
||||||
|
}
|
||||||
|
if (!FUNCTIONP(fobj)) {
|
||||||
|
// TODO error
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
switch (fobj->flags.type) {
|
||||||
|
case FUNCTION_NATIVE:
|
||||||
|
return call_native(func, fobj, args);
|
||||||
|
case FUNCTION_INTERP:
|
||||||
|
case FUNCTION_BYTECOMP:
|
||||||
|
default:
|
||||||
|
// TODO implement
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -29,9 +29,20 @@ union native_function {
|
|||||||
LispVal *(*five)(LispVal *, LispVal *, LispVal *, LispVal *, LispVal *);
|
LispVal *(*five)(LispVal *, LispVal *, LispVal *, LispVal *, LispVal *);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
FUNCTION_NATIVE,
|
||||||
|
FUNCTION_INTERP,
|
||||||
|
FUNCTION_BYTECOMP,
|
||||||
|
} LispFunctionType;
|
||||||
|
|
||||||
|
struct function_flags {
|
||||||
|
LispFunctionType type : 2;
|
||||||
|
unsigned int no_eval_args : 1;
|
||||||
|
};
|
||||||
|
|
||||||
DEFOBJTYPE(Function, FUNCTION, FUNCTIONP, {
|
DEFOBJTYPE(Function, FUNCTION, FUNCTIONP, {
|
||||||
LispVal *name; // symbol (or nil for a lambda)
|
LispVal *name; // symbol (or nil for a lambda)
|
||||||
bool is_native;
|
struct function_flags flags;
|
||||||
struct LambdaList args;
|
struct LambdaList args;
|
||||||
LispVal *docstr;
|
LispVal *docstr;
|
||||||
union {
|
union {
|
||||||
@ -71,4 +82,6 @@ LispVal *make_builtin_function(LispVal *name, LispVal *(*func)(),
|
|||||||
make_lisp_string(internal_F##cname##_docstr, \
|
make_lisp_string(internal_F##cname##_docstr, \
|
||||||
internal_F##cname##_docstr_len, false, false))
|
internal_F##cname##_docstr_len, false, false))
|
||||||
|
|
||||||
|
DECLARE_FUNCTION(funcall, (LispVal * func, LispVal *args));
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -9,6 +9,7 @@ int main(int argc, const char **argv) {
|
|||||||
const char BUF[] = "t";
|
const char BUF[] = "t";
|
||||||
read_stream_init(&s, BUF, sizeof(BUF) - 1);
|
read_stream_init(&s, BUF, sizeof(BUF) - 1);
|
||||||
LispVal *l = read(&s);
|
LispVal *l = read(&s);
|
||||||
|
CHECK_TYPE(l, TYPE_FIXNUM);
|
||||||
printf("%d\n", l == Qt);
|
printf("%d\n", l == Qt);
|
||||||
lisp_shutdown();
|
lisp_shutdown();
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user