/* xlstruct.c - the defstruct facility */ /* Copyright (c) 1988, by David Michael Betz All Rights Reserved Permission is granted for unrestricted non-commercial use */ #include "xlisp.h" /* external variables */ extern LVAL xlenv,xlfenv; extern LVAL s_lambda,s_quote,lk_key,true; extern char buf[]; /* local variables */ static prefix[STRMAX+1]; /* xmkstruct - the '%make-struct' function */ LVAL xmkstruct() { LVAL type,val; int i; /* get the structure type */ type = xlgasymbol(); /* make the structure */ val = newstruct(type,xlargc); /* store each argument */ for (i = 1; moreargs(); ++i) setelement(val,i,nextarg()); xllastarg(); /* return the structure */ return (val); } /* xcpystruct - the '%copy-struct' function */ LVAL xcpystruct() { LVAL str,val; int size,i; str = xlgastruct(); xllastarg(); size = getsize(str); val = newstruct(getelement(str,0),size-1); for (i = 1; i < size; ++i) setelement(val,i,getelement(str,i)); return (val); } /* xstrref - the '%struct-ref' function */ LVAL xstrref() { LVAL str,val; int i; str = xlgastruct(); val = xlgafixnum(); i = (int)getfixnum(val); xllastarg(); return (getelement(str,i)); } /* xstrset - the '%struct-set' function */ LVAL xstrset() { LVAL str,val; int i; str = xlgastruct(); val = xlgafixnum(); i = (int)getfixnum(val); val = xlgetarg(); xllastarg(); setelement(str,i,val); return (val); } /* xstrtypep - the '%struct-type-p' function */ LVAL xstrtypep() { LVAL type,val; type = xlgasymbol(); val = xlgetarg(); xllastarg(); return (structp(val) && getelement(val,0) == type ? true : NIL); } /* xdefstruct - the 'defstruct' special form */ LVAL xdefstruct() { LVAL structname,slotname,defexpr,sym,tmp,args,body; LVAL options,oargs,slots; char *pname; int slotn; /* protect some pointers */ xlstkcheck(6); xlsave(structname); xlsave(slotname); xlsave(defexpr); xlsave(args); xlsave(body); xlsave(tmp); /* initialize */ args = body = NIL; slotn = 0; /* get the structure name */ tmp = xlgetarg(); if (symbolp(tmp)) { structname = tmp; strcpy(prefix,getstring(getpname(structname))); strcat(prefix,"-"); } /* get the structure name and options */ else if (consp(tmp) && symbolp(car(tmp))) { structname = car(tmp); strcpy(prefix,getstring(getpname(structname))); strcat(prefix,"-"); /* handle the list of options */ for (options = cdr(tmp); consp(options); options = cdr(options)) { /* get the next argument */ tmp = car(options); /* handle options that don't take arguments */ if (symbolp(tmp)) { pname = getstring(getpname(tmp)); xlerror("unknown option",tmp); } /* handle options that take arguments */ else if (consp(tmp) && symbolp(car(tmp))) { pname = getstring(getpname(car(tmp))); oargs = cdr(tmp); /* check for the :CONC-NAME keyword */ if (strcmp(pname,":CONC-NAME") == 0) { /* get the name of the structure to include */ if (!consp(oargs) || !symbolp(car(oargs))) xlerror("expecting a symbol",oargs); /* save the prefix */ strcpy(prefix,getstring(getpname(car(oargs)))); } /* check for the :INCLUDE keyword */ else if (strcmp(pname,":INCLUDE") == 0) { /* get the name of the structure to include */ if (!consp(oargs) || !symbolp(car(oargs))) xlerror("expecting a structure name",oargs); tmp = car(oargs); oargs = cdr(oargs); /* add each slot from the included structure */ slots = xlgetprop(tmp,xlenter("*STRUCT-SLOTS*")); for (; consp(slots); slots = cdr(slots)) { if (consp(car(slots)) && consp(cdr(car(slots)))) { /* get the next slot description */ tmp = car(slots); /* create the slot access functions */ addslot(car(tmp),car(cdr(tmp)),++slotn,&args,&body); } } /* handle slot initialization overrides */ for (; consp(oargs); oargs = cdr(oargs)) { tmp = car(oargs); if (symbolp(tmp)) { slotname = tmp; defexpr = NIL; } else if (consp(tmp) && symbolp(car(tmp))) { slotname = car(tmp); defexpr = (consp(cdr(tmp)) ? car(cdr(tmp)) : NIL); } else xlerror("bad slot description",tmp); updateslot(args,slotname,defexpr); } } else xlerror("unknown option",tmp); } else xlerror("bad option syntax",tmp); } } /* get each of the structure members */ while (moreargs()) { /* get the slot name and default value expression */ tmp = xlgetarg(); if (symbolp(tmp)) { slotname = tmp; defexpr = NIL; } else if (consp(tmp) && symbolp(car(tmp))) { slotname = car(tmp); defexpr = (consp(cdr(tmp)) ? car(cdr(tmp)) : NIL); } else xlerror("bad slot description",tmp); /* create a closure for non-trival default expressions */ if (defexpr != NIL) { tmp = newclosure(NIL,s_lambda,xlenv,xlfenv); setbody(tmp,cons(defexpr,NIL)); tmp = cons(tmp,NIL); defexpr = tmp; } /* create the slot access functions */ addslot(slotname,defexpr,++slotn,&args,&body); } /* store the slotnames and default expressions */ xlputprop(structname,args,xlenter("*STRUCT-SLOTS*")); /* enter the MAKE-xxx symbol */ sprintf(buf,"MAKE-%s",getstring(getpname(structname))); sym = xlenter(buf); /* make the MAKE-xxx function */ args = cons(lk_key,args); tmp = cons(structname,NIL); tmp = cons(s_quote,tmp); body = cons(tmp,body); body = cons(xlenter("%MAKE-STRUCT"),body); body = cons(body,NIL); setfunction(sym, xlclose(sym,s_lambda,args,body,xlenv,xlfenv)); /* enter the xxx-P symbol */ sprintf(buf,"%s-P",getstring(getpname(structname))); sym = xlenter(buf); /* make the xxx-P function */ args = cons(xlenter("X"),NIL); body = cons(xlenter("X"),NIL); tmp = cons(structname,NIL); tmp = cons(s_quote,tmp); body = cons(tmp,body); body = cons(xlenter("%STRUCT-TYPE-P"),body); body = cons(body,NIL); setfunction(sym, xlclose(sym,s_lambda,args,body,NIL,NIL)); /* enter the COPY-xxx symbol */ sprintf(buf,"COPY-%s",getstring(getpname(structname))); sym = xlenter(buf); /* make the COPY-xxx function */ args = cons(xlenter("X"),NIL); body = cons(xlenter("X"),NIL); body = cons(xlenter("%COPY-STRUCT"),body); body = cons(body,NIL); setfunction(sym, xlclose(sym,s_lambda,args,body,NIL,NIL)); /* restore the stack */ xlpopn(6); /* return the structure name */ return (structname); } /* xlrdstruct - convert a list to a structure (used by the reader) */ LVAL xlrdstruct(list) LVAL list; { LVAL structname,sym,slotname,expr,last,val; /* protect the new structure */ xlsave1(expr); /* get the structure name */ if (!consp(list) || !symbolp(car(list))) xlerror("bad structure initialization list",list); structname = car(list); list = cdr(list); /* enter the MAKE-xxx symbol */ sprintf(buf,"MAKE-%s",getstring(getpname(structname))); /* initialize the MAKE-xxx function call expression */ expr = cons(xlenter(buf),NIL); last = expr; /* turn the rest of the initialization list into keyword arguments */ while (consp(list) && consp(cdr(list))) { /* get the slot keyword name */ slotname = car(list); if (!symbolp(slotname)) xlerror("expecting a slot name",slotname); sprintf(buf,":%s",getstring(getpname(slotname))); /* add the slot keyword */ rplacd(last,cons(xlenter(buf),NIL)); last = cdr(last); list = cdr(list); /* add the value expression */ rplacd(last,cons(car(list),NIL)); last = cdr(last); list = cdr(list); } /* make sure all of the initializers were used */ if (consp(list)) xlerror("bad structure initialization list",list); /* invoke the creation function */ val = xleval(expr); /* restore the stack */ xlpop(); /* return the new structure */ return (val); } /* xlprstruct - print a structure (used by printer) */ xlprstruct(fptr,vptr,flag) LVAL fptr,vptr; int flag; { LVAL next; int i,n; xlputc(fptr,'#'); xlputc(fptr,'S'); xlputc(fptr,'('); xlprint(fptr,getelement(vptr,0),flag); next = xlgetprop(getelement(vptr,0),xlenter("*STRUCT-SLOTS*")); for (i = 1, n = getsize(vptr) - 1; i <= n && consp(next); ++i) { if (consp(car(next))) { /* should always succeed */ xlputc(fptr,' '); xlprint(fptr,car(car(next)),flag); xlputc(fptr,' '); xlprint(fptr,getelement(vptr,i),flag); } next = cdr(next); } xlputc(fptr,')'); } /* addslot - make the slot access functions */ LOCAL addslot(slotname,defexpr,slotn,pargs,pbody) LVAL slotname,defexpr; int slotn; LVAL *pargs,*pbody; { LVAL sym,args,body,tmp; /* protect some pointers */ xlstkcheck(4); xlsave(sym); xlsave(args); xlsave(body); xlsave(tmp); /* construct the update function name */ sprintf(buf,"%s%s",prefix,getstring(getpname(slotname))); sym = xlenter(buf); /* make the access function */ args = cons(xlenter("S"),NIL); body = cons(cvfixnum((FIXTYPE)slotn),NIL); body = cons(xlenter("S"),body); body = cons(xlenter("%STRUCT-REF"),body); body = cons(body,NIL); setfunction(sym, xlclose(sym,s_lambda,args,body,NIL,NIL)); /* make the update function */ args = cons(xlenter("V"),NIL); args = cons(xlenter("S"),args); body = cons(xlenter("V"),NIL); body = cons(cvfixnum((FIXTYPE)slotn),body); body = cons(xlenter("S"),body); body = cons(xlenter("%STRUCT-SET"),body); body = cons(body,NIL); xlputprop(sym, xlclose(NIL,s_lambda,args,body,NIL,NIL), xlenter("*SETF*")); /* add the slotname to the make-xxx keyword list */ tmp = cons(defexpr,NIL); tmp = cons(slotname,tmp); tmp = cons(tmp,NIL); if ((args = *pargs) == NIL) *pargs = tmp; else { while (cdr(args) != NIL) args = cdr(args); rplacd(args,tmp); } /* add the slotname to the %make-xxx argument list */ tmp = cons(slotname,NIL); if ((body = *pbody) == NIL) *pbody = tmp; else { while (cdr(body) != NIL) body = cdr(body); rplacd(body,tmp); } /* restore the stack */ xlpopn(4); } /* updateslot - update a slot definition */ LOCAL updateslot(args,slotname,defexpr) LVAL args,slotname,defexpr; { LVAL tmp; for (; consp(args); args = cdr(args)) if (slotname == car(car(args))) { if (defexpr != NIL) { xlsave1(tmp); tmp = newclosure(NIL,s_lambda,xlenv,xlfenv); setbody(tmp,cons(defexpr,NIL)); tmp = cons(tmp,NIL); defexpr = tmp; xlpop(); } rplaca(cdr(car(args)),defexpr); break; } if (args == NIL) xlerror("unknown slot name",slotname); }