That’s a very good explanation and now I understand how to work with ulisp streams better than I did before. with-input-from-string looks really useful. That said I have several requests and questions. The first thing I thought of was having a function that let you read up to your chosen delimeter instead of just a newline. It turns out ulisp has this internally as readstring but its not exposed. So here’s my attempt at providing it:
object *fn_readuntil (object *args, object *env) {
(void) env;
object *obj = first(args);
gfun_t gfun = gstreamfun(rest(args));
char delim = checkchar(obj);
return readstring(delim, false, gfun);
}
const char string_readuntil[] PROGMEM = "read-until";
const char docreaduntil[] PROGMEM = "(read-until delim [stream])\n"
"Reads characters from the serial input up to the specifed delimiter character,\n"
"and returns them as a string, excluding the delimiter.\n"
"If stream is specified the line is read from the specified stream.";
//const tbl_entry_t lookup_table2[] PROGMEM = {
{ string_readuntil, fn_readuntil, 0212, docreaduntil },
//};
My second issue is with the way read-line (and read-until) handles string streams that don’t terminate in a newline (or delimiter), where they will show an error and return nothing. I’m not sure if that’s the most useful behavior because I would think that not finding a line or delimiter would be something that the function would expect. I suppose one can always append a newline or delimiter to the end if they don’t want the function to fail, but that seems awkward. I don’t know how to handle that scenario any better though, and that seems to be how Common Lisp handles it as well? For Arduino you get functions like find, findUntil, peek, and available. Would it make sense to implement that functionality here to help deal with that? Or what’s a good way to deal with this?