Macro expansion!
This commit is contained in:
+67
-45
@@ -235,21 +235,6 @@ LispVal *make_builtin_function(LispVal *name, LispVal *(*cfunc)(void),
|
||||
}
|
||||
|
||||
// Calling functions
|
||||
static ALWAYS_INLINE LispVal *evaluate_function_arguments(LispVal *args) {
|
||||
LispVal *start = Qnil;
|
||||
LispVal *end = NULL;
|
||||
DOLIST(arg, args) {
|
||||
if (NILP(start)) {
|
||||
start = CONS(Feval(arg, Vlexical_environment), Qnil);
|
||||
end = start;
|
||||
} else {
|
||||
RPLACD(end, CONS(Feval(arg, Vlexical_environment), Qnil));
|
||||
end = XCDR(end);
|
||||
}
|
||||
}
|
||||
return start;
|
||||
}
|
||||
|
||||
enum ProcessArgsResult {
|
||||
PROCESS_ARGS_OK,
|
||||
PROCESS_ARGS_TOO_FEW,
|
||||
@@ -334,13 +319,7 @@ static noreturn void signal_argument_error(enum ProcessArgsResult res) {
|
||||
lisp_signal(Qargument_error, LIST(msg));
|
||||
}
|
||||
|
||||
static ALWAYS_INLINE LispVal *call_native(LispVal *orig_func,
|
||||
LispFunction *fobj, LispVal *args) {
|
||||
StackFrame *stack_ref = LISP_STACK_REF();
|
||||
if (!fobj->impl.native.no_eval_args) {
|
||||
args = evaluate_function_arguments(args);
|
||||
}
|
||||
set_stack_evaluated_args(LISP_STACK_REF(), fobj, args);
|
||||
static ALWAYS_INLINE LispVal *call_native(LispFunction *fobj, LispVal *args) {
|
||||
LispVal *arg_arr[MAX_NATIVE_FUNCTION_ARGS] = {NULL};
|
||||
size_t count = NATIVE_FUNCTION_TOTAL_ARG_COUNT(fobj);
|
||||
intptr_t rest_idx;
|
||||
@@ -381,7 +360,7 @@ static ALWAYS_INLINE LispVal *call_native(LispVal *orig_func,
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
return UNWIND_AND_RETURN(stack_ref, retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static ALWAYS_INLINE void push_optional_argument_to_lexenv(LispVal *spec,
|
||||
@@ -455,21 +434,17 @@ push_interpreted_args_to_lexenv(LispFunction *fobj, LispVal *args) {
|
||||
return PROCESS_ARGS_OK;
|
||||
}
|
||||
|
||||
static ALWAYS_INLINE LispVal *
|
||||
call_interpreted(LispVal *orig_func, LispFunction *fobj, LispVal *args) {
|
||||
StackFrame *stack_ref = LISP_STACK_REF();
|
||||
LispVal *evaled_args = evaluate_function_arguments(args);
|
||||
set_stack_evaluated_args(LISP_STACK_REF(), fobj, evaled_args);
|
||||
static ALWAYS_INLINE LispVal *call_interpreted(LispFunction *fobj,
|
||||
LispVal *args) {
|
||||
push_dynamic_binding(Qlexical_environment, fobj->impl.interp.lexenv);
|
||||
enum ProcessArgsResult par =
|
||||
push_interpreted_args_to_lexenv(fobj, evaled_args);
|
||||
enum ProcessArgsResult par = push_interpreted_args_to_lexenv(fobj, args);
|
||||
if (par != PROCESS_ARGS_OK) {
|
||||
signal_argument_error(par);
|
||||
}
|
||||
return UNWIND_AND_RETURN(stack_ref, Fprogn(fobj->impl.interp.body));
|
||||
return Fprogn(fobj->impl.interp.body);
|
||||
}
|
||||
|
||||
static LispFunction *coerce_to_function(LispVal *func) {
|
||||
LispFunction *coerce_to_function(LispVal *orig_name, LispVal *func) {
|
||||
LispFunction *fobj = func;
|
||||
if (SYMBOLP(func)) {
|
||||
fobj = Fsymbol_function(func, Qt);
|
||||
@@ -477,29 +452,39 @@ static LispFunction *coerce_to_function(LispVal *func) {
|
||||
fobj = Feval(func, Vlexical_environment);
|
||||
}
|
||||
if (NILP(fobj)) {
|
||||
lisp_signal(Qvoid_function_error, LIST(orig_name));
|
||||
} else if (!FUNCTIONP(fobj)) {
|
||||
signal_type_error(fobj, LIST(Qcallable));
|
||||
}
|
||||
// include symbol here for the error message
|
||||
CHECK_TYPE(fobj, TYPE_FUNCTION, TYPE_SYMBOL);
|
||||
assert(FUNCTIONP(fobj));
|
||||
return fobj;
|
||||
}
|
||||
|
||||
DEFUN(funcall, "funcall", (LispVal * func, LispVal *args), "(func &rest args)",
|
||||
"") {
|
||||
StackFrame *stack_ref = LISP_STACK_REF();
|
||||
push_call_frame(func, args);
|
||||
LispFunction *fobj = coerce_to_function(func);
|
||||
LispVal *raw_funcall(LispVal *func, LispVal *args) {
|
||||
assert(FUNCTIONP(func));
|
||||
LispFunction *fobj = func;
|
||||
switch (fobj->type) {
|
||||
case FUNCTION_NATIVE:
|
||||
return UNWIND_AND_RETURN(stack_ref, call_native(func, fobj, args));
|
||||
return call_native(fobj, args);
|
||||
case FUNCTION_INTERP:
|
||||
return UNWIND_AND_RETURN(stack_ref, call_interpreted(func, fobj, args));
|
||||
return call_interpreted(fobj, args);
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
DEFUN(funcall, "funcall", (LispVal * func, LispVal *args), "(func &rest args)",
|
||||
"") {
|
||||
LispVal *res = coerce_to_function(func, func);
|
||||
if (!NILP(Fspecial_form_p(res))) {
|
||||
signal_type_error(res, Qfunction);
|
||||
}
|
||||
StackFrame *stack_ref = LISP_STACK_REF();
|
||||
push_call_frame(func, args);
|
||||
set_stack_evaluated_args(LISP_STACK_REF(), res, args);
|
||||
return UNWIND_AND_RETURN(stack_ref, raw_funcall(res, args));
|
||||
}
|
||||
|
||||
static LispVal *parse_lambda_declare_form(LispFunction *fobj, LispVal *body) {
|
||||
while (CONSP(body) && CONSP(XCAR(body)) && EQ(XCAR(XCAR(body)), Qdeclare)) {
|
||||
LispVal *decls = XCDR(XCAR(body));
|
||||
@@ -519,6 +504,18 @@ static LispVal *parse_lambda_declare_form(LispFunction *fobj, LispVal *body) {
|
||||
return body;
|
||||
}
|
||||
|
||||
static void macroexpand_lambda_list(struct LambdaList *restrict ll) {
|
||||
DOLIST(ent, ll->opt) {
|
||||
RPLACA(XCDR(ent), Fmacroexpand_all(SECOND(ent), Qnil));
|
||||
}
|
||||
if (HASH_TABLE_P(ll->kw)) {
|
||||
HT_FOREACH_INDEX(ll->kw, i) {
|
||||
LispVal *ent = HASH_VALUE(ll->kw, i);
|
||||
RPLACA(XCDR(XCDR(ent)), Fmacroexpand_all(THIRD(ent), Qnil));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DEFSPECIAL(lambda, "lambda", (LispVal * args, LispVal *body),
|
||||
"(args &rest body)", "") {
|
||||
LambdaListParseResult llpr;
|
||||
@@ -542,7 +539,8 @@ DEFSPECIAL(lambda, "lambda", (LispVal * args, LispVal *body),
|
||||
fobj->docstr = Qnil;
|
||||
}
|
||||
body = parse_lambda_declare_form(fobj, body);
|
||||
fobj->impl.interp.body = body;
|
||||
macroexpand_lambda_list(&fobj->args);
|
||||
fobj->impl.interp.body = macroexpand_list(body, Qnil);
|
||||
fobj->impl.interp.lexenv = Vlexical_environment;
|
||||
return fobj;
|
||||
}
|
||||
@@ -556,8 +554,9 @@ DEFUN(callablep, "callablep", (LispVal * obj), "(obj)", "") {
|
||||
}
|
||||
|
||||
DEFUN(function_arity, "function-arity", (LispVal * func), "(func)",
|
||||
"Return a list of the form (NUM-REQ NUM-OPT KW-NAMES HAS-REST).") {
|
||||
LispFunction *fobj = coerce_to_function(func);
|
||||
"Return a list of the form (NUM-REQ NUM-OPT KW-NAMES ALLOW-OTHER-KEYS "
|
||||
"HAS-REST).") {
|
||||
LispFunction *fobj = coerce_to_function(func, func);
|
||||
LispVal *kw = Qnil;
|
||||
if (HASH_TABLE_P(fobj->args.kw)) {
|
||||
HT_FOREACH_INDEX(fobj->args.kw, i) {
|
||||
@@ -565,7 +564,28 @@ DEFUN(function_arity, "function-arity", (LispVal * func), "(func)",
|
||||
}
|
||||
}
|
||||
return LIST(MAKE_FIXNUM(fobj->args.n_req), MAKE_FIXNUM(fobj->args.n_opt),
|
||||
kw, NILP(fobj->args.rest) ? Qnil : Qt);
|
||||
kw, fobj->args.allow_other_keys ? Qt : Qnil,
|
||||
NILP(fobj->args.rest) ? Qnil : Qt);
|
||||
}
|
||||
|
||||
bool builtin_function_p(LispVal *val, bool special_form) {
|
||||
if (SYMBOLP(val)) {
|
||||
val = Fsymbol_function(val, Qt);
|
||||
}
|
||||
if (FUNCTIONP(val)) {
|
||||
LispFunction *fobj = val;
|
||||
return fobj->type == FUNCTION_NATIVE
|
||||
&& fobj->impl.native.no_eval_args == special_form;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
DEFUN(builtin_function_p, "builtin-function-p", (LispVal * val), "(val)", "") {
|
||||
return builtin_function_p(val, false) ? Qt : Qnil;
|
||||
}
|
||||
|
||||
DEFUN(special_form_p, "special-form-p", (LispVal * val), "(val)", "") {
|
||||
return builtin_function_p(val, true) ? Qt : Qnil;
|
||||
}
|
||||
|
||||
DEFINE_SYMBOL(declare, "declare");
|
||||
@@ -574,6 +594,8 @@ DEFINE_SYMBOL(name, "name");
|
||||
DEFINE_SYMBOL(callable, "callable");
|
||||
DEFINE_SYMBOL(argument_error, "argument-error");
|
||||
DEFINE_CONDITION_CLASS(argument_error, error);
|
||||
DEFINE_SYMBOL(void_function_error, "void-function-error");
|
||||
DEFINE_CONDITION_CLASS(void_function_error, error);
|
||||
|
||||
DEFINE_SYMBOL(function_definition_error, "function-definition-error");
|
||||
DEFINE_CONDITION_CLASS(function_definition_error, error);
|
||||
|
||||
Reference in New Issue
Block a user