Test suite oddity


#1

I’m making some rather … pervasive changes to uLisp, and for obvious reasons want to sanity-check that things are still working every now and then. So I ran the 32-bit test suite on one of the ARM boards I have to hand. (I’ve managed to make uLisp fifty bytes or so too large for the ATmega328P. I’m working on it!)

Anyway. I get errors on two specific tests:

(aeq 'mapcan '(1 2 3 . 4) (mapcan (lambda (x) x) '((1) (2) (3 . 4))))
(aeq 'mapcan '(2 3 . 4) (mapcan (lambda (x) x) '(nil (2) (3 . 4))))

The error itself is a little curious, though: Error: 'mapcan' result is not a proper list: 4

Correct me if I’m wrong, but aren’t those tests explicitly building a dotted list?

A little off-topic, but hilarious: The error is generated by a line of code that seems otherwise unneeded. I commented it out, and the tests work. The error string is only ever used there, and now the compiler doesn’t bother including it in the image. And now my code does fit on the Arduino Uno. Yay!


#2

You’ve raised several interesting points!

First, you’re correct that the two tests should work without an error:

> (mapcan (lambda (x) x) '((1) (2) (3 . 4)))
(1 2 3 . 4)

> (mapcan (lambda (x) x) '(nil (2) (3 . 4)))
(2 3 . 4)

The error is generated by a line of code that seems otherwise unneeded.

I’m not sure which one you’re referring to, but the error check is still needed for mapcar; for example:

(mapcar (lambda (x) x) '(1 2 3 . 4))

I need to think about how to solve that.

I’ve managed to make uLisp fifty bytes or so too large for the ATmega328P

I had the same problem after making some bug fixes for the next release; try the following:

Replace the definitions of atom() and improperp() with:

#define atom(x) (!consp(x))

#define improperp(x) (!listp(x))

#3

The one I’m talking about is only in the mapcan path, though. Specifically:

void mapcanfun (object *result, object **tail) {
  while (consp(result)) {
    cdr(*tail) = result; *tail = result;
    result = cdr(result);
  }
  if (result != NULL) error(MAPCAN, resultproper, result); // It's this one.
}

That error message isn’t used anywhere else, either.

I’ll look at it. Part of what I’m doing is trying to make it easier to skip portions of uLisp in a build, partly because of how close to the Uno’s limits it has gotten.


#4

Thanks - I’ll investigate.


#5

Like I said, commenting that line out got the tests to work, and allowed me to get the version I had to run on an Arduino Uno. Turns out I had a little debugging to do on the AVR version, so I added a single function call. It results in the best report from the build process I’ve ever seen:

Sketch uses 32256 bytes (100%) of program storage space. Maximum is 32256 bytes.

#6

As you said, this should evaluate without error:

> (mapcan (lambda (x) x) '(nil (2) (3 . 4)))
(2 3 . 4)

However this should give an error:

(mapcan (lambda (x) x) '(nil (2 . 3) (4)))

Here’s a fixed version of mapcanfun() that achieves this:

void mapcanfun (object *result, object **tail) {
  if (cdr(*tail) != NULL) error(MAPCAN, notproper, *tail);
  while (consp(result)) {
    cdr(*tail) = result; *tail = result;
    result = cdr(result);
  }
}

I hope it doesn’t make your ATmega328P code go over the 100% mark!

In future I’ll include the latest test suites on the GitHub build system repository. I usually add tests to check for each bug fix in the latest release, so it makes sense to synchronise them.


#7

By six bytes. 😀

I haven’t applied the function-to-macro suggestions you made, so it can almost certainly be fixed.


#8

This is fixed in uLisp 3.5.


#9