Fix some bugs
This commit is contained in:
+24
-2
@@ -245,6 +245,7 @@ enum ProcessArgsResult {
|
||||
PROCESS_ARGS_TOO_MANY,
|
||||
PROCESS_ARGS_NO_KEY_VALUE,
|
||||
PROCESS_ARGS_BAD_KEY,
|
||||
PROCESS_ARGS_DOTTED,
|
||||
PROCESS_ARGS_N_ERRORS,
|
||||
};
|
||||
|
||||
@@ -255,6 +256,7 @@ static const char *process_args_strerror(enum ProcessArgsResult status) {
|
||||
[PROCESS_ARGS_TOO_MANY] = "Too many arguments",
|
||||
[PROCESS_ARGS_NO_KEY_VALUE] = "Key without a value",
|
||||
[PROCESS_ARGS_BAD_KEY] = "Unknown key",
|
||||
[PROCESS_ARGS_DOTTED] = "Dotted argument list",
|
||||
};
|
||||
return MSGS[status];
|
||||
}
|
||||
@@ -276,6 +278,8 @@ process_complex_native_args(LispFunction *fobj, LispVal *args,
|
||||
while (rem_req--) {
|
||||
if (NILP(args)) {
|
||||
return PROCESS_ARGS_TOO_FEW;
|
||||
} else if (!CONSP(args)) {
|
||||
return PROCESS_ARGS_DOTTED;
|
||||
}
|
||||
out[idx++] = XCAR(args);
|
||||
args = XCDR(args);
|
||||
@@ -283,6 +287,8 @@ process_complex_native_args(LispFunction *fobj, LispVal *args,
|
||||
while (rem_opt--) {
|
||||
if (NILP(args)) {
|
||||
return PROCESS_ARGS_OK;
|
||||
} else if (!CONSP(args)) {
|
||||
return PROCESS_ARGS_DOTTED;
|
||||
}
|
||||
out[idx++] = XCAR(args);
|
||||
args = XCDR(args);
|
||||
@@ -291,6 +297,9 @@ process_complex_native_args(LispFunction *fobj, LispVal *args,
|
||||
return PROCESS_ARGS_TOO_MANY;
|
||||
}
|
||||
if (!NILP(fobj->args.rest)) {
|
||||
if (!LISTP(args) || !NILP(Fdotted_list_p(args))) {
|
||||
return PROCESS_ARGS_DOTTED;
|
||||
}
|
||||
*rest_idx = idx;
|
||||
out[idx++] = args;
|
||||
} else {
|
||||
@@ -300,7 +309,9 @@ process_complex_native_args(LispFunction *fobj, LispVal *args,
|
||||
return PROCESS_ARGS_OK;
|
||||
}
|
||||
while (!NILP(args)) {
|
||||
if (NILP(XCDR(args))) {
|
||||
if (!CONSP(args)) {
|
||||
return PROCESS_ARGS_DOTTED;
|
||||
} else if (NILP(XCDR(args))) {
|
||||
return PROCESS_ARGS_NO_KEY_VALUE;
|
||||
}
|
||||
LispVal *entry = Fgethash(fobj->args.kw, XCAR(args), Qnil);
|
||||
@@ -390,12 +401,17 @@ push_interpreted_args_to_lexenv(LispFunction *fobj, LispVal *args) {
|
||||
while (!NILP(rem_req)) {
|
||||
if (NILP(args)) {
|
||||
return PROCESS_ARGS_TOO_FEW;
|
||||
} else if (!CONSP(args)) {
|
||||
return PROCESS_ARGS_DOTTED;
|
||||
}
|
||||
new_lexical_variable(XCAR(rem_req), XCAR(args));
|
||||
args = XCDR(args);
|
||||
rem_req = XCDR(rem_req);
|
||||
}
|
||||
while (!NILP(rem_opt) && !NILP(args)) {
|
||||
if (!CONSP(args)) {
|
||||
return PROCESS_ARGS_DOTTED;
|
||||
}
|
||||
push_optional_argument_to_lexenv(XCAR(rem_opt), XCAR(args));
|
||||
args = XCDR(args);
|
||||
rem_opt = XCDR(rem_opt);
|
||||
@@ -405,6 +421,9 @@ push_interpreted_args_to_lexenv(LispFunction *fobj, LispVal *args) {
|
||||
rem_opt = XCDR(rem_opt);
|
||||
}
|
||||
if (!NILP(fobj->args.rest)) {
|
||||
if (!LISTP(args) || !NILP(Fdotted_list_p(args))) {
|
||||
return PROCESS_ARGS_DOTTED;
|
||||
}
|
||||
new_lexical_variable(fobj->args.rest, args);
|
||||
}
|
||||
if (NILP(fobj->args.kw)) {
|
||||
@@ -413,6 +432,9 @@ push_interpreted_args_to_lexenv(LispFunction *fobj, LispVal *args) {
|
||||
}
|
||||
LispVal *seen_kw = make_hash_table_no_gc(Qnil, Qnil);
|
||||
while (!NILP(args)) {
|
||||
if (!CONSP(args)) {
|
||||
return PROCESS_ARGS_DOTTED;
|
||||
}
|
||||
if (NILP(XCDR(args))) {
|
||||
release_hash_table_no_gc(seen_kw);
|
||||
return PROCESS_ARGS_NO_KEY_VALUE;
|
||||
@@ -494,7 +516,7 @@ DEFUN(apply, "apply", (LispVal * func, LispVal *args), "(func &rest args)",
|
||||
if (NILP(args)) {
|
||||
return CALL0(func);
|
||||
}
|
||||
if (NILP(Fproper_list_p(XCDR(Flast(args))))) {
|
||||
if (NILP(Fproper_list_p(XCAR(Flast(args))))) {
|
||||
signal_type_error(args, Qlist);
|
||||
}
|
||||
return Ffuncall(func, Flist_star(XCAR(args), XCDR(args)));
|
||||
|
||||
+33
-7
@@ -105,8 +105,7 @@ DEFSPECIAL(setq, "setq", (LispVal * bindings), "(&rest bindings)", "") {
|
||||
LIST(LISP_LITSTR("Wrong number of arguments.")));
|
||||
}
|
||||
LispVal *value = Qnil;
|
||||
for (LispVal *rest = bindings; !NILP(bindings);
|
||||
bindings = XCDR(XCDR(bindings))) {
|
||||
for (LispVal *rest = bindings; !NILP(rest); rest = XCDR(XCDR(rest))) {
|
||||
LispVal *name = FIRST(rest);
|
||||
value = eval(SECOND(rest));
|
||||
set_lexical_variable(name, value);
|
||||
@@ -118,14 +117,16 @@ DEFSPECIAL(let, "let", (LispVal * bindings, LispVal *body),
|
||||
"(bindings &rest body)", "") {
|
||||
CHECK_LISTP(bindings);
|
||||
StackFrame *stack_ref = LISP_STACK_REF();
|
||||
DOLIST(binding, bindings) {
|
||||
bindings = Fcopy_list(bindings);
|
||||
DOTAILS(rest, bindings) {
|
||||
LispVal *binding = XCAR(rest);
|
||||
if (CONSP(binding) && list_length_eq(binding, 2)) {
|
||||
if (!SYMBOLP(XCAR(binding))) {
|
||||
signal_type_error(XCAR(binding), LIST(Qsymbol));
|
||||
}
|
||||
CHECK_TYPE(XCAR(binding), TYPE_SYMBOL);
|
||||
binding = Fcopy_list(binding);
|
||||
RPLACA(rest, binding);
|
||||
RPLACA(XCDR(binding), eval(SECOND(binding)));
|
||||
} else if (!SYMBOLP(binding)) {
|
||||
signal_type_error(binding, LIST(Qsymbol));
|
||||
signal_type_error(binding, LIST(Qsymbol, Qlist));
|
||||
}
|
||||
}
|
||||
push_copy_lexenv();
|
||||
@@ -140,6 +141,23 @@ DEFSPECIAL(let, "let", (LispVal * bindings, LispVal *body),
|
||||
return UNWIND_AND_RETURN(stack_ref, Fprogn(body));
|
||||
}
|
||||
|
||||
DEFSPECIAL(let_star, "let*", (LispVal * bindings, LispVal *body),
|
||||
"(bindings &rest body)", "") {
|
||||
CHECK_LISTP(bindings);
|
||||
StackFrame *stack_ref = LISP_STACK_REF();
|
||||
DOLIST(binding, bindings) {
|
||||
if (CONSP(binding) && list_length_eq(binding, 2)) {
|
||||
CHECK_TYPE(XCAR(binding), TYPE_SYMBOL);
|
||||
new_lexical_variable(FIRST(binding), eval(SECOND(binding)));
|
||||
} else if (SYMBOLP(binding)) {
|
||||
new_lexical_variable(binding, Qnil);
|
||||
} else {
|
||||
signal_type_error(binding, LIST(Qsymbol, Qlist));
|
||||
}
|
||||
}
|
||||
return UNWIND_AND_RETURN(stack_ref, Fprogn(body));
|
||||
}
|
||||
|
||||
DEFSPECIAL(if, "if", (LispVal * cond, LispVal *then, LispVal *otherwise),
|
||||
"(cond then &rest else)", "") {
|
||||
StackFrame *stack_ref = LISP_STACK_REF();
|
||||
@@ -180,6 +198,14 @@ DEFUN(not, "not", (LispVal * datum), "(datum)", "") {
|
||||
return NILP(datum) ? Qt : Qnil;
|
||||
}
|
||||
|
||||
DEFSPECIAL(while, "while", (LispVal * cond, LispVal *body), "(cond &rest body)",
|
||||
"") {
|
||||
while (!NILP(eval(cond))) {
|
||||
Fprogn(body);
|
||||
}
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
DEFSPECIAL(block, "block", (LispVal * name, LispVal *body), "(name &rest body)",
|
||||
"") {
|
||||
CHECK_TYPE(name, TYPE_SYMBOL);
|
||||
|
||||
@@ -8,11 +8,13 @@ DECLARE_FUNCTION(eval, (LispVal * form, LispVal *lexenv));
|
||||
DECLARE_FUNCTION(progn, (LispVal * forms));
|
||||
DECLARE_FUNCTION(setq, (LispVal * bindings));
|
||||
DECLARE_FUNCTION(let, (LispVal * bindings, LispVal *body));
|
||||
DECLARE_FUNCTION(let_star, (LispVal * bindings, LispVal *body));
|
||||
DECLARE_FUNCTION(if, (LispVal * cond, LispVal *then, LispVal *otherwise));
|
||||
DECLARE_FUNCTION(and, (LispVal * forms));
|
||||
DECLARE_FUNCTION(or, (LispVal * forms));
|
||||
DECLARE_FUNCTION(null, (LispVal * datum));
|
||||
DECLARE_FUNCTION(not, (LispVal * datum));
|
||||
DECLARE_FUNCTION(while, (LispVal * cond, LispVal *body));
|
||||
|
||||
DECLARE_FUNCTION(block, (LispVal * name, LispVal *body));
|
||||
DECLARE_FUNCTION(return_from, (LispVal * name, LispVal *value));
|
||||
|
||||
+14
@@ -53,6 +53,20 @@ DEFUN(cdr, "cdr", (LispVal * list), "(list)", "") {
|
||||
return NILP(list) ? Qnil : XCDR(list);
|
||||
}
|
||||
|
||||
DEFUN(rplaca, "rplaca", (LispVal * cons, LispVal *newcar), "(cons newcar)",
|
||||
"") {
|
||||
CHECK_TYPE(cons, TYPE_CONS);
|
||||
RPLACA(cons, newcar);
|
||||
return newcar;
|
||||
}
|
||||
|
||||
DEFUN(rplacd, "rplacd", (LispVal * cons, LispVal *newcdr), "(cons newcdr)",
|
||||
"") {
|
||||
CHECK_TYPE(cons, TYPE_CONS);
|
||||
RPLACD(cons, newcdr);
|
||||
return newcdr;
|
||||
}
|
||||
|
||||
DEFUN(length_eq, "length=", (LispVal * list, LispVal *length), "(list length)",
|
||||
"Return non-nil if LIST's length is LENGTH.") {
|
||||
CHECK_LISTP(list);
|
||||
|
||||
@@ -125,6 +125,8 @@ DECLARE_FUNCTION(atom, (LispVal * val));
|
||||
DECLARE_FUNCTION(cons, (LispVal * car, LispVal *cdr));
|
||||
DECLARE_FUNCTION(car, (LispVal * list));
|
||||
DECLARE_FUNCTION(cdr, (LispVal * list));
|
||||
DECLARE_FUNCTION(rplaca, (LispVal * cons, LispVal *newcar));
|
||||
DECLARE_FUNCTION(rplacd, (LispVal * cons, LispVal *newcdr));
|
||||
DECLARE_FUNCTION(length_eq, (LispVal * list, LispVal *length));
|
||||
DECLARE_FUNCTION(nreverse, (LispVal * list));
|
||||
DECLARE_FUNCTION(last, (LispVal * list));
|
||||
|
||||
+5
-2
@@ -52,6 +52,9 @@ DEFUN(macroexpand_toplevel, "macroexpand-toplevel",
|
||||
}
|
||||
|
||||
LispVal *macroexpand_list(LispVal *list, LispVal *lexical_macros) {
|
||||
if (!CONSP(list)) {
|
||||
return list;
|
||||
}
|
||||
LispVal *start = Qnil;
|
||||
LispVal *end = NULL;
|
||||
DOTAILS(rest, list) {
|
||||
@@ -103,7 +106,7 @@ static LispVal *macroexpand_special_form(LispVal *fobj, LispVal *form,
|
||||
return macroexpand_lambda_form(form, lexical_macros);
|
||||
} else if (IS(quote) || IS(function)) {
|
||||
return form;
|
||||
} else if (IS(progn) || IS(if) || IS(and) || IS(or)) {
|
||||
} else if (IS(progn) || IS(if) || IS(and) || IS(or) || IS(while)) {
|
||||
if (LISTP(XCDR(form))) {
|
||||
return CONS(XCAR(form),
|
||||
macroexpand_list(XCDR(form), lexical_macros));
|
||||
@@ -119,7 +122,7 @@ static LispVal *macroexpand_special_form(LispVal *fobj, LispVal *form,
|
||||
expand = !expand;
|
||||
}
|
||||
return CONS(XCAR(form), args);
|
||||
} else if (IS(let)) {
|
||||
} else if (IS(let) || IS(let_star)) {
|
||||
if (!CONSP(XCDR(form))) {
|
||||
return form;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user