Closed dragoncoder047 closed 1 year ago
Also in for-millis
, same sort of bug but less obvious fix
object* sp_formillis (object* args, object* env) {
if (args == NULL) error2(noargument);
object* param = first(args);
unsigned long start = millis();
unsigned long now, total = 0;
- if (param != NULL) total = checkinteger(eval(first(param), env));
+ if (param != NULL) {
+ if (atom(param)) error(notalist, param);
+ total = checkinteger(eval(first(param), env));
+ }
eval(tf_progn(cdr(args),env), env);
Thanks. Will put this in next release.
It's a bit more complicated; it should also object to this:
(for-millis (500 s) (print "Go"))
Thinking about a general solution to this...
I'm thinking as a general solution, on special forms like this, you could have a function int checkparams(object* params, int min_length, int max_length)
you would call it like this:
object* params = first(args);
int len = checkparams(params, 1, 1); // For (for-millis)
// do stuff
OK, here's a general solution:
/*
checkarguments - checks the arguments list in a special form such as with-xxx,
dolist, dotimes, for-millis, etc, and returns it.
*/
object *checkarguments (object *args, int min, int max) {
if (args == NULL) error2(noargument);
args = first(args);
if (!listp(args)) error(notalist, args);
int length = 0;
object *list = args;
while (list != NULL) {
length++;
if (length > max) error(toomanyargs, args);
list = cdr(list);
}
if (length < min) error(toofewargs, args);
return args;
}
It replaces the hand-crafted tests in each of those special forms; for example:
object *sp_formillis (object *args, object *env) {
object *param = checkarguments(args, 0, 1);
unsigned long start = millis();
unsigned long now, total = 0;
if (param != NULL) total = checkinteger(eval(first(param), env));
eval(tf_progn(cdr(args),env), env);
do {
now = millis() - start;
testescape();
} while (now < total);
if (now <= INT_MAX) return number(now);
return nil;
}
I was writing that as you sent your comment! Great minds etc ...
I was thinking of something simpler:
/*
checkarguments - checks the parameters list in a special form such as with-xxx,
dolist, dotimes, for-millis, etc, and returns it.
*/
object *checkarguments (object *args, int min, int max) {
if (args == NULL) error2(noargument);
args = first(args);
if (!listp(args)) error(notalist, args);
- int length = 0;
- object *list = args;
- while (list != NULL) {
- length++;
- if (length > max) error(toomanyargs, args);
- list = cdr(list);
- }
+ int length = listlength(args);
+ if (length < min) error(toomanyargs, args);
if (length > max) error(toofewargs, args);
return args;
}
...you already have listlength()
, why not use it?
Yes, that's neater. I wanted to avoid checking the length if we'd already exceeded max, but perhaps that's unnecessary.
but perhaps that's unnecessary.
You're going to throw an error anyway, so I would agree.
These should all now be fixed in Release 4.4b - thanks for reporting them!
fix:
(and repeat similar all
with-X
forms!!)