diff --git a/ulisp-arm.ino b/ulisp-arm.ino index 2d8098c..9319b1e 100644 --- a/ulisp-arm.ino +++ b/ulisp-arm.ino @@ -1,5 +1,5 @@ -/* uLisp ARM 2.7c - www.ulisp.com - David Johnson-Davies - www.technoblogy.com - 20th June 2019 +/* uLisp ARM 2.8 - www.ulisp.com + David Johnson-Davies - www.technoblogy.com - 20th July 2019 Licensed under the MIT license: https://opensource.org/licenses/MIT */ @@ -204,8 +204,8 @@ void printobject (object *form, pfun_t pfun); char *lookupbuiltin (symbol_t name); intptr_t lookupfn (symbol_t name); int builtin (char* n); -void error (const char *string); -void error3 (symbol_t name, const char *string); +void error (symbol_t fname, PGM_P string, object *symbol); +void error2 (symbol_t fname, PGM_P string); // Set up workspace @@ -221,7 +221,7 @@ void initworkspace () { } object *myalloc () { - if (Freespace == 0) error(PSTR("No room")); + if (Freespace == 0) error2(0, PSTR("no room")); object *temp = Freelist; Freelist = cdr(Freelist); Freespace--; @@ -525,8 +525,8 @@ int saveimage (object *arg) { file = SD.open(MakeFilename(arg), O_RDWR | O_CREAT | O_TRUNC); arg = NULL; } else if (arg == NULL || listp(arg)) file = SD.open("ULISP.IMG", O_RDWR | O_CREAT | O_TRUNC); - else error3(SAVEIMAGE, PSTR("illegal argument")); - if (!file) error(PSTR("Problem saving to SD card")); + else error(SAVEIMAGE, PSTR("illegal argument"), arg); + if (!file) error2(SAVEIMAGE, PSTR("problem saving to SD card")); SDWriteInt(file, (uintptr_t)arg); SDWriteInt(file, imagesize); SDWriteInt(file, (uintptr_t)GlobalEnv); @@ -543,16 +543,11 @@ int saveimage (object *arg) { file.close(); return imagesize; #elif defined(ARDUINO_METRO_M4) || defined(ARDUINO_ITSYBITSY_M4) || defined(ARDUINO_FEATHER_M4) - if (!(arg == NULL || listp(arg))) error3(SAVEIMAGE, PSTR("illegal argument")); - if (!FlashSetup()) error(PSTR("No DataFlash found.")); + if (!(arg == NULL || listp(arg))) error(SAVEIMAGE, PSTR("illegal argument"), arg); + if (!FlashSetup()) error2(SAVEIMAGE, PSTR("no DataFlash found.")); // Save to DataFlash int bytesneeded = imagesize*8 + SYMBOLTABLESIZE + 20; - if (bytesneeded > FLASHSIZE) { - pfstring(PSTR("Error: Image size too large: "), pserial); - pint(imagesize, pserial); pln(pserial); - GCStack = NULL; - longjmp(exception, 1); - } + if (bytesneeded > FLASHSIZE) error(SAVEIMAGE, PSTR("image size too large"), number(imagesize)); unsigned int addr = 0; FlashBeginWrite(); FlashWriteInt(&addr, (uintptr_t)arg); @@ -572,7 +567,7 @@ int saveimage (object *arg) { return imagesize; #else (void) arg; - error(PSTR("save-image not available")); + error2(SAVEIMAGE, PSTR("not available")); return 0; #endif } @@ -597,8 +592,8 @@ int loadimage (object *arg) { File file; if (stringp(arg)) file = SD.open(MakeFilename(arg)); else if (arg == NULL) file = SD.open("/ULISP.IMG"); - else error3(LOADIMAGE, PSTR("illegal argument")); - if (!file) error(PSTR("Problem loading from SD card")); + else error(LOADIMAGE, PSTR("illegal argument"), arg); + if (!file) error2(LOADIMAGE, PSTR("problem loading from SD card")); SDReadInt(file); int imagesize = SDReadInt(file); GlobalEnv = (object *)SDReadInt(file); @@ -616,11 +611,11 @@ int loadimage (object *arg) { gc(NULL, NULL); return imagesize; #elif defined(ARDUINO_METRO_M4) || defined(ARDUINO_ITSYBITSY_M4) || defined(ARDUINO_FEATHER_M4) - if (!FlashSetup()) error(PSTR("No DataFlash found.")); + if (!FlashSetup()) error2(LOADIMAGE, PSTR("no DataFlash found.")); FlashBeginRead(); FlashReadInt(); // Skip eval address int imagesize = FlashReadInt(); - if (imagesize == 0 || imagesize == 0xFFFF) error(PSTR("No saved image")); + if (imagesize == 0 || imagesize == 0xFFFF) error2(LOADIMAGE, PSTR("no saved image")); GlobalEnv = (object *)FlashReadInt(); GCStack = (object *)FlashReadInt(); #if SYMBOLTABLESIZE > BUFFERSIZE @@ -637,7 +632,7 @@ int loadimage (object *arg) { return imagesize; #else (void) arg; - error(PSTR("load-image not available")); + error2(LOADIMAGE, PSTR("not available")); return 0; #endif } @@ -646,53 +641,64 @@ void autorunimage () { #if defined(sdcardsupport) SD.begin(SDCARD_SS_PIN); File file = SD.open("ULISP.IMG"); - if (!file) error(PSTR("Error: Problem autorunning from SD card")); + if (!file) error2(0, PSTR("problem autorunning from SD card")); object *autorun = (object *)SDReadInt(file); file.close(); if (autorun != NULL) { loadimage(NULL); - apply(autorun, NULL, NULL); + apply(0, autorun, NULL, NULL); } #elif defined(ARDUINO_METRO_M4) || defined(ARDUINO_ITSYBITSY_M4) || defined(ARDUINO_FEATHER_M4) - if (!FlashSetup()) error(PSTR("No DataFlash found.")); + if (!FlashSetup()) error2(0, PSTR("no DataFlash found.")); FlashBeginRead(); object *autorun = (object *)FlashReadInt(); FlashEndRead(); if (autorun != NULL && (unsigned int)autorun != 0xFFFF) { loadimage(nil); - apply(autorun, NULL, NULL); + apply(0, autorun, NULL, NULL); } #else - error(PSTR("autorun not available")); + error2(0, PSTR("autorun not available")); #endif } // Error handling -void error (PGM_P string) { +void errorsub (symbol_t fname, PGM_P string) { pfl(pserial); pfstring(PSTR("Error: "), pserial); - pfstring(string, pserial); pln(pserial); + if (fname) { + pserial('\''); + pstring(symbolname(fname), pserial); + pfstring(PSTR("' "), pserial); + } + pfstring(string, pserial); +} + +void error (symbol_t fname, PGM_P string, object *symbol) { + errorsub(fname, string); + pfstring(PSTR(": "), pserial); printobject(symbol, pserial); + pln(pserial); GCStack = NULL; longjmp(exception, 1); } -void error2 (object *symbol, PGM_P string) { - pfl(pserial); pfstring(PSTR("Error: "), pserial); - if (symbol == NULL) pfstring(PSTR("function "), pserial); - else { pserial('\''); printobject(symbol, pserial); pfstring(PSTR("' "), pserial); } - pfstring(string, pserial); pln(pserial); +void error2 (symbol_t fname, PGM_P string) { + errorsub(fname, string); + pln(pserial); GCStack = NULL; longjmp(exception, 1); } -void error3 (symbol_t name, PGM_P string) { - pfl(pserial); pfstring(PSTR("Error: "), pserial); - if (symbol == NULL) pfstring(PSTR("function "), pserial); - else { pserial('\''); pstring(lookupbuiltin(name), pserial); pfstring(PSTR("' "), pserial); } - pfstring(string, pserial); pln(pserial); - GCStack = NULL; - longjmp(exception, 1); -} +// Save space as these are used multiple times +const char notanumber[] PROGMEM = "argument is not a number"; +const char notastring[] PROGMEM = "argument is not a string"; +const char notalist[] PROGMEM = "argument is not a list"; +const char notproper[] PROGMEM = "argument is not a proper list"; +const char notproper2[] PROGMEM = "second argument is not a proper list"; +const char notproper3[] PROGMEM = "third argument is not a proper list"; +const char noargument[] PROGMEM = "missing argument"; +const char nostream[] PROGMEM = "missing stream argument"; +const char overflow[] PROGMEM = "arithmetic overflow"; // Tracing @@ -706,13 +712,13 @@ boolean tracing (symbol_t name) { } void trace (symbol_t name) { - if (tracing(name)) error(PSTR("Already being traced")); + if (tracing(name)) error(TRACE, PSTR("already being traced"), symbol(name)); int i = 0; while (i < TRACEMAX) { if (TraceFn[i] == 0) { TraceFn[i] = name; TraceDepth[i] = 0; return; } i++; } - error(PSTR("Already tracing 3 functions")); + error2(TRACE, PSTR("already tracing 3 functions")); } void untrace (symbol_t name) { @@ -721,7 +727,7 @@ void untrace (symbol_t name) { if (TraceFn[i] == name) { TraceFn[i] = 0; return; } i++; } - error(PSTR("It wasn't being traced")); + error(UNTRACE, PSTR("not tracing"), symbol(name)); } // Helper functions @@ -745,6 +751,7 @@ boolean listp (object *x) { } boolean improperp (object *x) { + if (x == NULL) return false; unsigned int type = x->type; return type < PAIR && type != ZERO; } @@ -778,9 +785,7 @@ int digitvalue (char d) { return 16; } -char *name (object *obj){ - if (obj->type != SYMBOL) error(PSTR("Error in name")); - symbol_t x = obj->name; +char *symbolname (symbol_t x) { if (x < ENDFUNCTIONS) return lookupbuiltin(x); else if (x >= 64000) return lookupsymbol(x); char *buffer = SymbolTop; @@ -792,29 +797,24 @@ char *name (object *obj){ return buffer; } -int integer (object *obj){ - if (!integerp(obj)) error2(obj, PSTR("is not an integer")); +int checkinteger (symbol_t name, object *obj) { + if (!integerp(obj)) error(name, PSTR("argument is not an integer"), obj); return obj->integer; } -float fromfloat (object *obj){ - if (!floatp(obj)) error2(obj, PSTR("is not a float")); - return obj->single_float; -} - -float intfloat (object *obj){ +float checkintfloat (symbol_t name, object *obj){ if (integerp(obj)) return obj->integer; - if (!floatp(obj)) error2(obj, PSTR("is not an integer or float")); - return obj->single_float; + if (floatp(obj)) return obj->single_float; + error(name, notanumber, obj); } -int fromchar (object *obj){ - if (!characterp(obj)) error2(obj, PSTR("is not a character")); +int checkchar (symbol_t name, object *obj) { + if (!characterp(obj)) error(name, PSTR("argument is not a character"), obj); return obj->integer; } -int istream (object *obj){ - if (!streamp(obj)) error2(obj, PSTR("is not a stream")); +int isstream (object *obj){ + if (!streamp(obj)) error(0, PSTR("not a stream"), obj); return obj->integer; } @@ -822,6 +822,13 @@ int issymbol (object *obj, symbol_t n) { return symbolp(obj) && obj->name == n; } +void checkargs (symbol_t name, object *args) { + int nargs = listlength(name, args); + if (name >= ENDFUNCTIONS) error(0, PSTR("not valid here"), symbol(name)); + if (nargslookupmax(name)) error2(name, PSTR("has too many arguments")); +} + int eq (object *arg1, object *arg2) { if (arg1 == arg2) return true; // Same object if ((arg1 == nil) || (arg2 == nil)) return false; // Not both values @@ -833,10 +840,10 @@ int eq (object *arg1, object *arg2) { return false; } -int listlength (object *list) { +int listlength (symbol_t name, object *list) { int length = 0; while (list != NULL) { - if (improperp(list)) error(PSTR("List argument is not a proper list")); + if (improperp(list)) error2(name, notproper); list = cdr(list); length++; } @@ -847,9 +854,9 @@ int listlength (object *list) { object *assoc (object *key, object *list) { while (list != NULL) { - if (improperp(list)) error3(ASSOC, PSTR("argument is not a proper list")); + if (improperp(list)) error(ASSOC, notproper, list); object *pair = first(list); - if (!listp(pair)) error2(pair, PSTR("in 'assoc' is not a list")); + if (!listp(pair)) error(ASSOC, PSTR("element is not a list"), pair); if (pair != NULL && eq(key,car(pair))) return pair; list = cdr(list); } @@ -954,19 +961,19 @@ object *findvalue (object *var, object *env) { symbol_t varname = var->name; object *pair = value(varname, env); if (pair == NULL) pair = value(varname, GlobalEnv); - if (pair == NULL) error2(var, PSTR("unknown variable")); + if (pair == NULL) error(0, PSTR("unknown variable"), var); return pair; } // Handling closures -object *closure (int tc, object *fname, object *state, object *function, object *args, object **env) { +object *closure (int tc, symbol_t name, object *state, object *function, object *args, object **env) { int trace = 0; - if (fname != NULL) trace = tracing(fname->name); + if (name) trace = tracing(name); if (trace) { indent(TraceDepth[trace-1]<<1, pserial); pint(TraceDepth[trace-1]++, pserial); - pserial(':'); pserial(' '); pserial('('); printobject(fname, pserial); + pserial(':'); pserial(' '); pserial('('); pstring(lookupbuiltin(name), pserial); } object *params = first(function); function = cdr(function); @@ -991,13 +998,13 @@ object *closure (int tc, object *fname, object *state, object *function, object if (symbolp(var) && var->name == OPTIONAL) optional = true; else { if (consp(var)) { - if (!optional) error2(fname, PSTR("invalid default value")); + if (!optional) error(name, PSTR("invalid default value"), var); if (args == NULL) value = eval(second(var), *env); else { value = first(args); args = cdr(args); } var = first(var); - if (!symbolp(var)) error2(fname, PSTR("illegal optional parameter")); + if (!symbolp(var)) error(name, PSTR("illegal optional parameter"), var); } else if (!symbolp(var)) { - error2(fname, PSTR("illegal parameter")); + error2(name, PSTR("illegal parameter")); } else if (var->name == AMPREST) { params = cdr(params); var = first(params); @@ -1006,7 +1013,10 @@ object *closure (int tc, object *fname, object *state, object *function, object } else { if (args == NULL) { if (optional) value = nil; - else error2(fname, PSTR("has too few arguments")); + else { + if (name) error2(name, PSTR("has too few arguments")); + else error2(0, PSTR("function has too few arguments")); + } } else { value = first(args); args = cdr(args); } } push(cons(var,value), *env); @@ -1014,76 +1024,76 @@ object *closure (int tc, object *fname, object *state, object *function, object } params = cdr(params); } - if (args != NULL) error2(fname, PSTR("has too many arguments")); + if (args != NULL) { + if (name) error2(name, PSTR("has too many arguments")); + else error2(0, PSTR("function has too many arguments")); + } if (trace) { pserial(')'); pln(pserial); } // Do an implicit progn if (tc) push(nil, *env); return tf_progn(function, *env); } -object *apply (object *function, object *args, object *env) { +object *apply (symbol_t name, object *function, object *args, object *env) { if (symbolp(function)) { - symbol_t name = function->name; - int nargs = listlength(args); - if (name >= ENDFUNCTIONS) error2(function, PSTR("is not valid here")); - if (nargslookupmax(name)) error2(function, PSTR("has too many arguments")); - return ((fn_ptr_type)lookupfn(name))(args, env); + symbol_t fname = function->name; + checkargs(fname, args); + return ((fn_ptr_type)lookupfn(fname))(args, env); } if (listp(function) && issymbol(car(function), LAMBDA)) { function = cdr(function); - object *result = closure(0, NULL, NULL, function, args, &env); + object *result = closure(0, 0, NULL, function, args, &env); return eval(result, env); } if (listp(function) && issymbol(car(function), CLOSURE)) { function = cdr(function); - object *result = closure(0, NULL, car(function), cdr(function), args, &env); + object *result = closure(0, 0, car(function), cdr(function), args, &env); return eval(result, env); } - error2(function, PSTR("is an illegal function")); + error(name, PSTR("illegal function"), function); return NULL; } // In-place operations -object **place (object *args, object *env) { +object **place (symbol_t name, object *args, object *env) { if (atom(args)) return &cdr(findvalue(args, env)); object* function = first(args); if (issymbol(function, CAR) || issymbol(function, FIRST)) { object *value = eval(second(args), env); - if (!listp(value)) error(PSTR("Can't take car")); + if (!listp(value)) error(name, PSTR("can't take car"), value); return &car(value); } if (issymbol(function, CDR) || issymbol(function, REST)) { object *value = eval(second(args), env); - if (!listp(value)) error(PSTR("Can't take cdr")); + if (!listp(value)) error(name, PSTR("can't take cdr"), value); return &cdr(value); } if (issymbol(function, NTH)) { - int index = integer(eval(second(args), env)); + int index = checkinteger(NTH, eval(second(args), env)); object *list = eval(third(args), env); - if (atom(list)) error(PSTR("'nth' second argument is not a list")); + if (atom(list)) error(name, PSTR("second argument to nth is not a list"), list); while (index > 0) { list = cdr(list); - if (list == NULL) error(PSTR("'nth' index out of range")); + if (list == NULL) error2(name, PSTR("index to nth is out of range")); index--; } return &car(list); } - error(PSTR("Illegal place")); + error2(name, PSTR("illegal place")); return nil; } // Checked car and cdr inline object *carx (object *arg) { - if (!listp(arg)) error(PSTR("Can't take car")); + if (!listp(arg)) error(0, PSTR("Can't take car"), arg); if (arg == nil) return nil; return car(arg); } inline object *cdrx (object *arg) { - if (!listp(arg)) error(PSTR("Can't take cdr")); + if (!listp(arg)) error(0, PSTR("Can't take cdr"), arg); if (arg == nil) return nil; return cdr(arg); } @@ -1150,12 +1160,12 @@ inline int SDread () { void serialbegin (int address, int baud) { #if defined(ARDUINO_SAMD_ZERO) || defined(ARDUINO_SAMD_MKRZERO) || defined(ARDUINO_METRO_M4) || defined(ARDUINO_ITSYBITSY_M4) || defined(ARDUINO_FEATHER_M4) || defined(MAX32620) if (address == 1) Serial1.begin((long)baud*100); - else error(PSTR("'with-serial' port not supported")); + else error(WITHSERIAL, PSTR("port not supported"), number(address)); #elif defined(ARDUINO_SAM_DUE) if (address == 1) Serial1.begin((long)baud*100); else if (address == 2) Serial2.begin((long)baud*100); else if (address == 3) Serial3.begin((long)baud*100); - else error(PSTR("'with-serial' port not supported")); + else error(WITHSERIAL, PSTR("port not supported"), number(address)); #endif } @@ -1174,7 +1184,7 @@ gfun_t gstreamfun (object *args) { int address = 0; gfun_t gfun = gserial; if (args != NULL) { - int stream = istream(first(args)); + int stream = isstream(first(args)); streamtype = stream>>8; address = stream & 0xFF; } if (streamtype == I2CSTREAM) gfun = (gfun_t)I2Cread; @@ -1188,7 +1198,7 @@ gfun_t gstreamfun (object *args) { #if defined(sdcardsupport) else if (streamtype == SDSTREAM) gfun = (gfun_t)SDread; #endif - else error(PSTR("Unknown stream type")); + else error2(0, PSTR("unknown stream type")); return gfun; } @@ -1205,7 +1215,7 @@ pfun_t pstreamfun (object *args) { int address = 0; pfun_t pfun = pserial; if (args != NULL && first(args) != NULL) { - int stream = istream(first(args)); + int stream = isstream(first(args)); streamtype = stream>>8; address = stream & 0xFF; } if (streamtype == I2CSTREAM) pfun = (pfun_t)I2Cwrite; @@ -1219,7 +1229,7 @@ pfun_t pstreamfun (object *args) { #if defined(sdcardsupport) else if (streamtype == SDSTREAM) pfun = (pfun_t)SDwrite; #endif - else error(PSTR("unknown stream type")); + else error2(0, PSTR("unknown stream type")); return pfun; } @@ -1227,41 +1237,41 @@ pfun_t pstreamfun (object *args) { void checkanalogread (int pin) { #if defined(ARDUINO_SAM_DUE) - if (!(pin>=54 && pin<=65)) error(PSTR("'analogread' invalid pin")); + if (!(pin>=54 && pin<=65)) error(ANALOGREAD, PSTR("invalid pin"), number(pin)); #elif defined(ARDUINO_SAMD_ZERO) - if (!(pin>=14 && pin<=19)) error(PSTR("'analogread' invalid pin")); + if (!(pin>=14 && pin<=19)) error(ANALOGREAD, PSTR("invalid pin"), number(pin)); #elif defined(ARDUINO_SAMD_MKRZERO) - if (!(pin>=15 && pin<=21)) error(PSTR("'analogread' invalid pin")); + if (!(pin>=15 && pin<=21)) error(ANALOGREAD, PSTR("invalid pin"), number(pin)); #elif defined(ARDUINO_METRO_M4) - if (!(pin>=14 && pin<=21)) error(PSTR("'analogread' invalid pin")); + if (!(pin>=14 && pin<=21)) error(ANALOGREAD, PSTR("invalid pin"), number(pin)); #elif defined(ARDUINO_ITSYBITSY_M4) - if (!(pin>=14 && pin<=19)) error(PSTR("'analogread' invalid pin")); + if (!(pin>=14 && pin<=19)) error(ANALOGREAD, PSTR("invalid pin"), number(pin)); #elif defined(ARDUINO_FEATHER_M4) - if (!(pin>=14 && pin<=19)) error(PSTR("'analogread' invalid pin")); + if (!(pin>=14 && pin<=19)) error(ANALOGREAD, PSTR("invalid pin"), number(pin)); #elif defined(_VARIANT_BBC_MICROBIT_) - if (!((pin>=0 && pin<=4) || pin==10)) error(PSTR("'analogread' invalid pin")); + if (!((pin>=0 && pin<=4) || pin==10)) error(ANALOGREAD, PSTR("invalid pin"), number(pin)); #elif defined(MAX32620) - if (!(pin>=49 && pin<=52)) error(PSTR("'analogread' invalid pin")); + if (!(pin>=49 && pin<=52)) error(ANALOGREAD, PSTR("invalid pin"), number(pin)); #endif } void checkanalogwrite (int pin) { #if defined(ARDUINO_SAM_DUE) - if (!((pin>=2 && pin<=13) || pin==66 || pin==67)) error(PSTR("'analogwrite' invalid pin")); + if (!((pin>=2 && pin<=13) || pin==66 || pin==67)) error(ANALOGWRITE, PSTR("invalid pin"), number(pin)); #elif defined(ARDUINO_SAMD_ZERO) - if (!((pin>=3 && pin<=6) || (pin>=8 && pin<=13) || pin==14)) error(PSTR("'analogwrite' invalid pin")); + if (!((pin>=3 && pin<=6) || (pin>=8 && pin<=13) || pin==14)) error(ANALOGWRITE, PSTR("invalid pin"), number(pin)); #elif defined(ARDUINO_SAMD_MKRZERO) - if (!((pin>=0 && pin<=8) || pin==10 || pin==18 || pin==19)) error(PSTR("'analogwrite' invalid pin")); + if (!((pin>=0 && pin<=8) || pin==10 || pin==18 || pin==19)) error(ANALOGWRITE, PSTR("invalid pin"), number(pin)); #elif defined(ARDUINO_METRO_M4) - if (!(pin>=0 && pin<=15)) error(PSTR("'analogwrite' invalid pin")); + if (!(pin>=0 && pin<=15)) error(ANALOGWRITE, PSTR("invalid pin"), number(pin)); #elif defined(ARDUINO_ITSYBITSY_M4) - if (!(pin==0 || pin==1 || pin==4 || pin==5 || pin==7 || (pin>=9 && pin<=15) || pin==21 || pin==22)) error(PSTR("'analogwrite' invalid pin")); + if (!(pin==0 || pin==1 || pin==4 || pin==5 || pin==7 || (pin>=9 && pin<=15) || pin==21 || pin==22)) error(ANALOGWRITE, PSTR("invalid pin"), number(pin)); #elif defined(ARDUINO_FEATHER_M4) - if (!(pin==0 || pin==1 || (pin>=4 && pin<=6) || (pin>=9 && pin<=13) || pin==14 || pin==15 || pin==17 || pin==21 || pin==22)) error(PSTR("'analogwrite' invalid pin")); + if (!(pin==0 || pin==1 || (pin>=4 && pin<=6) || (pin>=9 && pin<=13) || pin==14 || pin==15 || pin==17 || pin==21 || pin==22)) error(ANALOGWRITE, PSTR("invalid pin"), number(pin)); #elif defined(_VARIANT_BBC_MICROBIT_) - if (!(pin>=0 && pin<=2)) error(PSTR("'analogwrite' invalid pin")); + if (!(pin>=0 && pin<=2)) error(ANALOGWRITE, PSTR("invalid pin"), number(pin)); #elif defined(MAX32620) - if (!((pin>=20 && pin<=29) || pin==32 || (pin>=40 && pin<=48))) error(PSTR("'analogwrite' invalid pin")); + if (!((pin>=20 && pin<=29) || pin==32 || (pin>=40 && pin<=48))) error(ANALOGWRITE, PSTR("invalid pin"), number(pin)); #endif } @@ -1279,7 +1289,7 @@ const int scale[] PROGMEM = {4186,4435,4699,4978,5274,5588,5920,6272,6645,7040,7 void playnote (int pin, int note, int octave) { int prescaler = 8 - octave - note/12; - if (prescaler<0 || prescaler>8) error(PSTR("'note' octave out of range")); + if (prescaler<0 || prescaler>8) error(NOTE, PSTR("octave out of range"), number(prescaler)); tone(pin, scale[note%12]>>prescaler); } @@ -1356,13 +1366,15 @@ void sleep (int secs) { object *sp_quote (object *args, object *env) { (void) env; + checkargs(QUOTE, args); return first(args); } object *sp_defun (object *args, object *env) { (void) env; + checkargs(DEFUN, args); object *var = first(args); - if (var->type != SYMBOL) error2(var, PSTR("is not a symbol")); + if (var->type != SYMBOL) error(DEFUN, PSTR("not a symbol"), var); object *val = cons(symbol(LAMBDA), cdr(args)); object *pair = value(var->name,GlobalEnv); if (pair != NULL) { cdr(pair) = val; return var; } @@ -1371,18 +1383,19 @@ object *sp_defun (object *args, object *env) { } object *sp_defvar (object *args, object *env) { + checkargs(DEFVAR, args); object *var = first(args); - if (var->type != SYMBOL) error2(var, PSTR("is not a symbol")); + if (var->type != SYMBOL) error(DEFVAR, PSTR("not a symbol"), var); object *val = NULL; - args = cdr(args); - if (args != NULL) val = eval(first(args), env); - object *pair = value(var->name,GlobalEnv); + val = eval(second(args), env); + object *pair = value(var->name, GlobalEnv); if (pair != NULL) { cdr(pair) = val; return var; } push(cons(var, val), GlobalEnv); return var; } object *sp_setq (object *args, object *env) { + checkargs(SETQ, args); object *arg = eval(second(args), env); object *pair = findvalue(first(args), env); cdr(pair) = arg; @@ -1406,14 +1419,16 @@ object *sp_loop (object *args, object *env) { } object *sp_push (object *args, object *env) { + checkargs(PUSH, args); object *item = eval(first(args), env); - object **loc = place(second(args), env); + object **loc = place(PUSH, second(args), env); push(item, *loc); return *loc; } object *sp_pop (object *args, object *env) { - object **loc = place(first(args), env); + checkargs(POP, args); + object **loc = place(POP, first(args), env); object *result = car(*loc); pop(*loc); return result; @@ -1422,7 +1437,8 @@ object *sp_pop (object *args, object *env) { // Special forms incf/decf object *sp_incf (object *args, object *env) { - object **loc = place(first(args), env); + checkargs(INCF, args); + object **loc = place(INCF, first(args), env); args = cdr(args); object *x = *loc; @@ -1430,18 +1446,18 @@ object *sp_incf (object *args, object *env) { if (floatp(x) || floatp(inc)) { float increment; - float value = intfloat(x); + float value = checkintfloat(INCF, x); if (inc == NULL) increment = 1.0; - else increment = intfloat(inc); + else increment = checkintfloat(INCF, inc); *loc = makefloat(value + increment); - } else { + } else if (integerp(x) && (integerp(inc) || inc == NULL)) { int increment; - int value = integer(x); + int value = x->integer; if (inc == NULL) increment = 1; - else increment = integer(inc); + else increment = inc->integer; if (increment < 1) { if (INT_MIN - increment > value) *loc = makefloat((float)value + (float)increment); @@ -1450,12 +1466,13 @@ object *sp_incf (object *args, object *env) { if (INT_MAX - increment < value) *loc = makefloat((float)value + (float)increment); else *loc = number(value + increment); } - } + } else error2(INCF, notanumber); return *loc; } object *sp_decf (object *args, object *env) { - object **loc = place(first(args), env); + checkargs(DECF, args); + object **loc = place(DECF, first(args), env); args = cdr(args); object *x = *loc; @@ -1463,18 +1480,18 @@ object *sp_decf (object *args, object *env) { if (floatp(x) || floatp(dec)) { float decrement; - float value = intfloat(x); + float value = checkintfloat(DECF, x); if (dec == NULL) decrement = 1.0; - else decrement = intfloat(dec); + else decrement = checkintfloat(DECF, dec); *loc = makefloat(value - decrement); - } else { + } if (integerp(x) && (integerp(dec) || dec == NULL)) { int decrement; - int value = integer(x); + int value = x->integer; if (dec == NULL) decrement = 1; - else decrement = integer(dec); + else decrement = dec->integer; if (decrement < 1) { if (INT_MAX + decrement < value) *loc = makefloat((float)value - (float)decrement); @@ -1483,18 +1500,20 @@ object *sp_decf (object *args, object *env) { if (INT_MIN + decrement > value) *loc = makefloat((float)value - (float)decrement); else *loc = number(value - decrement); } - } + } else error2(DECF, notanumber); return *loc; } object *sp_setf (object *args, object *env) { - object **loc = place(first(args), env); + checkargs(SETF, args); + object **loc = place(SETF, first(args), env); object *result = eval(second(args), env); *loc = result; return result; } object *sp_dolist (object *args, object *env) { + if (args == NULL) error2(DOLIST, noargument); object *params = first(args); object *var = first(params); object *result; @@ -1505,7 +1524,7 @@ object *sp_dolist (object *args, object *env) { params = cdr(cdr(params)); object *forms = cdr(args); while (list != NULL) { - if (improperp(list)) error3(DOLIST, PSTR("argument is not a proper list")); + if (improperp(list)) error(DOLIST, notproper, list); cdr(pair) = first(list); list = cdr(list); result = eval(tf_progn(forms,env), env); @@ -1521,10 +1540,11 @@ object *sp_dolist (object *args, object *env) { } object *sp_dotimes (object *args, object *env) { + if (args == NULL) error2(DOTIMES, noargument); object *params = first(args); object *var = first(params); object *result; - int count = integer(eval(second(params), env)); + int count = checkinteger(DOTIMES, eval(second(params), env)); int index = 0; params = cdr(cdr(params)); object *pair = cons(var,number(0)); @@ -1580,7 +1600,7 @@ object *sp_formillis (object *args, object *env) { object *param = first(args); unsigned long start = millis(); unsigned long now, total = 0; - if (param != NULL) total = integer(eval(first(param), env)); + if (param != NULL) total = checkinteger(FORMILLIS, eval(first(param), env)); eval(tf_progn(cdr(args),env), env); do { now = millis() - start; @@ -1592,11 +1612,12 @@ object *sp_formillis (object *args, object *env) { object *sp_withserial (object *args, object *env) { object *params = first(args); + if (params == NULL) error2(WITHSERIAL, nostream); object *var = first(params); - int address = integer(eval(second(params), env)); + int address = checkinteger(WITHSERIAL, eval(second(params), env)); params = cddr(params); int baud = 96; - if (params != NULL) baud = integer(eval(first(params), env)); + if (params != NULL) baud = checkinteger(WITHSERIAL, eval(first(params), env)); object *pair = cons(var, stream(SERIALSTREAM, address)); push(pair,env); serialbegin(address, baud); @@ -1608,14 +1629,15 @@ object *sp_withserial (object *args, object *env) { object *sp_withi2c (object *args, object *env) { object *params = first(args); + if (params == NULL) error2(WITHI2C, nostream); object *var = first(params); - int address = integer(eval(second(params), env)); + int address = checkinteger(WITHI2C, eval(second(params), env)); params = cddr(params); int read = 0; // Write I2CCount = 0; if (params != NULL) { object *rw = eval(first(params), env); - if (integerp(rw)) I2CCount = integer(rw); + if (integerp(rw)) I2CCount = rw->integer; read = (rw != NULL); } I2Cinit(1); // Pullups @@ -1629,51 +1651,58 @@ object *sp_withi2c (object *args, object *env) { object *sp_withspi (object *args, object *env) { object *params = first(args); + if (params == NULL) error2(WITHSPI, nostream); object *var = first(params); - int pin = integer(eval(second(params), env)); - int divider = 0, mode = 0, bitorder = 1; + params = cdr(params); + if (params == NULL) error2(WITHSPI, nostream); + int pin = checkinteger(WITHSPI, eval(car(params), env)); + pinMode(pin, OUTPUT); + digitalWrite(pin, HIGH); + params = cdr(params); + int clock = 4000, mode = SPI_MODE0; // Defaults + BitOrder bitorder = MSBFIRST; + if (params != NULL) { + clock = checkinteger(WITHSPI, eval(car(params), env)); + params = cdr(params); + if (params != NULL) { + bitorder = (checkinteger(WITHSPI, eval(car(params), env)) == 0) ? LSBFIRST : MSBFIRST; + params = cdr(params); + if (params != NULL) { + int modeval = checkinteger(WITHSPI, eval(car(params), env)); + mode = (modeval == 3) ? SPI_MODE3 : (modeval == 2) ? SPI_MODE2 : (modeval == 1) ? SPI_MODE1 : SPI_MODE0; + } + } + } object *pair = cons(var, stream(SPISTREAM, pin)); push(pair,env); SPI.begin(); - params = cddr(params); - if (params != NULL) { - divider = integer(eval(first(params), env)); - params = cdr(params); - if (params != NULL) { - bitorder = (eval(first(params), env) == NULL); - params = cdr(params); - if (params != NULL) mode = integer(eval(first(params), env)); - } - } - pinMode(pin, OUTPUT); + SPI.beginTransaction(SPISettings(((unsigned long)clock * 1000), bitorder, mode)); digitalWrite(pin, LOW); - SPI.setBitOrder((BitOrder)bitorder); - if (divider != 0) SPI.setClockDivider(divider); - SPI.setDataMode(mode); object *forms = cdr(args); object *result = eval(tf_progn(forms,env), env); digitalWrite(pin, HIGH); - SPI.end(); + SPI.endTransaction(); return result; } object *sp_withsdcard (object *args, object *env) { #if defined(sdcardsupport) object *params = first(args); + if (params == NULL) error2(WITHSPCARD, nostream); object *var = first(params); object *filename = eval(second(params), env); params = cddr(params); SD.begin(SDCARD_SS_PIN); int mode = 0; - if (params != NULL && first(params) != NULL) mode = integer(first(params)); + if (params != NULL && first(params) != NULL) mode = checkinteger(WITHSDCARD, first(params)); int oflag = O_READ; if (mode == 1) oflag = O_RDWR | O_CREAT | O_APPEND; else if (mode == 2) oflag = O_RDWR | O_CREAT | O_TRUNC; if (mode >= 1) { SDpfile = SD.open(MakeFilename(filename), oflag); - if (!SDpfile) error(PSTR("Problem writing to SD card")); + if (!SDpfile) error2(WITHSPCARD, PSTR("problem writing to SD card")); } else { SDgfile = SD.open(MakeFilename(filename), oflag); - if (!SDgfile) error(PSTR("Problem reading from SD card")); + if (!SDgfile) error2(WITHSPCARD, PSTR("problem reading from SD card")); } object *pair = cons(var, stream(SDSTREAM, 1)); push(pair,env); @@ -1683,7 +1712,7 @@ object *sp_withsdcard (object *args, object *env) { return result; #else (void) args, (void) env; - error(PSTR("with-sd-card not supported")); + error2(WITHSDCARD, PSTR("not supported")); return nil; #endif } @@ -1708,7 +1737,7 @@ object *tf_return (object *args, object *env) { } object *tf_if (object *args, object *env) { - if (args == NULL || cdr(args) == NULL) error3(IF, PSTR("missing argument(s)")); + if (args == NULL || cdr(args) == NULL) error2(IF, PSTR("missing argument(s)")); if (eval(first(args), env) != nil) return second(args); args = cddr(args); return (args != NULL) ? first(args) : nil; @@ -1717,7 +1746,7 @@ object *tf_if (object *args, object *env) { object *tf_cond (object *args, object *env) { while (args != NULL) { object *clause = first(args); - if (!consp(clause)) error2(clause, PSTR("is an illegal 'cond' clause")); + if (!consp(clause)) error(COND, PSTR("illegal clause"), clause); object *test = eval(first(clause), env); object *forms = cdr(clause); if (test != nil) { @@ -1729,13 +1758,13 @@ object *tf_cond (object *args, object *env) { } object *tf_when (object *args, object *env) { - if (args == NULL) error3(WHEN, PSTR("missing argument")); + if (args == NULL) error2(WHEN, noargument); if (eval(first(args), env) != nil) return tf_progn(cdr(args),env); else return nil; } object *tf_unless (object *args, object *env) { - if (args == NULL) error3(UNLESS, PSTR("missing argument")); + if (args == NULL) error2(UNLESS, noargument); if (eval(first(args), env) != nil) return nil; else return tf_progn(cdr(args),env); } @@ -1745,7 +1774,7 @@ object *tf_case (object *args, object *env) { args = cdr(args); while (args != NULL) { object *clause = first(args); - if (!consp(clause)) error2(clause, PSTR("is an illegal 'case' clause")); + if (!consp(clause)) error(CASE, PSTR("illegal clause"), clause); object *key = car(clause); object *forms = cdr(clause); if (consp(key)) { @@ -1897,8 +1926,8 @@ object *fn_cdddr (object *args, object *env) { object *fn_length (object *args, object *env) { (void) env; object *arg = first(args); - if (listp(arg)) return number(listlength(arg)); - if (!stringp(arg)) error3(LENGTH, PSTR("argument is not a list or string")); + if (listp(arg)) return number(listlength(LENGTH, arg)); + if (!stringp(arg)) error(LENGTH, PSTR("argument is not a list or string"), arg); return number(stringlength(arg)); } @@ -1912,7 +1941,7 @@ object *fn_reverse (object *args, object *env) { object *list = first(args); object *result = NULL; while (list != NULL) { - if (improperp(list)) error3(REVERSE, PSTR("argument is not a proper list")); + if (improperp(list)) error(REVERSE, notproper, list); push(first(list),result); list = cdr(list); } @@ -1921,10 +1950,10 @@ object *fn_reverse (object *args, object *env) { object *fn_nth (object *args, object *env) { (void) env; - int n = integer(first(args)); + int n = checkinteger(NTH, first(args)); object *list = second(args); while (list != NULL) { - if (improperp(list)) error3(NTH, PSTR("argument is not a proper list")); + if (improperp(list)) error(NTH, notproper2, list); if (n == 0) return car(list); list = cdr(list); n--; @@ -1936,7 +1965,6 @@ object *fn_assoc (object *args, object *env) { (void) env; object *key = first(args); object *list = second(args); - if (!listp(list)) error3(ASSOC, PSTR("second argument is not a list")); return assoc(key,list); } @@ -1945,7 +1973,7 @@ object *fn_member (object *args, object *env) { object *item = first(args); object *list = second(args); while (list != NULL) { - if (improperp(list)) error3(MEMBER, PSTR("argument is not a proper list")); + if (improperp(list)) error(MEMBER, notproper, list); if (eq(item,car(list))) return list; list = cdr(list); } @@ -1959,52 +1987,54 @@ object *fn_apply (object *args, object *env) { previous = last; last = cdr(last); } - if (!listp(car(last))) error3(APPLY, PSTR("last argument is not a list")); - cdr(previous) = car(last); - return apply(first(args), cdr(args), env); + object *arg = car(last); + if (!listp(arg)) error(APPLY, PSTR("last argument is not a list"), arg); + cdr(previous) = arg; + return apply(APPLY, first(args), cdr(args), env); } object *fn_funcall (object *args, object *env) { - return apply(first(args), cdr(args), env); + return apply(FUNCALL, first(args), cdr(args), env); } object *fn_append (object *args, object *env) { (void) env; object *head = NULL; - object *tail = NULL; + object *tail; while (args != NULL) { object *list = first(args); - while ((unsigned int)list >= PAIR) { + if (!listp(list)) error(APPEND, notalist, list); + while (consp(list)) { object *obj = cons(car(list), cdr(list)); if (head == NULL) head = obj; else cdr(tail) = obj; tail = obj; list = cdr(list); + if (cdr(args) != NULL && improperp(list)) error(APPEND, notproper, first(args)); } - if (cdr(args) != NULL && list != NULL) error3(APPEND, PSTR("argument is not a proper list")); args = cdr(args); } return head; } object *fn_mapc (object *args, object *env) { - symbol_t name = MAPC; object *function = first(args); object *list1 = second(args); object *result = list1; object *list2 = cddr(args); if (list2 != NULL) { list2 = car(list2); + object *result2 = list2; while (list1 != NULL && list2 != NULL) { - if (improperp(list1)) error3(name, PSTR("second argument is not a proper list")); - if (improperp(list2)) error3(name, PSTR("third argument is not a proper list")); - apply(function, cons(car(list1),cons(car(list2),NULL)), env); + if (improperp(list1)) error(MAPC, notproper2, result); + if (improperp(list2)) error(MAPC, notproper3, result2); + apply(MAPC, function, cons(car(list1),cons(car(list2),NULL)), env); list1 = cdr(list1); list2 = cdr(list2); } } else { while (list1 != NULL) { - if (improperp(list1)) error3(name, PSTR("second argument is not a proper list")); - apply(function, cons(car(list1),NULL), env); + if (improperp(list1)) error(MAPC, notproper2, result); + apply(MAPC, function, cons(car(list1),NULL), env); list1 = cdr(list1); } } @@ -2012,19 +2042,20 @@ object *fn_mapc (object *args, object *env) { } object *fn_mapcar (object *args, object *env) { - symbol_t name = MAPCAR; object *function = first(args); object *list1 = second(args); + object *result = list1; object *list2 = cddr(args); object *head = cons(NULL, NULL); push(head,GCStack); object *tail = head; if (list2 != NULL) { list2 = car(list2); + object *result2 = list2; while (list1 != NULL && list2 != NULL) { - if (improperp(list1)) error3(name, PSTR("second argument is not a proper list")); - if (improperp(list2)) error3(name, PSTR("third argument is not a proper list")); - object *result = apply(function, cons(car(list1), cons(car(list2),NULL)), env); + if (improperp(list1)) error(MAPCAR, notproper2, result); + if (improperp(list2)) error(MAPCAR, notproper3, result2); + object *result = apply(MAPCAR, function, cons(car(list1), cons(car(list2),NULL)), env); object *obj = cons(result,NULL); cdr(tail) = obj; tail = obj; @@ -2032,8 +2063,8 @@ object *fn_mapcar (object *args, object *env) { } } else if (list1 != NULL) { while (list1 != NULL) { - if (improperp(list1)) error3(name, PSTR("second argument is not a proper list")); - object *result = apply(function, cons(car(list1),NULL), env); + if (improperp(list1)) error(MAPCAR, notproper2, result); + object *result = apply(MAPCAR, function, cons(car(list1),NULL), env); object *obj = cons(result,NULL); cdr(tail) = obj; tail = obj; @@ -2045,37 +2076,38 @@ object *fn_mapcar (object *args, object *env) { } object *fn_mapcan (object *args, object *env) { - symbol_t name = MAPCAN; object *function = first(args); object *list1 = second(args); + object *result = list1; object *list2 = cddr(args); object *head = cons(NULL, NULL); push(head,GCStack); object *tail = head; if (list2 != NULL) { list2 = car(list2); + object *result2 = list2; while (list1 != NULL && list2 != NULL) { - if (improperp(list1)) error3(name, PSTR("second argument is not a proper list")); - if (improperp(list2)) error3(name, PSTR("third argument is not a proper list")); - object *result = apply(function, cons(car(list1), cons(car(list2),NULL)), env); - while (result != NULL && (unsigned int)result >= PAIR) { + if (improperp(list1)) error(MAPCAN, notproper2, result); + if (improperp(list2)) error(MAPCAN, notproper3, result2); + object *result = apply(MAPCAN, function, cons(car(list1), cons(car(list2),NULL)), env); + while ((unsigned int)result >= PAIR) { cdr(tail) = result; tail = result; result = cdr(result); } - if (cdr(list1) != NULL && cdr(list2) != NULL && result != NULL) error3(name, PSTR("result is not a proper list")); + if (cdr(list1) != NULL && cdr(list2) != NULL && result != NULL) error2(MAPCAN, PSTR("result is not a proper list")); list1 = cdr(list1); list2 = cdr(list2); } } else if (list1 != NULL) { while (list1 != NULL) { - if (improperp(list1)) error3(name, PSTR("second argument is not a proper list")); - object *result = apply(function, cons(car(list1),NULL), env); - while (result != NULL && (unsigned int)result >= PAIR) { + if (improperp(list1)) error(MAPCAN, notproper2, result); + object *result = apply(MAPCAN, function, cons(car(list1),NULL), env); + while ((unsigned int)result >= PAIR) { cdr(tail) = result; tail = result; result = cdr(result); } - if (cdr(list1) != NULL && result != NULL) error3(name, PSTR("result is not a proper list")); + if (cdr(list1) != NULL && result != NULL) error2(MAPCAN, PSTR("result is not a proper list")); list1 = cdr(list1); } } @@ -2088,7 +2120,7 @@ object *fn_mapcan (object *args, object *env) { object *add_floats (object *args, float fresult) { while (args != NULL) { object *arg = car(args); - fresult = fresult + intfloat(arg); + fresult = fresult + checkintfloat(ADD, arg); args = cdr(args); } return makefloat(fresult); @@ -2099,13 +2131,13 @@ object *fn_add (object *args, object *env) { int result = 0; while (args != NULL) { object *arg = car(args); - if (floatp(arg)) return add_floats(args, (float)result); - - int val = integer(arg); - if (val < 1) { if (INT_MIN - val > result) return add_floats(args, (float)result); } - else { if (INT_MAX - val < result) return add_floats(args, (float)result); } - result = result + val; + else if (integerp(arg)) { + int val = arg->integer; + if (val < 1) { if (INT_MIN - val > result) return add_floats(args, (float)result); } + else { if (INT_MAX - val < result) return add_floats(args, (float)result); } + result = result + val; + } else error(ADD, notanumber, arg); args = cdr(args); } return number(result); @@ -2114,7 +2146,7 @@ object *fn_add (object *args, object *env) { object *subtract_floats (object *args, float fresult) { while (args != NULL) { object *arg = car(args); - fresult = fresult - intfloat(arg); + fresult = fresult - checkintfloat(SUBTRACT, arg); args = cdr(args); } return makefloat(fresult); @@ -2122,42 +2154,40 @@ object *subtract_floats (object *args, float fresult) { object *negate (object *arg) { if (integerp(arg)) { - int result = integer(arg); - if (result == INT_MIN) return makefloat(-fromfloat(arg)); + int result = arg->integer; + if (result == INT_MIN) return makefloat(-result); else return number(-result); - } else return makefloat(-fromfloat(arg)); + } else if (floatp(arg)) return makefloat(-(arg->single_float)); + else error(SUBTRACT, notanumber, arg); } object *fn_subtract (object *args, object *env) { (void) env; - object *arg = car(args); args = cdr(args); - if (args == NULL) return negate(arg); - else if (floatp(arg)) return subtract_floats(args, fromfloat(arg)); - else { - int result = integer(arg); - + else if (floatp(arg)) return subtract_floats(args, arg->single_float); + else if (integerp(arg)) { + int result = arg->integer; while (args != NULL) { arg = car(args); - if (floatp(arg)) return subtract_floats(args, result); - - int val = integer(car(args)); - if (val < 1) { if (INT_MAX + val < result) return subtract_floats(args, result); } - else { if (INT_MIN + val > result) return subtract_floats(args, result); } - result = result - val; + else if (integerp(arg)) { + int val = (car(args))->integer; + if (val < 1) { if (INT_MAX + val < result) return subtract_floats(args, result); } + else { if (INT_MIN + val > result) return subtract_floats(args, result); } + result = result - val; + } else error(SUBTRACT, notanumber, arg); args = cdr(args); } return number(result); - } + } else error(SUBTRACT, notanumber, arg); } object *multiply_floats (object *args, float fresult) { while (args != NULL) { object *arg = car(args); - fresult = fresult * intfloat(arg); + fresult = fresult * checkintfloat(MULTIPLY, arg); args = cdr(args); } return makefloat(fresult); @@ -2168,13 +2198,12 @@ object *fn_multiply (object *args, object *env) { int result = 1; while (args != NULL){ object *arg = car(args); - if (floatp(arg)) return multiply_floats(args, result); - - int64_t val = result * (int64_t)integer(arg); - if ((val > INT_MAX) || (val < INT_MIN)) return multiply_floats(args, result); - result = val; - + else if (integerp(arg)) { + int64_t val = result * (int64_t)(arg->integer); + if ((val > INT_MAX) || (val < INT_MIN)) return multiply_floats(args, result); + result = val; + } else error(MULTIPLY, notanumber, arg); args = cdr(args); } return number(result); @@ -2183,8 +2212,8 @@ object *fn_multiply (object *args, object *env) { object *divide_floats (object *args, float fresult) { while (args != NULL) { object *arg = car(args); - float f = intfloat(arg); - if (f == 0.0) error(PSTR("Division by zero")); + float f = checkintfloat(DIVIDE, arg); + if (f == 0.0) error2(DIVIDE, PSTR("division by zero")); fresult = fresult / f; args = cdr(args); } @@ -2198,35 +2227,35 @@ object *fn_divide (object *args, object *env) { // One argument if (args == NULL) { if (floatp(arg)) { - float f = fromfloat(arg); - if (f == 0.0) error(PSTR("Division by zero")); + float f = arg->single_float; + if (f == 0.0) error2(DIVIDE, PSTR("division by zero")); return makefloat(1.0 / f); - } else { - int i = integer(arg); - if (i == 0) error(PSTR("Division by zero")); + } else if (integerp(arg)) { + int i = arg->integer; + if (i == 0) error2(DIVIDE, PSTR("division by zero")); else if (i == 1) return number(1); else return makefloat(1.0 / i); - } + } else error(DIVIDE, notanumber, arg); } // Multiple arguments - if (floatp(arg)) return divide_floats(args, fromfloat(arg)); - else { - int result = integer(arg); + if (floatp(arg)) return divide_floats(args, arg->single_float); + else if (integerp(arg)) { + int result = arg->integer; while (args != NULL) { arg = car(args); if (floatp(arg)) { return divide_floats(args, result); - } else { - int i = integer(arg); - if (i == 0) error(PSTR("Division by zero")); + } else if (integerp(arg)) { + int i = arg->integer; + if (i == 0) error2(DIVIDE, PSTR("division by zero")); if ((result % i) != 0) return divide_floats(args, result); if ((result == INT_MIN) && (i == -1)) return divide_floats(args, result); result = result / i; args = cdr(args); - } - } + } else error(DIVIDE, notanumber, arg); + } return number(result); - } + } else error(DIVIDE, notanumber, arg); } object *fn_mod (object *args, object *env) { @@ -2234,16 +2263,16 @@ object *fn_mod (object *args, object *env) { object *arg1 = first(args); object *arg2 = second(args); if (integerp(arg1) && integerp(arg2)) { - int divisor = integer(arg2); - if (divisor == 0) error(PSTR("Division by zero")); - int dividend = integer(arg1); + int divisor = arg2->integer; + if (divisor == 0) error2(MOD, PSTR("division by zero")); + int dividend = arg1->integer; int remainder = dividend % divisor; if ((dividend<0) != (divisor<0)) remainder = remainder + divisor; return number(remainder); } else { - float fdivisor = intfloat(arg2); - if (fdivisor == 0.0) error(PSTR("Division by zero")); - float fdividend = intfloat(arg1); + float fdivisor = checkintfloat(MOD, arg2); + if (fdivisor == 0.0) error2(MOD, PSTR("division by zero")); + float fdividend = checkintfloat(MOD, arg1); float fremainder = fmod(fdividend , fdivisor); if ((fdividend<0) != (fdivisor<0)) fremainder = fremainder + fdivisor; return makefloat(fremainder); @@ -2253,41 +2282,42 @@ object *fn_mod (object *args, object *env) { object *fn_oneplus (object *args, object *env) { (void) env; object* arg = first(args); - if (floatp(arg)) return makefloat(fromfloat(arg) + 1.0); - else { - int result = integer(arg); - if (result == INT_MAX) return makefloat(integer(arg) + 1.0); + if (floatp(arg)) return makefloat((arg->single_float) + 1.0); + else if (integerp(arg)) { + int result = arg->integer; + if (result == INT_MAX) return makefloat((arg->integer) + 1.0); else return number(result + 1); - } + } else error(ONEPLUS, notanumber, arg); } object *fn_oneminus (object *args, object *env) { (void) env; object* arg = first(args); - if (floatp(arg)) return makefloat(fromfloat(arg) - 1.0); - else { - int result = integer(arg); - if (result == INT_MIN) return makefloat(integer(arg) - 1.0); + if (floatp(arg)) return makefloat((arg->single_float) - 1.0); + else if (integerp(arg)) { + int result = arg->integer; + if (result == INT_MIN) return makefloat((arg->integer) - 1.0); else return number(result - 1); - } + } else error(ONEMINUS, notanumber, arg); } object *fn_abs (object *args, object *env) { (void) env; object *arg = first(args); - if (floatp(arg)) return makefloat(abs(fromfloat(arg))); - else { - int result = integer(arg); - if (result == INT_MIN) return makefloat(abs((float)integer(arg))); + if (floatp(arg)) return makefloat(abs(arg->single_float)); + else if (integerp(arg)) { + int result = arg->integer; + if (result == INT_MIN) return makefloat(abs((float)result)); else return number(abs(result)); - } + } else error(ABS, notanumber, arg); } object *fn_random (object *args, object *env) { (void) env; object *arg = first(args); - if (integerp(arg)) return number(random(integer(arg))); - else return makefloat((float)rand()/(float)(RAND_MAX/fromfloat(arg))); + if (integerp(arg)) return number(random(arg->integer)); + else if (floatp(arg)) return makefloat((float)rand()/(float)(RAND_MAX/(arg->single_float))); + else error(RANDOM, notanumber, arg); } object *fn_maxfn (object *args, object *env) { @@ -2297,8 +2327,8 @@ object *fn_maxfn (object *args, object *env) { while (args != NULL) { object *arg = car(args); if (integerp(result) && integerp(arg)) { - if ((integer(arg) > integer(result))) result = arg; - } else if ((intfloat(arg) > intfloat(result))) result = arg; + if ((arg->integer) > (result->integer)) result = arg; + } else if ((checkintfloat(MAXFN, arg) > checkintfloat(MAXFN, result))) result = arg; args = cdr(args); } return result; @@ -2311,8 +2341,8 @@ object *fn_minfn (object *args, object *env) { while (args != NULL) { object *arg = car(args); if (integerp(result) && integerp(arg)) { - if ((integer(arg) < integer(result))) result = arg; - } else if ((intfloat(arg) < intfloat(result))) result = arg; + if ((arg->integer) < (result->integer)) result = arg; + } else if ((checkintfloat(MINFN, arg) < checkintfloat(MINFN, result))) result = arg; args = cdr(args); } return result; @@ -2329,8 +2359,8 @@ object *fn_noteq (object *args, object *env) { while (nargs != NULL) { object *arg2 = first(nargs); if (integerp(arg1) && integerp(arg2)) { - if ((integer(arg1) == integer(arg2))) return nil; - } else if ((intfloat(arg1) == intfloat(arg2))) return nil; + if ((arg1->integer) == (arg2->integer)) return nil; + } else if ((checkintfloat(NOTEQ, arg1) == checkintfloat(NOTEQ, arg2))) return nil; nargs = cdr(nargs); } args = cdr(args); @@ -2345,8 +2375,8 @@ object *fn_numeq (object *args, object *env) { while (args != NULL) { object *arg2 = first(args); if (integerp(arg1) && integerp(arg2)) { - if (!(integer(arg1) == integer(arg2))) return nil; - } else if (!(intfloat(arg1) == intfloat(arg2))) return nil; + if (!((arg1->integer) == (arg2->integer))) return nil; + } else if (!(checkintfloat(NUMEQ, arg1) == checkintfloat(NUMEQ, arg2))) return nil; arg1 = arg2; args = cdr(args); } @@ -2360,8 +2390,8 @@ object *fn_less (object *args, object *env) { while (args != NULL) { object *arg2 = first(args); if (integerp(arg1) && integerp(arg2)) { - if (!(integer(arg1) < integer(arg2))) return nil; - } else if (!(intfloat(arg1) < intfloat(arg2))) return nil; + if (!((arg1->integer) < (arg2->integer))) return nil; + } else if (!(checkintfloat(LESS, arg1) < checkintfloat(LESS, arg2))) return nil; arg1 = arg2; args = cdr(args); } @@ -2375,8 +2405,8 @@ object *fn_lesseq (object *args, object *env) { while (args != NULL) { object *arg2 = first(args); if (integerp(arg1) && integerp(arg2)) { - if (!(integer(arg1) <= integer(arg2))) return nil; - } else if (!(intfloat(arg1) <= intfloat(arg2))) return nil; + if (!((arg1->integer) <= (arg2->integer))) return nil; + } else if (!(checkintfloat(LESSEQ, arg1) <= checkintfloat(LESSEQ, arg2))) return nil; arg1 = arg2; args = cdr(args); } @@ -2390,8 +2420,8 @@ object *fn_greater (object *args, object *env) { while (args != NULL) { object *arg2 = first(args); if (integerp(arg1) && integerp(arg2)) { - if (!(integer(arg1) > integer(arg2))) return nil; - } else if (!(intfloat(arg1) > intfloat(arg2))) return nil; + if (!((arg1->integer) > (arg2->integer))) return nil; + } else if (!(checkintfloat(GREATER, arg1) > checkintfloat(GREATER, arg2))) return nil; arg1 = arg2; args = cdr(args); } @@ -2405,8 +2435,8 @@ object *fn_greatereq (object *args, object *env) { while (args != NULL) { object *arg2 = first(args); if (integerp(arg1) && integerp(arg2)) { - if (!(integer(arg1) >= integer(arg2))) return nil; - } else if (!(intfloat(arg1) >= intfloat(arg2))) return nil; + if (!((arg1->integer) >= (arg2->integer))) return nil; + } else if (!(checkintfloat(GREATEREQ, arg1) >= checkintfloat(GREATEREQ, arg2))) return nil; arg1 = arg2; args = cdr(args); } @@ -2416,32 +2446,37 @@ object *fn_greatereq (object *args, object *env) { object *fn_plusp (object *args, object *env) { (void) env; object *arg = first(args); - if (floatp(arg)) return (fromfloat(arg) > 0.0) ? tee : nil; - return (integer(arg) > 0) ? tee : nil; + if (floatp(arg)) return ((arg->single_float) > 0.0) ? tee : nil; + else if (integerp(arg)) return ((arg->integer) > 0) ? tee : nil; + else error(PLUSP, notanumber, arg); } object *fn_minusp (object *args, object *env) { (void) env; object *arg = first(args); - if (floatp(arg)) return (fromfloat(arg) < 0.0) ? tee : nil; - return (integer(arg) < 0) ? tee : nil; + if (floatp(arg)) return ((arg->single_float) < 0.0) ? tee : nil; + else if (integerp(arg)) return ((arg->integer) < 0) ? tee : nil; + else error(MINUSP, notanumber, arg); } object *fn_zerop (object *args, object *env) { (void) env; object *arg = first(args); - if (floatp(arg)) return (fromfloat(arg) == 0.0) ? tee : nil; - return (integer(arg) == 0) ? tee : nil; + if (floatp(arg)) return ((arg->single_float) == 0.0) ? tee : nil; + else if (integerp(arg)) return ((arg->integer) == 0) ? tee : nil; + else error(ZEROP, notanumber, arg); } object *fn_oddp (object *args, object *env) { (void) env; - return ((integer(first(args)) & 1) == 1) ? tee : nil; + int arg = checkinteger(ODDP, first(args)); + return ((arg & 1) == 1) ? tee : nil; } object *fn_evenp (object *args, object *env) { (void) env; - return ((integer(first(args)) & 1) == 0) ? tee : nil; + int arg = checkinteger(EVENP, first(args)); + return ((arg & 1) == 0) ? tee : nil; } // Number functions @@ -2462,7 +2497,7 @@ object *fn_numberp (object *args, object *env) { object *fn_floatfn (object *args, object *env) { (void) env; object *arg = first(args); - return (floatp(arg)) ? arg : makefloat((float)integer(arg)); + return (floatp(arg)) ? arg : makefloat((float)(arg->integer)); } object *fn_floatp (object *args, object *env) { @@ -2472,27 +2507,27 @@ object *fn_floatp (object *args, object *env) { object *fn_sin (object *args, object *env) { (void) env; - return makefloat(sin(intfloat(first(args)))); + return makefloat(sin(checkintfloat(SIN, first(args)))); } object *fn_cos (object *args, object *env) { (void) env; - return makefloat(cos(intfloat(first(args)))); + return makefloat(cos(checkintfloat(COS, first(args)))); } object *fn_tan (object *args, object *env) { (void) env; - return makefloat(tan(intfloat(first(args)))); + return makefloat(tan(checkintfloat(TAN, first(args)))); } object *fn_asin (object *args, object *env) { (void) env; - return makefloat(asin(intfloat(first(args)))); + return makefloat(asin(checkintfloat(ASIN, first(args)))); } object *fn_acos (object *args, object *env) { (void) env; - return makefloat(acos(intfloat(first(args)))); + return makefloat(acos(checkintfloat(ACOS, first(args)))); } object *fn_atan (object *args, object *env) { @@ -2500,42 +2535,42 @@ object *fn_atan (object *args, object *env) { object *arg = first(args); float div = 1.0; args = cdr(args); - if (args != NULL) div = intfloat(first(args)); - return makefloat(atan2(intfloat(arg), div)); + if (args != NULL) div = checkintfloat(ATAN, first(args)); + return makefloat(atan2(checkintfloat(ATAN, arg), div)); } object *fn_sinh (object *args, object *env) { (void) env; - return makefloat(sinh(intfloat(first(args)))); + return makefloat(sinh(checkintfloat(SINH, first(args)))); } object *fn_cosh (object *args, object *env) { (void) env; - return makefloat(cosh(intfloat(first(args)))); + return makefloat(cosh(checkintfloat(COSH, first(args)))); } object *fn_tanh (object *args, object *env) { (void) env; - return makefloat(tanh(intfloat(first(args)))); + return makefloat(tanh(checkintfloat(TANH, first(args)))); } object *fn_exp (object *args, object *env) { (void) env; - return makefloat(exp(intfloat(first(args)))); + return makefloat(exp(checkintfloat(EXP, first(args)))); } object *fn_sqrt (object *args, object *env) { (void) env; - return makefloat(sqrt(intfloat(first(args)))); + return makefloat(sqrt(checkintfloat(SQRT, first(args)))); } object *fn_log (object *args, object *env) { (void) env; object *arg = first(args); - float fresult = log(intfloat(arg)); + float fresult = log(checkintfloat(LOG, arg)); args = cdr(args); if (args == NULL) return makefloat(fresult); - else return makefloat(fresult / log(intfloat(first(args)))); + else return makefloat(fresult / log(checkintfloat(LOG, first(args)))); } int intpower (int base, int exp) { @@ -2551,11 +2586,11 @@ int intpower (int base, int exp) { object *fn_expt (object *args, object *env) { (void) env; object *arg1 = first(args); object *arg2 = second(args); - float float1 = intfloat(arg1); - float value = log(abs(float1)) * intfloat(arg2); - if (integerp(arg1) && integerp(arg2) && (integer(arg2) > 0) && (abs(value) < 21.4875)) - return number(intpower(integer(arg1), integer(arg2))); - if (float1 < 0) error3(EXPT, PSTR("invalid result")); + float float1 = checkintfloat(EXPT, arg1); + float value = log(abs(float1)) * checkintfloat(EXPT, arg2); + if (integerp(arg1) && integerp(arg2) && ((arg2->integer) > 0) && (abs(value) < 21.4875)) + return number(intpower(arg1->integer, arg2->integer)); + if (float1 < 0) error2(EXPT, PSTR("invalid result")); return makefloat(exp(value)); } @@ -2563,24 +2598,24 @@ object *fn_ceiling (object *args, object *env) { (void) env; object *arg = first(args); args = cdr(args); - if (args != NULL) return number(ceil(intfloat(arg) / intfloat(first(args)))); - else return number(ceil(intfloat(arg))); + if (args != NULL) return number(ceil(checkintfloat(CEILING, arg) / checkintfloat(CEILING, first(args)))); + else return number(ceil(checkintfloat(CEILING, arg))); } object *fn_floor (object *args, object *env) { (void) env; object *arg = first(args); args = cdr(args); - if (args != NULL) return number(floor(intfloat(arg) / intfloat(first(args)))); - else return number(floor(intfloat(arg))); + if (args != NULL) return number(floor(checkintfloat(FLOOR, arg) / checkintfloat(FLOOR, first(args)))); + else return number(floor(checkintfloat(FLOOR, arg))); } object *fn_truncate (object *args, object *env) { (void) env; object *arg = first(args); args = cdr(args); - if (args != NULL) return number((int)(intfloat(arg) / intfloat(first(args)))); - else return number((int)(intfloat(arg))); + if (args != NULL) return number((int)(checkintfloat(TRUNCATE, arg) / checkintfloat(TRUNCATE, first(args)))); + else return number((int)(checkintfloat(TRUNCATE, arg))); } int myround (float number) { @@ -2591,8 +2626,8 @@ object *fn_round (object *args, object *env) { (void) env; object *arg = first(args); args = cdr(args); - if (args != NULL) return number(myround(intfloat(arg) / intfloat(first(args)))); - else return number(myround(intfloat(arg))); + if (args != NULL) return number(myround(checkintfloat(ROUND, arg) / checkintfloat(ROUND, first(args)))); + else return number(myround(checkintfloat(ROUND, arg))); } // Characters @@ -2600,20 +2635,20 @@ object *fn_round (object *args, object *env) { object *fn_char (object *args, object *env) { (void) env; object *arg = first(args); - if (!stringp(arg)) error2(arg, PSTR("is not a string")); - char c = nthchar(arg, integer(second(args))); - if (c == 0) error3(CHAR, PSTR("index out of range")); + if (!stringp(arg)) error(CHAR, notastring, arg); + char c = nthchar(arg, checkinteger(CHAR, second(args))); + if (c == 0) error2(CHAR, PSTR("index out of range")); return character(c); } object *fn_charcode (object *args, object *env) { (void) env; - return number(fromchar(first(args))); + return number(checkchar(CHARCODE, first(args))); } object *fn_codechar (object *args, object *env) { (void) env; - return character(integer(first(args))); + return character(checkinteger(CODECHAR, first(args))); } object *fn_characterp (object *args, object *env) { @@ -2628,10 +2663,9 @@ object *fn_stringp (object *args, object *env) { return stringp(first(args)) ? tee : nil; } -bool stringcompare (object *args, bool lt, bool gt, bool eq, symbol_t name) { - object *arg1 = first(args); - object *arg2 = second(args); - if (!stringp(arg1) || !stringp(arg2)) error3(name, PSTR("argument is not a string")); +bool stringcompare (symbol_t name, object *args, bool lt, bool gt, bool eq) { + object *arg1 = first(args); if (!stringp(arg1)) error(name, notastring, arg1); + object *arg2 = second(args); if (!stringp(arg2)) error(name, notastring, arg2); arg1 = cdr(arg1); arg2 = cdr(arg2); while ((arg1 != NULL) || (arg2 != NULL)) { @@ -2647,17 +2681,17 @@ bool stringcompare (object *args, bool lt, bool gt, bool eq, symbol_t name) { object *fn_stringeq (object *args, object *env) { (void) env; - return stringcompare(args, false, false, true, STRINGEQ) ? tee : nil; + return stringcompare(STRINGEQ, args, false, false, true) ? tee : nil; } object *fn_stringless (object *args, object *env) { (void) env; - return stringcompare(args, true, false, false, STRINGLESS) ? tee : nil; + return stringcompare(STRINGLESS, args, true, false, false) ? tee : nil; } object *fn_stringgreater (object *args, object *env) { (void) env; - return stringcompare(args, false, true, false, STRINGGREATER) ? tee : nil; + return stringcompare(STRINGGREATER, args, false, true, false) ? tee : nil; } object *fn_sort (object *args, object *env) { @@ -2665,14 +2699,14 @@ object *fn_sort (object *args, object *env) { object *list = cons(nil,first(args)); push(list,GCStack); object *predicate = second(args); - object *compare = cons(NULL,cons(NULL,NULL)); + object *compare = cons(NULL, cons(NULL, NULL)); object *ptr = cdr(list); while (cdr(ptr) != NULL) { object *go = list; while (go != ptr) { car(compare) = car(cdr(ptr)); car(cdr(compare)) = car(cdr(go)); - if (apply(predicate, compare, env)) break; + if (apply(SORT, predicate, compare, env)) break; go = cdr(go); } if (go != ptr) { @@ -2697,10 +2731,10 @@ object *fn_stringfn (object *args, object *env) { object *cell = myalloc(); cell->car = NULL; uint8_t shift = (sizeof(int)-1)*8; - cell->integer = fromchar(arg)<integer = (arg->integer)<cdr = cell; } else if (type == SYMBOL) { - char *s = name(arg); + char *s = symbolname(arg->name); char ch = *s++; object *head = NULL; int chars = 0; @@ -2710,7 +2744,7 @@ object *fn_stringfn (object *args, object *env) { ch = *s++; } obj->cdr = head; - } else error(PSTR("Cannot convert to string")); + } else error(STRINGFN, PSTR("can't convert to string"), arg); return obj; } @@ -2718,7 +2752,7 @@ object *fn_concatenate (object *args, object *env) { (void) env; object *arg = first(args); symbol_t name = arg->name; - if (name != STRINGFN) error3(CONCATENATE, PSTR("only supports strings")); + if (name != STRINGFN) error2(CONCATENATE, PSTR("only supports strings")); args = cdr(args); object *result = myalloc(); result->type = STRING; @@ -2726,7 +2760,7 @@ object *fn_concatenate (object *args, object *env) { int chars = 0; while (args != NULL) { object *obj = first(args); - if (obj->type != STRING) error2(obj, PSTR("not a string")); + if (obj->type != STRING) error(CONCATENATE, notastring, obj); obj = cdr(obj); while (obj != NULL) { int quad = obj->integer; @@ -2746,18 +2780,18 @@ object *fn_concatenate (object *args, object *env) { object *fn_subseq (object *args, object *env) { (void) env; object *arg = first(args); - if (!stringp(arg)) error3(SUBSEQ, PSTR("first argument is not a string")); - int start = integer(second(args)); + if (!stringp(arg)) error(SUBSEQ, notastring, arg); + int start = checkinteger(SUBSEQ, second(args)); int end; args = cddr(args); - if (args != NULL) end = integer(car(args)); else end = stringlength(arg); + if (args != NULL) end = checkinteger(SUBSEQ, car(args)); else end = stringlength(arg); object *result = myalloc(); result->type = STRING; object *head = NULL; int chars = 0; for (int i=start; icdr = head; @@ -2777,7 +2811,7 @@ int gstr () { object *fn_readfromstring (object *args, object *env) { (void) env; object *arg = first(args); - if (!stringp(arg)) error3(READFROMSTRING, PSTR("argument is not a string")); + if (!stringp(arg)) error(READFROMSTRING, notastring, arg); GlobalString = arg; GlobalStringIndex = 0; return read(gstr); @@ -2820,7 +2854,7 @@ object *fn_logand (object *args, object *env) { (void) env; int result = -1; while (args != NULL) { - result = result & integer(first(args)); + result = result & checkinteger(LOGAND, first(args)); args = cdr(args); } return number(result); @@ -2830,7 +2864,7 @@ object *fn_logior (object *args, object *env) { (void) env; int result = 0; while (args != NULL) { - result = result | integer(first(args)); + result = result | checkinteger(LOGIOR, first(args)); args = cdr(args); } return number(result); @@ -2840,7 +2874,7 @@ object *fn_logxor (object *args, object *env) { (void) env; int result = 0; while (args != NULL) { - result = result ^ integer(first(args)); + result = result ^ checkinteger(LOGXOR, first(args)); args = cdr(args); } return number(result); @@ -2848,14 +2882,14 @@ object *fn_logxor (object *args, object *env) { object *fn_lognot (object *args, object *env) { (void) env; - int result = integer(car(args)); + int result = checkinteger(LOGNOT, car(args)); return number(~result); } object *fn_ash (object *args, object *env) { (void) env; - int value = integer(first(args)); - int count = integer(second(args)); + int value = checkinteger(ASH, first(args)); + int count = checkinteger(ASH, second(args)); if (count >= 0) return number(value << count); else @@ -2864,8 +2898,8 @@ object *fn_ash (object *args, object *env) { object *fn_logbitp (object *args, object *env) { (void) env; - int index = integer(first(args)); - int value = integer(second(args)); + int index = checkinteger(LOGBITP, first(args)); + int value = checkinteger(LOGBITP, second(args)); return (bitRead(value, index) == 1) ? tee : nil; } @@ -2959,7 +2993,7 @@ object *fn_readline (object *args, object *env) { object *fn_writebyte (object *args, object *env) { (void) env; - int value = integer(first(args)); + int value = checkinteger(WRITEBYTE, first(args)); pfun_t pfun = pstreamfun(cdr(args)); (pfun)(value); return nil; @@ -2990,17 +3024,17 @@ object *fn_writeline (object *args, object *env) { object *fn_restarti2c (object *args, object *env) { (void) env; - int stream = istream(first(args)); + int stream = first(args)->integer; args = cdr(args); int read = 0; // Write I2CCount = 0; if (args != NULL) { object *rw = first(args); - if (integerp(rw)) I2CCount = integer(rw); + if (integerp(rw)) I2CCount = checkinteger(RESTARTI2C, rw); read = (rw != NULL); } int address = stream & 0xFF; - if (stream>>8 != I2CSTREAM) error3(RESTARTI2C, PSTR("not an i2c stream")); + if (stream>>8 != I2CSTREAM) error2(RESTARTI2C, PSTR("not an i2c stream")); return I2Crestart(address, read) ? tee : nil; } @@ -3043,11 +3077,11 @@ object *fn_cls (object *args, object *env) { object *fn_pinmode (object *args, object *env) { (void) env; - int pin = integer(first(args)); + int pin = checkinteger(PINMODE, first(args)); int pm = INPUT; object *mode = second(args); if (integerp(mode)) { - int nmode = integer(mode); + int nmode = checkinteger(PINMODE, mode); if (nmode == 1) pm = OUTPUT; else if (nmode == 2) pm = INPUT_PULLUP; #if defined(INPUT_PULLDOWN) else if (nmode == 4) pm = INPUT_PULLDOWN; @@ -3059,13 +3093,13 @@ object *fn_pinmode (object *args, object *env) { object *fn_digitalread (object *args, object *env) { (void) env; - int pin = integer(first(args)); + int pin = checkinteger(DIGITALREAD, first(args)); if (digitalRead(pin) != 0) return tee; else return nil; } object *fn_digitalwrite (object *args, object *env) { (void) env; - int pin = integer(first(args)); + int pin = checkinteger(DIGITALWRITE, first(args)); object *mode = second(args); if (integerp(mode)) digitalWrite(pin, mode->integer); else digitalWrite(pin, (mode != nil)); @@ -3074,24 +3108,24 @@ object *fn_digitalwrite (object *args, object *env) { object *fn_analogread (object *args, object *env) { (void) env; - int pin = integer(first(args)); + int pin = checkinteger(ANALOGREAD, first(args)); checkanalogread(pin); return number(analogRead(pin)); } object *fn_analogwrite (object *args, object *env) { (void) env; - int pin = integer(first(args)); + int pin = checkinteger(ANALOGWRITE, first(args)); checkanalogwrite(pin); object *value = second(args); - analogWrite(pin, integer(value)); + analogWrite(pin, checkinteger(ANALOGWRITE, value)); return value; } object *fn_delay (object *args, object *env) { (void) env; object *arg1 = first(args); - delay(integer(arg1)); + delay(checkinteger(DELAY, arg1)); return arg1; } @@ -3103,7 +3137,7 @@ object *fn_millis (object *args, object *env) { object *fn_sleep (object *args, object *env) { (void) env; object *arg1 = first(args); - sleep(integer(arg1)); + sleep(checkinteger(SLEEP, arg1)); return arg1; } @@ -3111,11 +3145,11 @@ object *fn_note (object *args, object *env) { (void) env; static int pin = 255; if (args != NULL) { - pin = integer(first(args)); + pin = checkinteger(NOTE, first(args)); int note = 0; - if (cddr(args) != NULL) note = integer(second(args)); + if (cddr(args) != NULL) note = checkinteger(NOTE, second(args)); int octave = 0; - if (cddr(args) != NULL) octave = integer(third(args)); + if (cddr(args) != NULL) octave = checkinteger(NOTE, third(args)); playnote(pin, note, octave); } else nonote(pin); return nil; @@ -3187,7 +3221,7 @@ int subwidthlist (object *form, int w) { void superprint (object *form, int lm, pfun_t pfun) { if (atom(form)) { - if (symbolp(form) && form->name == NOTHING) pstring(name(form), pfun); + if (symbolp(form) && form->name == NOTHING) pstring(symbolname(form->name), pfun); else printobject(form, pfun); } else if (quoted(form)) { pfun('\''); superprint(car(cdr(form)), lm + 1, pfun); } @@ -3237,11 +3271,14 @@ object *fn_pprintall (object *args, object *env) { object *pair = first(globals); object *var = car(pair); object *val = cdr(pair); + pln(pserial); if (consp(val) && symbolp(car(val)) && car(val)->name == LAMBDA) { - pln(pserial); superprint(cons(symbol(DEFUN), cons(var, cdr(val))), 0, pserial); - pln(pserial); + } else { + superprint(cons(symbol(DEFVAR),cons(var,cons(cons(symbol(QUOTE),cons(val,NULL)) + ,NULL))), 0, pserial); } + pln(pserial); globals = cdr(globals); } return symbol(NOTHING); @@ -3252,7 +3289,7 @@ object *fn_pprintall (object *args, object *env) { object *fn_require (object *args, object *env) { object *arg = first(args); object *globals = GlobalEnv; - if (!symbolp(arg)) error3(REQUIRE, PSTR("argument is not a symbol")); + if (!symbolp(arg)) error(REQUIRE, PSTR("argument is not a symbol"), arg); while (globals != NULL) { object *pair = first(globals); object *var = car(pair); @@ -3280,7 +3317,7 @@ object *fn_listlibrary (object *args, object *env) { while (line != NULL) { int fname = first(line)->name; if (fname == DEFUN || fname == DEFVAR) { - pstring(name(second(line)), pserial); pserial(' '); + pstring(symbolname(second(line)->name), pserial); pserial(' '); } line = read(glibrary); } @@ -3670,10 +3707,10 @@ int longsymbol (char *buffer) { if (p == buffer) { // Add to symbol table? char *newtop = SymbolTop + strlen(p) + 1; - if (SYMBOLTABLESIZE - (newtop - SymbolTable) < BUFFERSIZE) error(PSTR("No room for long symbols")); + if (SYMBOLTABLESIZE - (newtop - SymbolTable) < BUFFERSIZE) error2(0, PSTR("no room for long symbols")); SymbolTop = newtop; } - if (i > 1535) error(PSTR("Too many long symbols")); + if (i > 1535) error2(0, PSTR("Too many long symbols")); return i + 64000; // First number unused by radix40 } @@ -3712,7 +3749,7 @@ void deletesymbol (symbol_t name) { } void testescape () { - if (Serial.read() == '~') error(PSTR("Escape!")); + if (Serial.read() == '~') error2(0, PSTR("escape!")); } // Main evaluator @@ -3724,13 +3761,13 @@ object *eval (object *form, object *env) { EVAL: yield(); // Needed on ESP8266 to avoid Soft WDT Reset // Enough space? - if (End != 0xA5) error(PSTR("Stack overflow")); + if (End != 0xA5) error2(0, PSTR("Stack overflow")); if (Freespace <= WORKSPACESIZE>>4) gc(form, env); // Escape - if (tstflag(ESCAPE)) { clrflag(ESCAPE); error(PSTR("Escape!"));} + if (tstflag(ESCAPE)) { clrflag(ESCAPE); error2(0, PSTR("Escape!"));} #if defined (serialmonitor) testescape(); - #endif + #endif if (form == NULL) return nil; @@ -3744,15 +3781,15 @@ object *eval (object *form, object *env) { pair = value(name, GlobalEnv); if (pair != NULL) return cdr(pair); else if (name <= ENDFUNCTIONS) return form; - error2(form, PSTR("undefined")); + error(0, PSTR("undefined"), form); } // It's a list object *function = car(form); object *args = cdr(form); - if (function == NULL) error3(NIL, PSTR("is an illegal function")); - if (!listp(args)) error(PSTR("Can't evaluate a dotted pair")); + if (function == NULL) error2(0, PSTR("'nil' illegal function")); + if (!listp(args)) error(0, PSTR("can't evaluate a dotted pair"), args); // List starts with a symbol? if (symbolp(function)) { @@ -3791,7 +3828,7 @@ object *eval (object *form, object *env) { return cons(symbol(CLOSURE), cons(envcopy,args)); } - if (name < SPECIAL_FORMS) error2(function, PSTR("can't be used as a function")); + if (name < SPECIAL_FORMS) error2((int)function, PSTR("can't be used as a function")); if ((name > SPECIAL_FORMS) && (name < TAIL_FORMS)) { return ((fn_ptr_type)lookupfn(name))(args, env); @@ -3826,16 +3863,16 @@ object *eval (object *form, object *env) { if (symbolp(function)) { symbol_t name = function->name; - if (name >= ENDFUNCTIONS) error2(fname, PSTR("is not valid here")); - if (nargslookupmax(name)) error2(fname, PSTR("has too many arguments")); + if (name >= ENDFUNCTIONS) error(0, PSTR("not valid here"), fname); + if (nargslookupmax(name)) error2(name, PSTR("has too many arguments")); object *result = ((fn_ptr_type)lookupfn(name))(args, env); pop(GCStack); return result; } if (listp(function) && issymbol(car(function), LAMBDA)) { - form = closure(TCstart, fname, NULL, cdr(function), args, &env); + form = closure(TCstart, fname->name, NULL, cdr(function), args, &env); pop(GCStack); int trace = tracing(fname->name); if (trace) { @@ -3854,13 +3891,13 @@ object *eval (object *form, object *env) { if (listp(function) && issymbol(car(function), CLOSURE)) { function = cdr(function); - form = closure(TCstart, fname, car(function), cdr(function), args, &env); + form = closure(TCstart, fname->name, car(function), cdr(function), args, &env); pop(GCStack); TC = 1; goto EVAL; } - error2(fname, PSTR("is an illegal function")); return nil; + error2((int)fname, PSTR("is an illegal function")); return nil; } // Print functions @@ -4007,17 +4044,12 @@ void printobject (object *form, pfun_t pfun){ printobject(form, pfun); } pfun(')'); - } else if (integerp(form)) { - pint(integer(form), pfun); - } else if (floatp(form)) { - pfloat(fromfloat(form), pfun); - } else if (symbolp(form)) { - if (form->name != NOTHING) pstring(name(form), pfun); - } else if (characterp(form)) { - pcharacter(form->integer, pfun); - } else if (stringp(form)) { - printstring(form, pfun); - } else if (streamp(form)) { + } else if (integerp(form)) pint(form->integer, pfun); + else if (floatp(form)) pfloat(form->single_float, pfun); + else if (symbolp(form)) { if (form->name != NOTHING) pstring(symbolname(form->name), pfun); } + else if (characterp(form)) pcharacter(form->integer, pfun); + else if (stringp(form)) printstring(form, pfun); + else if (streamp(form)) { pfstring(PSTR("<"), pfun); if ((form->integer)>>8 == SPISTREAM) pfstring(PSTR("spi"), pfun); else if ((form->integer)>>8 == I2CSTREAM) pfstring(PSTR("i2c"), pfun); @@ -4027,7 +4059,7 @@ void printobject (object *form, pfun_t pfun){ pint(form->integer & 0xFF, pfun); pfun('>'); } else - error(PSTR("Error in print.")); + error2(0, PSTR("Error in print")); } // Read functions @@ -4107,7 +4139,7 @@ object *nextitem (gfun_t gfun) { else if (ch == 'O') base = 8; else if (ch == 'X') base = 16; else if (ch == 0x07) return (object *)QUO; - else error(PSTR("Illegal character after #")); + else error2(0, PSTR("Illegal character after #")); ch = gfun(); } int valid; // 0=undecided, -1=invalid, +1=valid @@ -4158,7 +4190,7 @@ object *nextitem (gfun_t gfun) { if (strcasecmp(buffer, p) == 0) return character(c); p = p + strlen(p) + 1; c++; } - error(PSTR("Unknown character")); + error2(0, PSTR("Unknown character")); } int x = builtin(buffer); @@ -4180,7 +4212,7 @@ object *readrest (gfun_t gfun) { item = cons(symbol(QUOTE), cons(read(gfun), NULL)); } else if (item == (object *)DOT) { tail->cdr = read(gfun); - if (readrest(gfun) != NULL) error(PSTR("Malformed list")); + if (readrest(gfun) != NULL) error2(0, PSTR("malformed list")); return head; } else { object *cell = cons(item, NULL); @@ -4195,7 +4227,7 @@ object *readrest (gfun_t gfun) { object *read (gfun_t gfun) { object *item = nextitem(gfun); - if (item == (object *)KET) error(PSTR("Incomplete list")); + if (item == (object *)KET) error2(0, PSTR("incomplete list")); if (item == (object *)BRA) return readrest(gfun); if (item == (object *)DOT) return read(gfun); if (item == (object *)QUO) return cons(symbol(QUOTE), cons(read(gfun), NULL)); @@ -4215,7 +4247,7 @@ void setup () { initworkspace(); initenv(); initsleep(); - pfstring(PSTR("uLisp 2.7 "), pserial); pln(pserial); + pfstring(PSTR("uLisp 2.8 "), pserial); pln(pserial); } // Read/Evaluate/Print loop @@ -4234,7 +4266,7 @@ void repl (object *env) { pfstring(PSTR("> "), pserial); object *line = read(gserial); if (BreakLevel && line == nil) { pln(pserial); return; } - if (line == (object *)KET) error(PSTR("Unmatched right bracket")); + if (line == (object *)KET) error2(0, PSTR("unmatched right bracket")); push(line, GCStack); pfl(pserial); line = eval(line, env);