@@ -184,7 +184,7 @@ typedef int (*gfun_t)();
184184typedef void (*pfun_t )(char );
185185
186186enum builtins: builtin_t { NIL, TEE, NOTHING, OPTIONAL, INITIALELEMENT, ELEMENTTYPE, BIT, AMPREST, LAMBDA, MACRO, LET, LETSTAR,
187- CLOSURE, PSTAR, QUOTE, BACKQUOTE, UNQUOTE, UNQUOTE_SPLICING, CONS, APPEND, DEFUN, DEFVAR, DEFMACRO, CAR, FIRST, CDR, REST, NTH, AREF, STRINGFN, PINMODE, DIGITALWRITE,
187+ CLOSURE, PSTAR, QUOTE, BACKQUOTE, UNQUOTE, UNQUOTE_SPLICING, CONS, APPEND, DEFUN, SETF, DEFVAR, DEFMACRO, CAR, FIRST, CDR, REST, NTH, AREF, STRINGFN, PINMODE, DIGITALWRITE,
188188ANALOGREAD, REGISTER, FORMAT,
189189 };
190190
@@ -2162,16 +2162,31 @@ object* sp_or (object* args, object* env) {
21622162 return nil;
21632163}
21642164
2165+ // Need to do manual search because findvalue() uses eq() but we need equal() for this.
2166+ object* find_setf_func (object* whatenv, object* funcname) {
2167+ object* what = cons (bsymbol (SETF), cons (funcname, nil));
2168+ for (object* z = whatenv; z != nil; z = cdr (z)) {
2169+ object* pair = car (z);
2170+ if (equal (what, car (pair))) return pair;
2171+ }
2172+ return nil;
2173+ }
2174+
21652175/*
21662176 (defun name (parameters) form*)
21672177 Defines a function.
21682178*/
21692179object* sp_defun (object* args, object* env) {
21702180 (void ) env;
21712181 object* var = first (args);
2172- if (!symbolp (var)) error (notasymbol, var);
2182+ if (!symbolp (var)) {
2183+ // Check for (setf foo) forms
2184+ if (consp (var) && listlength (var) == 2 && eq (first (var), bsymbol (SETF))) /* do nothing */ ;
2185+ else error (notasymbol, var);
2186+ }
21732187 object* val = cons (bsymbol (LAMBDA), cdr (args));
21742188 object* pair = value (var->name , GlobalEnv);
2189+ if (consp (var) && !pair) pair = find_setf_func (GlobalEnv, second (var));
21752190 if (pair != NULL ) cdr (pair) = val;
21762191 else push (cons (var, val), GlobalEnv);
21772192 return var;
@@ -2384,12 +2399,27 @@ object* sp_decf (object* args, object* env) {
23842399object* sp_setf (object* args, object* env) {
23852400 int bit;
23862401 object* arg = nil;
2402+ object* placeform = nil;
2403+ object** loc;
23872404 while (args != NULL ) {
23882405 if (cdr (args) == NULL ) error2 (oddargs);
2389- object** loc = place (first (args), env, &bit);
2406+ placeform = first (args);
2407+ // Check for special defsetf forms first before calling place()
2408+ if (consp (placeform)) {
2409+ object* funcname = first (placeform);
2410+ object* userdef = find_setf_func (env, funcname);
2411+ if (!userdef) userdef = find_setf_func (GlobalEnv, funcname);
2412+ if (userdef) {
2413+ // usercode should be a lambda
2414+ arg = eval (cons (cdr (userdef), cons (second (args), rest (placeform))), env);
2415+ goto next;
2416+ }
2417+ }
23902418 arg = eval (second (args), env);
2419+ loc = place (placeform, env, &bit);
23912420 if (bit == -1 ) *loc = arg;
23922421 else *loc = number ((checkinteger (*loc) & ~(1 <<bit)) | checkbitvalue (arg)<<bit);
2422+ next:
23932423 args = cddr (args);
23942424 }
23952425 return arg;
@@ -6451,6 +6481,7 @@ const tbl_entry_t BuiltinTable[] PROGMEM = {
64516481 { string57, fn_cons, MINMAX (FUNCTIONS, 2 , 2 ), doc57 },
64526482 { string92, fn_append, MINMAX (FUNCTIONS, 0 , UNLIMITED), doc92 },
64536483 { string14, sp_defun, MINMAX (SPECIAL_FORMS, 2 , UNLIMITED), doc14 },
6484+ { string36, sp_setf, MINMAX (SPECIAL_FORMS, 2 , UNLIMITED), doc36 },
64546485 { string15, sp_defvar, MINMAX (SPECIAL_FORMS, 1 , 3 ), doc15 },
64556486 { stringdefmacro, sp_defmacro, MINMAX (SPECIAL_FORMS, 2 , UNLIMITED), docdefmacro },
64566487 { string16, fn_car, MINMAX (FUNCTIONS, 1 , 1 ), doc16 },
@@ -6473,7 +6504,6 @@ const tbl_entry_t BuiltinTable[] PROGMEM = {
64736504 { string33, sp_pop, MINMAX (SPECIAL_FORMS, 1 , 1 ), doc33 },
64746505 { string34, sp_incf, MINMAX (SPECIAL_FORMS, 1 , 2 ), doc34 },
64756506 { string35, sp_decf, MINMAX (SPECIAL_FORMS, 1 , 2 ), doc35 },
6476- { string36, sp_setf, MINMAX (SPECIAL_FORMS, 2 , UNLIMITED), doc36 },
64776507 { string37, sp_dolist, MINMAX (SPECIAL_FORMS, 1 , UNLIMITED), doc37 },
64786508 { string38, sp_dotimes, MINMAX (SPECIAL_FORMS, 1 , UNLIMITED), doc38 },
64796509 { string39, sp_trace, MINMAX (SPECIAL_FORMS, 0 , 1 ), doc39 },
0 commit comments