home *** CD-ROM | disk | FTP | other *** search
/ Education Sampler 1992 [NeXTSTEP] / Education_1992_Sampler.iso / Programming / Source / winterp-1.13 / src-server / xlisp / xlobj.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-10-04  |  13.8 KB  |  526 lines

  1. /* -*-C-*-
  2. ********************************************************************************
  3. *
  4. * File:         xlobj.c
  5. * RCS:          $Header: xlobj.c,v 1.5 91/03/24 22:25:15 mayer Exp $
  6. * Description:  xlisp object functions
  7. * Author:       David Michael Betz
  8. * Created:      
  9. * Modified:     Fri Oct  4 04:07:16 1991 (Niels Mayer) mayer@hplnpm
  10. * Language:     C
  11. * Package:      N/A
  12. * Status:       X11r5 contrib tape release
  13. *
  14. * WINTERP Copyright 1989, 1990, 1991 Hewlett-Packard Company (by Niels Mayer).
  15. * XLISP version 2.1, Copyright (c) 1989, by David Betz.
  16. *
  17. * Permission to use, copy, modify, distribute, and sell this software and its
  18. * documentation for any purpose is hereby granted without fee, provided that
  19. * the above copyright notice appear in all copies and that both that
  20. * copyright notice and this permission notice appear in supporting
  21. * documentation, and that the name of Hewlett-Packard and David Betz not be
  22. * used in advertising or publicity pertaining to distribution of the software
  23. * without specific, written prior permission.  Hewlett-Packard and David Betz
  24. * make no representations about the suitability of this software for any
  25. * purpose. It is provided "as is" without express or implied warranty.
  26. *
  27. * HEWLETT-PACKARD AND DAVID BETZ DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
  28. * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
  29. * IN NO EVENT SHALL HEWLETT-PACKARD NOR DAVID BETZ BE LIABLE FOR ANY SPECIAL,
  30. * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  31. * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  32. * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  33. * PERFORMANCE OF THIS SOFTWARE.
  34. *
  35. * See ./winterp/COPYRIGHT for information on contacting the authors.
  36. * Please send modifications, improvements and bugfixes to mayer@hplabs.hp.com
  37. * Post XLISP-specific questions/information to the newsgroup comp.lang.lisp.x
  38. *
  39. ********************************************************************************
  40. */
  41. static char rcs_identity[] = "@(#)$Header: xlobj.c,v 1.5 91/03/24 22:25:15 mayer Exp $";
  42.  
  43.  
  44. #include "xlisp.h"
  45.  
  46. /* external variables */
  47. extern LVAL xlenv,xlfenv,xlvalue;
  48. extern LVAL s_stdout,s_lambda;
  49.  
  50. /* local variables */
  51. static LVAL s_self,k_new,k_isnew;
  52. static LVAL class,object;
  53.  
  54. /* instance variable numbers for the class 'Class' */
  55. #define MESSAGES    0    /* list of messages */
  56. #define IVARS        1    /* list of instance variable names */
  57. #define CVARS        2    /* list of class variable names */
  58. #define CVALS        3    /* list of class variable values */
  59. #define SUPERCLASS    4    /* pointer to the superclass */
  60. #define IVARCNT        5    /* number of class instance variables */
  61. #define IVARTOTAL    6    /* total number of instance variables */
  62.  
  63. /* number of instance variables for the class 'Class' */
  64. #define CLASSSIZE    7
  65.  
  66. /* forward declarations */
  67. LOCAL FORWARD LVAL entermsg();    /* NPM: changed this to LOCAL */
  68. LOCAL FORWARD LVAL sendmsg();    /* NPM: changed this to LOCAL */
  69. LOCAL FORWARD LVAL evmethod();    /* NPM: changed this to LOCAL */
  70.  
  71. /* xsend - send a message to an object */
  72. LVAL xsend()
  73. {
  74.     LVAL obj;
  75.     obj = xlgaobject();
  76.     return (sendmsg(obj,getclass(obj),xlgasymbol()));
  77. }
  78.  
  79. /* xsendsuper - send a message to the superclass of an object */
  80. LVAL xsendsuper()
  81. {
  82.     LVAL env,p;
  83.     for (env = xlenv; env; env = cdr(env))
  84.     if ((p = car(env)) && objectp(car(p)))
  85.         return (sendmsg(car(p),
  86.                 getivar(cdr(p),SUPERCLASS),
  87.                 xlgasymbol()));
  88.     xlfail("not in a method");
  89. }
  90.  
  91. /* xlclass - define a class */
  92. LVAL xlclass(name,vcnt)
  93.   char *name; int vcnt;
  94. {
  95.     LVAL sym,cls;
  96.  
  97.     /* create the class */
  98.     sym = xlenter(name);
  99.     cls = newobject(class,CLASSSIZE);
  100.     setvalue(sym,cls);
  101.  
  102.     /* set the instance variable counts */
  103.     setivar(cls,IVARCNT,cvfixnum((FIXTYPE)vcnt));
  104.     setivar(cls,IVARTOTAL,cvfixnum((FIXTYPE)vcnt));
  105.  
  106.     /* set the superclass to 'Object' */
  107.     setivar(cls,SUPERCLASS,object);
  108.  
  109.     /* return the new class */
  110.     return (cls);
  111. }
  112.  
  113. #ifdef WINTERP
  114. /* xlclass_p -- check if object is a class object as created by xlclass() */
  115. int xlclass_p(o_class)
  116.      LVAL o_class;        /* assume type==OBJECT */
  117. {
  118.   return (getclass(o_class) == class);
  119. }
  120. #endif
  121.  
  122. /* xladdivar - enter an instance variable */
  123. xladdivar(cls,var)
  124.   LVAL cls; char *var;
  125. {
  126.     setivar(cls,IVARS,cons(xlenter(var),getivar(cls,IVARS)));
  127. }
  128.  
  129. /* xladdmsg - add a message to a class */
  130. xladdmsg(cls,msg,offset)
  131.   LVAL cls; char *msg; int offset;
  132. {
  133.     extern FUNDEF funtab[];
  134.     LVAL mptr;
  135.  
  136.     /* enter the message selector */
  137.     mptr = entermsg(cls,xlenter(msg));
  138.  
  139.     /* store the method for this message */
  140.     rplacd(mptr,cvsubr(funtab[offset].fd_subr,funtab[offset].fd_type,offset));
  141. }
  142.  
  143. /* xlobgetvalue - get the value of an instance variable */
  144. int xlobgetvalue(pair,sym,pval)
  145.   LVAL pair,sym,*pval;
  146. {
  147.     LVAL cls,names;
  148.     int ivtotal,n;
  149.  
  150.     /* find the instance or class variable */
  151.     for (cls = cdr(pair); objectp(cls); cls = getivar(cls,SUPERCLASS)) {
  152.  
  153.     /* check the instance variables */
  154.     names = getivar(cls,IVARS);
  155.     ivtotal = getivcnt(cls,IVARTOTAL);
  156.     for (n = ivtotal - getivcnt(cls,IVARCNT); n < ivtotal; ++n) {
  157.         if (car(names) == sym) {
  158.         *pval = getivar(car(pair),n);
  159.         return (TRUE);
  160.         }
  161.         names = cdr(names);
  162.     }
  163.  
  164.     /* check the class variables */
  165.     names = getivar(cls,CVARS);
  166.     for (n = 0; consp(names); ++n) {
  167.         if (car(names) == sym) {
  168.         *pval = getelement(getivar(cls,CVALS),n);
  169.         return (TRUE);
  170.         }
  171.         names = cdr(names);
  172.     }
  173.     }
  174.  
  175.     /* variable not found */
  176.     return (FALSE);
  177. }
  178.  
  179. /* xlobsetvalue - set the value of an instance variable */
  180. int xlobsetvalue(pair,sym,val)
  181.   LVAL pair,sym,val;
  182. {
  183.     LVAL cls,names;
  184.     int ivtotal,n;
  185.  
  186.     /* find the instance or class variable */
  187.     for (cls = cdr(pair); objectp(cls); cls = getivar(cls,SUPERCLASS)) {
  188.  
  189.     /* check the instance variables */
  190.     names = getivar(cls,IVARS);
  191.     ivtotal = getivcnt(cls,IVARTOTAL);
  192.     for (n = ivtotal - getivcnt(cls,IVARCNT); n < ivtotal; ++n) {
  193.         if (car(names) == sym) {
  194.         setivar(car(pair),n,val);
  195.         return (TRUE);
  196.         }
  197.         names = cdr(names);
  198.     }
  199.  
  200.     /* check the class variables */
  201.     names = getivar(cls,CVARS);
  202.     for (n = 0; consp(names); ++n) {
  203.         if (car(names) == sym) {
  204.         setelement(getivar(cls,CVALS),n,val);
  205.         return (TRUE);
  206.         }
  207.         names = cdr(names);
  208.     }
  209.     }
  210.  
  211.     /* variable not found */
  212.     return (FALSE);
  213. }
  214.  
  215. /* obisnew - default 'isnew' method */
  216. LVAL obisnew()
  217. {
  218.     LVAL self;
  219.     self = xlgaobject();
  220.     xllastarg();
  221.     return (self);
  222. }
  223.  
  224. /* obclass - get the class of an object */
  225. LVAL obclass()
  226. {
  227.     LVAL self;
  228.     self = xlgaobject();
  229.     xllastarg();
  230.     return (getclass(self));
  231. }
  232.  
  233. /* obshow - show the instance variables of an object */
  234. LVAL obshow()
  235. {
  236.     LVAL self,fptr,cls,names;
  237.     int ivtotal,n;
  238.  
  239.     /* get self and the file pointer */
  240.     self = xlgaobject();
  241.     fptr = (moreargs() ? xlgetfile() : getvalue(s_stdout));
  242.     xllastarg();
  243.  
  244.     /* get the object's class */
  245.     cls = getclass(self);
  246.  
  247.     /* print the object and class */
  248.     xlputstr(fptr,"Object is ");
  249.     xlprint(fptr,self,TRUE);
  250.     xlputstr(fptr,", Class is ");
  251.     xlprint(fptr,cls,TRUE);
  252.     xlterpri(fptr);
  253.  
  254.     /* print the object's instance variables */
  255.     for (; cls; cls = getivar(cls,SUPERCLASS)) {
  256.     names = getivar(cls,IVARS);
  257.     ivtotal = getivcnt(cls,IVARTOTAL);
  258.     for (n = ivtotal - getivcnt(cls,IVARCNT); n < ivtotal; ++n) {
  259.         xlputstr(fptr,"  ");
  260.         xlprint(fptr,car(names),TRUE);
  261.         xlputstr(fptr," = ");
  262.         xlprint(fptr,getivar(self,n),TRUE);
  263.         xlterpri(fptr);
  264.         names = cdr(names);
  265.     }
  266.     }
  267.  
  268.     /* return the object */
  269.     return (self);
  270. }
  271.  
  272. /* clnew - create a new object instance */
  273. LVAL clnew()
  274. {
  275.     LVAL self;
  276.     self = xlgaobject();
  277.     return (newobject(self,getivcnt(self,IVARTOTAL)));
  278. }
  279.  
  280. /* clisnew - initialize a new class */
  281. LVAL clisnew()
  282. {
  283.     LVAL self,ivars,cvars,super;
  284.     int n;
  285.  
  286.     /* get self, the ivars, cvars and superclass */
  287.     self = xlgaobject();
  288.     ivars = xlgalist();
  289.     cvars = (moreargs() ? xlgalist() : NIL);
  290.     super = (moreargs() ? xlgaobject() : object);
  291.     xllastarg();
  292.  
  293.     /* store the instance and class variable lists and the superclass */
  294.     setivar(self,IVARS,ivars);
  295.     setivar(self,CVARS,cvars);
  296.     setivar(self,CVALS,(cvars ? newvector(listlength(cvars)) : NIL));
  297.     setivar(self,SUPERCLASS,super);
  298.  
  299.     /* compute the instance variable count */
  300.     n = listlength(ivars);
  301.     setivar(self,IVARCNT,cvfixnum((FIXTYPE)n));
  302.     n += getivcnt(super,IVARTOTAL);
  303.     setivar(self,IVARTOTAL,cvfixnum((FIXTYPE)n));
  304.  
  305.     /* return the new class object */
  306.     return (self);
  307. }
  308.  
  309. /* clanswer - define a method for answering a message */
  310. LVAL clanswer()
  311. {
  312.     LVAL self,msg,fargs,code,mptr;
  313.  
  314.     /* message symbol, formal argument list and code */
  315.     self = xlgaobject();
  316.     msg = xlgasymbol();
  317.     fargs = xlgalist();
  318.     code = xlgalist();
  319.     xllastarg();
  320.  
  321.     /* make a new message list entry */
  322.     mptr = entermsg(self,msg);
  323.  
  324.     /* setup the message node */
  325.     xlprot1(fargs);
  326.     fargs = cons(s_self,fargs); /* add 'self' as the first argument */
  327.     rplacd(mptr,xlclose(msg,s_lambda,fargs,code,xlenv,xlfenv));    /* changed by NPM -- pass in lexical and functional environment */
  328.     xlpop();
  329.  
  330.     /* return the object */
  331.     return (self);
  332. }
  333.  
  334. /* entermsg - add a message to a class */
  335. LOCAL LVAL entermsg(cls,msg)
  336.   LVAL cls,msg;
  337. {
  338.     LVAL lptr,mptr;
  339.  
  340.     /* lookup the message */
  341.     for (lptr = getivar(cls,MESSAGES); lptr; lptr = cdr(lptr))
  342.     if (car(mptr = car(lptr)) == msg)
  343.         return (mptr);
  344.  
  345.     /* allocate a new message entry if one wasn't found */
  346.     xlsave1(mptr);
  347.     mptr = consa(msg);
  348.     setivar(cls,MESSAGES,cons(mptr,getivar(cls,MESSAGES)));
  349.     xlpop();
  350.  
  351.     /* return the symbol node */
  352.     return (mptr);
  353. }
  354.  
  355. /* sendmsg - send a message to an object */
  356. LOCAL LVAL sendmsg(obj,cls,sym)
  357.   LVAL obj,cls,sym;
  358. {
  359.     LVAL msg,msgcls,method,val,p;
  360.  
  361.     /* look for the message in the class or superclasses */
  362.     for (msgcls = cls; msgcls; ) {
  363.  
  364.     /* lookup the message in this class */
  365.     for (p = getivar(msgcls,MESSAGES); p; p = cdr(p))
  366.         if ((msg = car(p)) && car(msg) == sym)
  367.         goto send_message;
  368.  
  369.     /* look in class's superclass */
  370.     msgcls = getivar(msgcls,SUPERCLASS);
  371.     }
  372.  
  373.     /* message not found */
  374.     xlerror("no method for this message",sym);
  375.  
  376. send_message:
  377.  
  378.     /* insert the value for 'self' (overwrites message selector) */
  379.     *--xlargv = obj;
  380.     ++xlargc;
  381.     
  382.     /* invoke the method */
  383.     if ((method = cdr(msg)) == NULL)
  384.     xlerror("bad method",method);
  385.     switch (ntype(method)) {
  386.     case SUBR:
  387.     val = (*getsubr(method))();
  388.     break;
  389.     case CLOSURE:
  390.     if (gettype(method) != s_lambda)
  391.         xlerror("bad method",method);
  392.     val = evmethod(obj,msgcls,method);
  393.     break;
  394.     default:
  395.     xlerror("bad method",method);
  396.     }
  397.  
  398.     /* after creating an object, send it the ":isnew" message */
  399.     if (car(msg) == k_new && val) {
  400.     xlprot1(val);
  401.     sendmsg(val,getclass(val),k_isnew);
  402.     xlpop();
  403.     }
  404.     
  405.     /* return the result value */
  406.     return (val);
  407. }
  408.  
  409. /* evmethod - evaluate a method */
  410. LOCAL LVAL evmethod(obj,msgcls,method)
  411.   LVAL obj,msgcls,method;
  412. {
  413.     LVAL oldenv,oldfenv,cptr,name,val;
  414.     CONTEXT cntxt;
  415.  
  416.     /* protect some pointers */
  417.     xlstkcheck(3);
  418.     xlsave(oldenv);
  419.     xlsave(oldfenv);
  420.     xlsave(cptr);
  421.  
  422.     /* create an 'object' stack entry and a new environment frame */
  423.     oldenv = xlenv;
  424.     oldfenv = xlfenv;
  425. #ifdef WINTERP            /* note: changed getenv()-->getenvt() due to name conflict with stdlib.h:getenv() */
  426.     xlenv = cons(cons(obj,msgcls),getenvt(method));
  427. #else
  428.     xlenv = cons(cons(obj,msgcls),getenv(method));
  429. #endif                /* WINTERP */
  430.     xlenv = xlframe(xlenv);
  431.     xlfenv = getfenv(method);
  432.  
  433.     /* bind the formal parameters */
  434.     xlabind(method,xlargc,xlargv);
  435.  
  436.     /* setup the implicit block */
  437.     if (name = getname(method))
  438.     xlbegin(&cntxt,CF_RETURN,name);
  439.  
  440.     /* execute the block */
  441.     if (name && setjmp(cntxt.c_jmpbuf))
  442.     val = xlvalue;
  443.     else
  444.     for (cptr = getbody(method); consp(cptr); cptr = cdr(cptr))
  445.         val = xleval(car(cptr));
  446.  
  447.     /* finish the block context */
  448.     if (name)
  449.     xlend(&cntxt);
  450.  
  451.     /* restore the environment */
  452.     xlenv = oldenv;
  453.     xlfenv = oldfenv;
  454.  
  455.     /* restore the stack */
  456.     xlpopn(3);
  457.  
  458.     /* return the result value */
  459.     return (val);
  460. }
  461.  
  462. /* getivcnt - get the number of instance variables for a class */
  463. LOCAL int getivcnt(cls,ivar)
  464.   LVAL cls; int ivar;
  465. {
  466.     LVAL cnt;
  467.     if ((cnt = getivar(cls,ivar)) == NIL || !fixp(cnt))
  468.     xlfail("bad value for instance variable count");
  469.     return ((int)getfixnum(cnt));
  470. }
  471.  
  472. /* listlength - find the length of a list */
  473. LOCAL int listlength(list)
  474.   LVAL list;
  475. {
  476.     int len;
  477.     for (len = 0; consp(list); len++)
  478.     list = cdr(list);
  479.     return (len);
  480. }
  481.  
  482. /* obsymbols - initialize symbols */
  483. obsymbols()
  484. {
  485.     /* enter the object related symbols */
  486.     s_self  = xlenter("SELF");
  487.     k_new   = xlenter(":NEW");
  488.     k_isnew = xlenter(":ISNEW");
  489.  
  490.     /* get the Object and Class symbol values */
  491.     object = getvalue(xlenter("OBJECT"));
  492.     class  = getvalue(xlenter("CLASS"));
  493. }
  494.  
  495. /* xloinit - object function initialization routine */
  496. xloinit()
  497. {
  498.     /* create the 'Class' object */
  499.     class = xlclass("CLASS",CLASSSIZE);
  500.     setelement(class,0,class);
  501.  
  502.     /* create the 'Object' object */
  503.     object = xlclass("OBJECT",0);
  504.  
  505.     /* finish initializing 'class' */
  506.     setivar(class,SUPERCLASS,object);
  507.     xladdivar(class,"IVARTOTAL");    /* ivar number 6 */
  508.     xladdivar(class,"IVARCNT");        /* ivar number 5 */
  509.     xladdivar(class,"SUPERCLASS");    /* ivar number 4 */
  510.     xladdivar(class,"CVALS");        /* ivar number 3 */
  511.     xladdivar(class,"CVARS");        /* ivar number 2 */
  512.     xladdivar(class,"IVARS");        /* ivar number 1 */
  513.     xladdivar(class,"MESSAGES");    /* ivar number 0 */
  514.     xladdmsg(class,":NEW",FT_CLNEW);
  515.     xladdmsg(class,":ISNEW",FT_CLISNEW);
  516.     xladdmsg(class,":ANSWER",FT_CLANSWER);
  517.  
  518.     /* finish initializing 'object' */
  519.     setivar(object,SUPERCLASS,NIL);
  520.     xladdmsg(object,":ISNEW",FT_OBISNEW);
  521.     xladdmsg(object,":CLASS",FT_OBCLASS);
  522.     xladdmsg(object,":SHOW",FT_OBSHOW);
  523. }
  524.  
  525.