Allow default values for optional argumnts
This commit is contained in:
252
src/lisp.c
252
src/lisp.c
@ -17,8 +17,17 @@ struct _TypeNameEntry LISP_TYPE_NAMES[N_LISP_TYPES] = {
|
||||
[TYPE_VECTOR] = {"vector", sizeof("vector") - 1},
|
||||
[TYPE_FUNCTION] = {"function", sizeof("function") - 1},
|
||||
[TYPE_HASHTABLE] = {"hashtable", sizeof("hashtable") - 1},
|
||||
[TYPE_USER_POINTER] = {"user-pointer", sizeof("user-pointer") - 1},
|
||||
};
|
||||
|
||||
void free_opt_arg_desc(void *obj) {
|
||||
struct OptArgDesc *oad = obj;
|
||||
lisp_unref(oad->name);
|
||||
lisp_unref(oad->default_form);
|
||||
lisp_unref(oad->pred_var);
|
||||
lisp_free(oad);
|
||||
}
|
||||
|
||||
DEF_STATIC_STRING(_Qnil_name, "nil");
|
||||
LispSymbol _Qnil = {
|
||||
.type = TYPE_SYMBOL,
|
||||
@ -120,6 +129,13 @@ void _internal_lisp_delete_object(LispVal *val) {
|
||||
lisp_unref(tbl->hash_fn);
|
||||
lisp_free(val);
|
||||
} break;
|
||||
case TYPE_USER_POINTER: {
|
||||
LispUserPointer *ptr = (LispUserPointer *) val;
|
||||
if (ptr->free_func) {
|
||||
ptr->free_func(ptr->data);
|
||||
}
|
||||
lisp_free(val);
|
||||
} break;
|
||||
default:
|
||||
abort();
|
||||
};
|
||||
@ -222,25 +238,68 @@ DEF_STATIC_SYMBOL(key, "&key");
|
||||
DEF_STATIC_SYMBOL(allow_other_keys, "&allow-other-keys");
|
||||
DEF_STATIC_SYMBOL(rest, "&rest");
|
||||
|
||||
static bool parse_opt_arg_entry(LispVal *ent, struct OptArgDesc *aod,
|
||||
LispVal *found_args) {
|
||||
aod->name = Qnil;
|
||||
aod->default_form = Qnil;
|
||||
aod->pred_var = Qnil;
|
||||
if (TYPEOF(ent) == TYPE_SYMBOL) {
|
||||
if (VALUE_CONSTANTP(ent)) {
|
||||
return false;
|
||||
} else if (!NILP(Fgethash(found_args, ent, Qnil))) {
|
||||
return false;
|
||||
}
|
||||
aod->name = lisp_ref(ent);
|
||||
aod->pred_var = Qnil;
|
||||
aod->default_form = Qnil;
|
||||
return true;
|
||||
} else if (LISTP(ent) && SYMBOLP(Fhead(ent)) && !VALUE_CONSTANTP(Fhead(ent))
|
||||
&& LISTP(Ftail(ent))) {
|
||||
LispVal *end = Ftail(Ftail(ent));
|
||||
if (!LISTP(end) || (!SYMBOLP(Fhead(end)) && !NILP(Fhead(end)))
|
||||
|| (!NILP(Fhead(end)) && VALUE_CONSTANTP(Fhead(end)))) {
|
||||
return false;
|
||||
} else if (!NILP(Fgethash(found_args, Fhead(ent), Qnil))) {
|
||||
return false;
|
||||
} else if (!NILP(end)
|
||||
&& (!NILP(Fgethash(found_args, Fhead(end), Qnil))
|
||||
|| VALUE_CONSTANTP(Fhead(end))
|
||||
|| Fhead(end) == Fhead(ent))) {
|
||||
return false;
|
||||
}
|
||||
aod->name = lisp_ref(Fhead(ent));
|
||||
aod->default_form = lisp_ref(Fhead(Ftail(ent)));
|
||||
aod->pred_var = lisp_ref(Fhead(end));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void set_function_args(LispFunction *func, LispVal *args) {
|
||||
// TODO disallow duplicate args
|
||||
lisp_unref(func->args);
|
||||
lisp_unref(func->kwargs);
|
||||
lisp_unref(func->rargs);
|
||||
lisp_unref(func->oargs);
|
||||
lisp_unref(func->rest_arg);
|
||||
|
||||
int mode = 0; // required
|
||||
bool has_opt = false; // mode 1
|
||||
bool has_key = false; // mode 2
|
||||
bool has_rest = false; // mode 3
|
||||
LispVal *found_args = make_lisp_hashtable(Qnil, Qnil);
|
||||
|
||||
enum {
|
||||
REQ,
|
||||
OPT,
|
||||
KEY,
|
||||
REST,
|
||||
MUST_CHANGE,
|
||||
} mode = REQ;
|
||||
bool has_opt = false;
|
||||
bool has_key = false;
|
||||
bool has_rest = false;
|
||||
|
||||
func->n_req = 0;
|
||||
func->rargs = Qnil;
|
||||
func->n_opt = 0;
|
||||
func->oargs = Qnil;
|
||||
func->rest_arg = Qnil;
|
||||
size_t n_kw = 0;
|
||||
func->kwargs = lisp_ref(make_lisp_hashtable(Qnil, Qnil));
|
||||
func->allow_other_keys = false;
|
||||
|
||||
@ -248,35 +307,37 @@ void set_function_args(LispFunction *func, LispVal *args) {
|
||||
LispVal *oargs_end;
|
||||
|
||||
FOREACH(arg, args) {
|
||||
if (!SYMBOLP(arg) || VALUE_CONSTANTP(arg)) {
|
||||
goto malformed;
|
||||
} else if (arg == Qopt) {
|
||||
if (has_opt || mode == 3) {
|
||||
if (arg == Qopt) {
|
||||
if (has_opt || mode == REST) {
|
||||
goto malformed;
|
||||
}
|
||||
has_opt = true;
|
||||
mode = 1;
|
||||
mode = OPT;
|
||||
} else if (arg == Qkey) {
|
||||
if (has_key || mode == 3) {
|
||||
if (has_key || mode == REST) {
|
||||
goto malformed;
|
||||
}
|
||||
has_key = true;
|
||||
mode = 2;
|
||||
mode = KEY;
|
||||
} else if (arg == Qrest) {
|
||||
if (has_rest) {
|
||||
goto malformed;
|
||||
}
|
||||
has_rest = true;
|
||||
mode = 3;
|
||||
mode = REST;
|
||||
} else if (arg == Qallow_other_keys) {
|
||||
if (func->allow_other_keys || mode != 2) {
|
||||
if (func->allow_other_keys || mode != KEY) {
|
||||
goto malformed;
|
||||
}
|
||||
func->allow_other_keys = true;
|
||||
mode = -1;
|
||||
mode = MUST_CHANGE;
|
||||
} else {
|
||||
switch (mode) {
|
||||
case 0:
|
||||
case REQ:
|
||||
if (!SYMBOLP(arg) || VALUE_CONSTANTP(arg)
|
||||
|| !NILP(Fgethash(found_args, arg, Qnil))) {
|
||||
goto malformed;
|
||||
}
|
||||
if (NILP(func->rargs)) {
|
||||
func->rargs = Fpair(arg, Qnil);
|
||||
rargs_end = func->rargs;
|
||||
@ -285,21 +346,46 @@ void set_function_args(LispFunction *func, LispVal *args) {
|
||||
Fsettail(rargs_end, new_end);
|
||||
rargs_end = new_end;
|
||||
}
|
||||
Fputhash(found_args, arg, Qt);
|
||||
++func->n_req;
|
||||
break;
|
||||
case 1:
|
||||
case OPT: {
|
||||
LispVal *desc =
|
||||
ALLOC_USERPTR(struct OptArgDesc, free_opt_arg_desc);
|
||||
USERPTR(struct OptArgDesc, desc)->index = 0;
|
||||
if (!parse_opt_arg_entry(arg, USERPTR(struct OptArgDesc, desc),
|
||||
found_args)) {
|
||||
lisp_unref(desc);
|
||||
goto malformed;
|
||||
}
|
||||
if (NILP(func->oargs)) {
|
||||
func->oargs = Fpair(arg, Qnil);
|
||||
func->oargs = Fpair(desc, Qnil);
|
||||
oargs_end = func->oargs;
|
||||
} else {
|
||||
LispVal *new_end = Fpair(arg, Qnil);
|
||||
LispVal *new_end = Fpair(desc, Qnil);
|
||||
Fsettail(oargs_end, new_end);
|
||||
oargs_end = new_end;
|
||||
}
|
||||
Fputhash(found_args, USERPTR(struct OptArgDesc, desc)->name,
|
||||
Qt);
|
||||
if (!NILP(USERPTR(struct OptArgDesc, desc)->pred_var)) {
|
||||
Fputhash(found_args,
|
||||
USERPTR(struct OptArgDesc, desc)->pred_var, Qt);
|
||||
}
|
||||
++func->n_opt;
|
||||
break;
|
||||
case 2: {
|
||||
LispString *sn = ((LispSymbol *) arg)->name;
|
||||
} break;
|
||||
case KEY: {
|
||||
LispVal *desc =
|
||||
ALLOC_USERPTR(struct OptArgDesc, free_opt_arg_desc);
|
||||
if (!parse_opt_arg_entry(arg, USERPTR(struct OptArgDesc, desc),
|
||||
found_args)) {
|
||||
lisp_unref(desc);
|
||||
goto malformed;
|
||||
}
|
||||
USERPTR(struct OptArgDesc, desc)->index = 0;
|
||||
LispString *sn =
|
||||
((LispSymbol *) USERPTR(struct OptArgDesc, desc)->name)
|
||||
->name;
|
||||
char kns[sn->length + 2];
|
||||
kns[0] = ':';
|
||||
memcpy(kns + 1, sn->data, sn->length);
|
||||
@ -307,29 +393,43 @@ void set_function_args(LispFunction *func, LispVal *args) {
|
||||
LispVal *kn =
|
||||
make_lisp_string(kns, sn->length + 1, false, false);
|
||||
lisp_ref(kn);
|
||||
Fputhash(func->kwargs, Fintern(kn),
|
||||
Fpair(make_lisp_integer(n_kw), arg));
|
||||
Fputhash(func->kwargs, Fintern(kn), desc);
|
||||
lisp_unref(kn);
|
||||
Fputhash(found_args, USERPTR(struct OptArgDesc, desc)->name,
|
||||
Qt);
|
||||
if (!NILP(USERPTR(struct OptArgDesc, desc)->pred_var)) {
|
||||
Fputhash(found_args,
|
||||
USERPTR(struct OptArgDesc, desc)->pred_var, Qt);
|
||||
}
|
||||
} break;
|
||||
case 3:
|
||||
case REST:
|
||||
if (!NILP(func->rest_arg)) {
|
||||
goto malformed;
|
||||
} else if (!SYMBOLP(arg) || VALUE_CONSTANTP(arg)) {
|
||||
goto malformed;
|
||||
} else if (!NILP(Fgethash(found_args, arg, Qnil))) {
|
||||
goto malformed;
|
||||
}
|
||||
func->rest_arg = lisp_ref(arg);
|
||||
mode = -1;
|
||||
mode = MUST_CHANGE;
|
||||
break;
|
||||
case -1:
|
||||
case MUST_CHANGE:
|
||||
goto malformed;
|
||||
}
|
||||
}
|
||||
}
|
||||
lisp_ref(func->rargs);
|
||||
lisp_ref(func->oargs);
|
||||
lisp_unref(found_args);
|
||||
// do this last
|
||||
func->args = lisp_ref(args);
|
||||
return;
|
||||
malformed:
|
||||
lisp_unref(func->rargs);
|
||||
lisp_unref(func->oargs);
|
||||
lisp_unref(func->rest_arg);
|
||||
lisp_unref(func->kwargs);
|
||||
lisp_unref(found_args);
|
||||
Fthrow(Qmalformed_lambda_list_error, Fpair(args, Qnil));
|
||||
}
|
||||
|
||||
@ -370,6 +470,15 @@ LispVal *make_lisp_hashtable(LispVal *eq_fn, LispVal *hash_fn) {
|
||||
return LISPVAL(self);
|
||||
}
|
||||
|
||||
LispVal *make_user_pointer(void *data, void (*free_func)(void *)) {
|
||||
LispUserPointer *self = lisp_malloc(sizeof(LispUserPointer));
|
||||
self->type = TYPE_USER_POINTER;
|
||||
self->ref_count = 0;
|
||||
self->data = data;
|
||||
self->free_func = free_func;
|
||||
return LISPVAL(self);
|
||||
}
|
||||
|
||||
DEFUN(type_of, "type-of", (LispVal * obj)) {
|
||||
if (obj->type < 0 || obj->type >= N_LISP_TYPES) {
|
||||
return Qnil;
|
||||
@ -923,24 +1032,24 @@ static LispVal **process_builtin_args(LispFunction *func, LispVal *args,
|
||||
LispVal *rest = Qnil;
|
||||
LispVal *rest_end;
|
||||
size_t have_count = 0;
|
||||
LispVal *index;
|
||||
LispVal *opt_desc;
|
||||
LispVal *arg = Qnil; // last arg processed
|
||||
while (!NILP(args)) {
|
||||
arg = Fhead(args);
|
||||
if (have_count < func->n_req + func->n_opt) {
|
||||
vec[have_count++] = lisp_ref(arg);
|
||||
} else if (KEYWORDP(arg)
|
||||
&& !NILP(index = Fhead(Fgethash(func->kwargs, arg, Qnil)))
|
||||
&& !NILP(opt_desc = Fhead(Fgethash(func->kwargs, arg, Qnil)))
|
||||
&& NILP(rest)) {
|
||||
LispInteger *n = (LispInteger *) index;
|
||||
if (vec[n->value]) {
|
||||
struct OptArgDesc *oad = USERPTR(struct OptArgDesc, opt_desc);
|
||||
if (vec[oad->index]) {
|
||||
goto multikey;
|
||||
}
|
||||
args = Ftail(args);
|
||||
if (NILP(args)) {
|
||||
goto key_no_val;
|
||||
}
|
||||
vec[n->value] = lisp_ref(Fhead(arg));
|
||||
vec[oad->index] = lisp_ref(Fhead(arg));
|
||||
} else if (KEYWORDP(arg) && !func->allow_other_keys && NILP(rest)) {
|
||||
goto unknown_key;
|
||||
} else if (NILP(func->rest_arg)) {
|
||||
@ -1039,11 +1148,6 @@ static void process_lisp_args(LispFunction *func, LispVal *args,
|
||||
enum { REQ, OPT, KEY, REST } mode = REQ;
|
||||
LispVal *rargs = func->rargs;
|
||||
LispVal *oargs = func->oargs;
|
||||
// TODO fix macro to avoid warnings
|
||||
HASHTABLE_FOREACH(arg, info, func->kwargs, {
|
||||
// TODO allow default values
|
||||
Fputhash(lexenv, Fhead(info), Qnil);
|
||||
});
|
||||
while (!NILP(args)) {
|
||||
LispVal *arg = Fhead(args);
|
||||
switch (mode) {
|
||||
@ -1060,7 +1164,11 @@ static void process_lisp_args(LispFunction *func, LispVal *args,
|
||||
mode = KEY;
|
||||
continue; // skip increment
|
||||
}
|
||||
Fputhash(lexenv, Fhead(oargs), arg);
|
||||
struct OptArgDesc *oad = USERPTR(struct OptArgDesc, Fhead(oargs));
|
||||
Fputhash(lexenv, oad->name, arg);
|
||||
if (!NILP(oad->pred_var)) {
|
||||
Fputhash(lexenv, oad->pred_var, Qt);
|
||||
}
|
||||
oargs = Ftail(oargs);
|
||||
} break;
|
||||
case KEY:
|
||||
@ -1068,23 +1176,37 @@ static void process_lisp_args(LispFunction *func, LispVal *args,
|
||||
mode = REST;
|
||||
continue; // skip increment
|
||||
}
|
||||
LispVal *var_name = Fhead(Fgethash(func->kwargs, arg, Qnil));
|
||||
if (NILP(var_name)) {
|
||||
LispVal *desc_lv = Fgethash(func->kwargs, arg, Qnil);
|
||||
if (NILP(desc_lv)) {
|
||||
if (!func->allow_other_keys) {
|
||||
goto unknown_key;
|
||||
}
|
||||
mode = REST;
|
||||
continue; // skip increment
|
||||
}
|
||||
struct OptArgDesc *oad = USERPTR(struct OptArgDesc, desc_lv);
|
||||
args = Ftail(args);
|
||||
if (NILP(args)) {
|
||||
goto missing_value;
|
||||
}
|
||||
LispVal *value = Fhead(args);
|
||||
Fputhash(lexenv, var_name, value);
|
||||
Fputhash(lexenv, oad->name, value);
|
||||
if (!NILP(oad->pred_var)) {
|
||||
Fputhash(lexenv, oad->pred_var, Qt);
|
||||
}
|
||||
break;
|
||||
case REST:
|
||||
if (NILP(func->rest_arg)) {
|
||||
goto too_many_args;
|
||||
if (KEYWORDP(arg)) {
|
||||
args = Ftail(args);
|
||||
if (NILP(args)) {
|
||||
goto missing_value;
|
||||
}
|
||||
args = Ftail(args);
|
||||
continue; // skip increment
|
||||
} else {
|
||||
goto too_many_args;
|
||||
}
|
||||
}
|
||||
Fputhash(lexenv, func->rest_arg, args);
|
||||
// done processing
|
||||
@ -1095,8 +1217,25 @@ static void process_lisp_args(LispFunction *func, LispVal *args,
|
||||
if (!NILP(rargs)) {
|
||||
goto missing_required;
|
||||
}
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wunused-variable"
|
||||
HASHTABLE_FOREACH(arg, desc_lv, func->kwargs, {
|
||||
struct OptArgDesc *oad = USERPTR(struct OptArgDesc, desc_lv);
|
||||
// only check the current function's lexenv and not its parents'
|
||||
if (Fgethash(lexenv, oad->name, Qunbound) == Qunbound) {
|
||||
Fputhash(lexenv, oad->name, Feval(oad->default_form));
|
||||
if (!NILP(oad->pred_var)) {
|
||||
Fputhash(lexenv, oad->pred_var, Qnil);
|
||||
}
|
||||
}
|
||||
});
|
||||
#pragma GCC diagnostic pop
|
||||
FOREACH(arg, oargs) {
|
||||
Fputhash(lexenv, arg, Qnil);
|
||||
struct OptArgDesc *oad = USERPTR(struct OptArgDesc, arg);
|
||||
Fputhash(lexenv, oad->name, Feval(oad->default_form));
|
||||
if (!NILP(oad->pred_var)) {
|
||||
Fputhash(lexenv, oad->pred_var, Qnil);
|
||||
}
|
||||
}
|
||||
return;
|
||||
// TODO different messages
|
||||
@ -1109,14 +1248,10 @@ unknown_key:
|
||||
|
||||
static LispVal *call_lisp_function(LispVal *name, LispFunction *func,
|
||||
LispVal *args) {
|
||||
Fputhash(the_stack->lexenv, Qparent_lexenv, func->lexenv);
|
||||
process_lisp_args(func, args, the_stack->lexenv);
|
||||
// TODO handle macros
|
||||
LispVal *body = Fpair(Qprogn, func->body);
|
||||
LispVal *retval = Qnil;
|
||||
WITH_CLEANUP(body, {
|
||||
retval = Feval(body); //
|
||||
});
|
||||
return retval;
|
||||
return Fprogn(func->body);
|
||||
}
|
||||
|
||||
static LispVal *call_function(LispVal *func, LispVal *args,
|
||||
@ -1158,10 +1293,15 @@ DEFUN(eval_in_env, "eval-in-env", (LispVal * form, LispVal *lexenv)) {
|
||||
case TYPE_INTEGER:
|
||||
case TYPE_FLOAT:
|
||||
case TYPE_HASHTABLE:
|
||||
case TYPE_USER_POINTER:
|
||||
// the above all are self-evaluating
|
||||
return form;
|
||||
case TYPE_SYMBOL:
|
||||
return symbol_value_in_lexenv(lexenv, form);
|
||||
if (KEYWORDP(form)) {
|
||||
return form;
|
||||
} else {
|
||||
return symbol_value_in_lexenv(lexenv, form);
|
||||
}
|
||||
case TYPE_VECTOR: {
|
||||
LispVector *vec = (LispVector *) form;
|
||||
LispVal **elts = lisp_malloc(sizeof(LispVal *) * vec->length);
|
||||
@ -1267,10 +1407,7 @@ DEFMACRO(if, "if", (LispVal * cond, LispVal *t, LispVal *nil)) {
|
||||
if (!NILP(res)) {
|
||||
retval = Feval(t);
|
||||
} else {
|
||||
LispVal *body = Fpair(Qprogn, nil);
|
||||
WITH_CLEANUP(body, {
|
||||
retval = Feval(body); //
|
||||
});
|
||||
retval = Fprogn(nil);
|
||||
}
|
||||
});
|
||||
return retval;
|
||||
@ -1397,6 +1534,11 @@ static void debug_dump_real(FILE *stream, void *obj, bool first) {
|
||||
fprintf(stream, "<hashtable size=%zu count=%zu at %#jx>",
|
||||
tbl->table_size, tbl->count, (uintmax_t) obj);
|
||||
} break;
|
||||
case TYPE_USER_POINTER: {
|
||||
LispUserPointer *ptr = (LispUserPointer *) obj;
|
||||
fprintf(stream, "<user-pointer ptr=%#jx at %#jx>",
|
||||
(uintmax_t) ptr->data, (uintmax_t) obj);
|
||||
} break;
|
||||
default:
|
||||
fprintf(stream, "<object type=%ju at %#jx>",
|
||||
(uintmax_t) LISPVAL(obj)->type, (uintmax_t) obj);
|
||||
|
48
src/lisp.h
48
src/lisp.h
@ -29,6 +29,7 @@ typedef enum {
|
||||
TYPE_VECTOR,
|
||||
TYPE_FUNCTION,
|
||||
TYPE_HASHTABLE,
|
||||
TYPE_USER_POINTER,
|
||||
N_LISP_TYPES,
|
||||
} LispType;
|
||||
|
||||
@ -90,6 +91,15 @@ typedef struct {
|
||||
size_t length;
|
||||
} LispVector;
|
||||
|
||||
struct OptArgDesc {
|
||||
size_t index; // only for keywords
|
||||
LispVal *name;
|
||||
LispVal *default_form;
|
||||
LispVal *pred_var;
|
||||
};
|
||||
|
||||
void free_opt_arg_desc(void *obj);
|
||||
|
||||
typedef struct {
|
||||
LISP_OBJECT_HEADER;
|
||||
|
||||
@ -135,6 +145,14 @@ typedef struct {
|
||||
LispVal *hash_fn;
|
||||
} LispHashtable;
|
||||
|
||||
typedef struct {
|
||||
LISP_OBJECT_HEADER;
|
||||
|
||||
void *data;
|
||||
void (*free_func)(void *);
|
||||
} LispUserPointer;
|
||||
#define USERPTR(type, obj) ((type *) ((LispUserPointer *) (obj))->data)
|
||||
|
||||
// #######################
|
||||
// # nil, unbound, and t #
|
||||
// #######################
|
||||
@ -159,15 +177,16 @@ extern LispSymbol _Qt;
|
||||
// only use on symbols!
|
||||
#define VALUE_CONSTANTP(v) (((LispSymbol *) (v))->is_constant)
|
||||
|
||||
#define NILP(v) (((void *) (v)) == (void *) Qnil)
|
||||
#define STRINGP(v) (TYPEOF(v) == TYPE_STRING)
|
||||
#define SYMBOLP(v) (TYPEOF(v) == TYPE_SYMBOL)
|
||||
#define PAIRP(v) (TYPEOF(v) == TYPE_PAIR)
|
||||
#define INTEGERP(v) (TYPEOF(v) == TYPE_INTEGER)
|
||||
#define FLOATP(v) (TYPEOF(v) == TYPE_FLOAT)
|
||||
#define VECTORP(v) (TYPEOF(v) == TYPE_VECTOR)
|
||||
#define FUNCTIONP(v) (TYPEOF(v) == TYPE_FUNCTION)
|
||||
#define HASHTABLEP(v) (TYPEOF(v) == TYPE_HASHTABLE)
|
||||
#define NILP(v) (((void *) (v)) == (void *) Qnil)
|
||||
#define STRINGP(v) (TYPEOF(v) == TYPE_STRING)
|
||||
#define SYMBOLP(v) (TYPEOF(v) == TYPE_SYMBOL)
|
||||
#define PAIRP(v) (TYPEOF(v) == TYPE_PAIR)
|
||||
#define INTEGERP(v) (TYPEOF(v) == TYPE_INTEGER)
|
||||
#define FLOATP(v) (TYPEOF(v) == TYPE_FLOAT)
|
||||
#define VECTORP(v) (TYPEOF(v) == TYPE_VECTOR)
|
||||
#define FUNCTIONP(v) (TYPEOF(v) == TYPE_FUNCTION)
|
||||
#define HASHTABLEP(v) (TYPEOF(v) == TYPE_HASHTABLE)
|
||||
#define USER_POINTER_P(v) (TYPEOF(v) == TYPE_USER_POINTER)
|
||||
|
||||
#define ATOM(v) (TYPEOF(v) != TYPE_PAIR)
|
||||
|
||||
@ -328,6 +347,9 @@ void set_function_args(LispFunction *func, LispVal *args);
|
||||
LispVal *make_lisp_function(LispVal *args, LispVal *doc, LispVal *lexenv,
|
||||
LispVal *body, bool is_macro);
|
||||
LispVal *make_lisp_hashtable(LispVal *eq_fn, LispVal *hash_fn);
|
||||
LispVal *make_user_pointer(void *data, void (*free_func)(void *));
|
||||
#define ALLOC_USERPTR(type, free_func) \
|
||||
(make_user_pointer(lisp_malloc(sizeof(type)), &free_func))
|
||||
|
||||
// ########################
|
||||
// # Utility and internal #
|
||||
@ -346,7 +368,13 @@ DECLARE_FUNCTION(remhash, (LispVal * table, LispVal *key));
|
||||
DECLARE_FUNCTION(hash_table_count, (LispVal * table));
|
||||
LispVal *intern(const char *name, size_t length, bool take);
|
||||
DECLARE_FUNCTION(intern, (LispVal * name));
|
||||
#define INTERN_STATIC(name) (Fintern(STATIC_STRING(name)))
|
||||
static inline LispVal *_internal_INTERN_STATIC(const char *name, size_t len) {
|
||||
LispVal *kn = lisp_ref(make_lisp_string(name, len, true, true));
|
||||
LispVal *retval = Fintern(kn);
|
||||
lisp_unref(kn);
|
||||
return retval;
|
||||
}
|
||||
#define INTERN_STATIC(name) (_internal_INTERN_STATIC((name), sizeof(name) - 1))
|
||||
|
||||
DECLARE_FUNCTION(sethead, (LispVal * pair, LispVal *head));
|
||||
DECLARE_FUNCTION(settail, (LispVal * pair, LispVal *tail));
|
||||
|
@ -241,6 +241,7 @@ static int parse_base(size_t left, const char *c) {
|
||||
|
||||
static LispVal *read_symbol(struct ReadState *state) {
|
||||
const char *start = state->head;
|
||||
// TODO allow escaping characters
|
||||
while (!is_symbol_end(peekc(state))) {
|
||||
popc(state);
|
||||
}
|
||||
|
Reference in New Issue
Block a user