home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Fish 'n' More 2
/
fishmore-publicdomainlibraryvol.ii1991xetec.iso
/
fish
/
applications
/
xlispstat
/
src
/
src2.lzh
/
XLisp-Stat
/
objects.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-10-04
|
36KB
|
1,427 lines
/* objects - Additional object functions */
/* XLISP-STAT 2.1 Copyright (c) 1990, by Luke Tierney */
/* Additions to Xlisp 2.1, Copyright (c) 1989 by David Michael Betz */
/* You may give out copies of this software; for conditions see the */
/* file COPYING included with this distribution. */
#include "xlisp.h"
#include "osdef.h"
#ifdef ANSI
#include "xlproto.h"
#include "xlsproto.h"
#else
#include "xlfun.h"
#include "xlsfun.h"
#endif ANSI
#include "xlvar.h"
#include "xlsvar.h"
#ifdef ANSI
LVAL get_self(void),delete_duplicates(LVAL),append_list(LVAL,LVAL),
delete(LVAL,LVAL),check_object(LVAL),find_SC(LVAL),find_S(LVAL),
find_RC(LVAL),find_R(LVAL),find_no_predecessor_list(LVAL,LVAL),
next_object(LVAL,LVAL),trim_S(LVAL,LVAL),trim_R(LVAL,LVAL),
precedence_list(LVAL),calculate_preclist(LVAL),
make_object(LVAL,LVAL),find_own_slot(LVAL,LVAL),find_slot(LVAL,LVAL),
delete_slot(LVAL,LVAL),find_own_method(LVAL,LVAL),find_method(LVAL,LVAL),
delete_method(LVAL,LVAL),message_method(LVAL,LVAL),
set_message_method(LVAL,LVAL,LVAL),sendmsg(LVAL,LVAL),get_cars(LVAL),
find_documentation(LVAL,LVAL,int),get_documentation(LVAL,LVAL),
instance_slots(LVAL,LVAL),get_initial_slot_value(LVAL,LVAL),
callmethod(LVAL,LVAL,int,LVAL *);
int equal(LVAL,LVAL),is_member(LVAL,LVAL),has_duplicates(LVAL),
has_predecessor(LVAL,LVAL),child_position(LVAL,LVAL);
void check_parents(LVAL),add_slot(LVAL,LVAL,LVAL),add_method(LVAL,LVAL,LVAL),
add_documentation(LVAL,LVAL,LVAL),
make_prototype(LVAL,LVAL,LVAL,LVAL,LVAL,int);
#else
LVAL get_self(),delete_duplicates(),append_list(),
delete(),check_object(),find_SC(),find_S(),
find_RC(),find_R(),find_no_predecessor_list(),
next_object(),trim_S(),trim_R(),
precedence_list(),calculate_preclist(),
make_object(),find_own_slot(),find_slot(),
delete_slot(),find_own_method(),find_method(),
delete_method(),message_method(),
set_message_method(),sendmsg(),get_cars(),
find_documentation(,int),get_documentation(),
instance_slots(),get_initial_slot_value(),callmethod();
int equal(),is_member(),has_duplicates(),
has_predecessor(),child_position();
void check_parents(),add_slot(),add_method(),
add_documentation(),
make_prototype();
#endif ANSI
/* macros to handle tracing */
#define trenter(sym,argc,argv) {if (sym) doenter(sym,argc,argv);}
#define trexit(sym,val) {if (sym) doexit(sym,val);}
/***********************************************************************/
/** **/
/** CLASS Definitions **/
/** **/
/***********************************************************************/
/* instance variable numbers for the class 'CLASS' */
# define CVARS 2 /* list of class variable names */
# define CVALS 3 /* list of class variable values */
# define SUPERCLASS 4
# define IVARTOTAL 6
/* time stamp for determining validity of allocated objects */
/* long time_stamp; moved to statinit.c JKL */
/***********************************************************************/
/** **/
/** Utility Functions **/
/** **/
/***********************************************************************/
/* Built in KIND-OF-P function */
LVAL xskind_of_p()
{
LVAL x, y;
x = xlgetarg();
y = xlgetarg();
xllastarg();
return((kind_of_p(x, y)) ? s_true : NIL);
}
LVAL xsobject_null_method() { return(NIL); }
/***********************************************************************/
/***********************************************************************/
/*** ***/
/*** New Object System ***/
/*** ***/
/***********************************************************************/
/***********************************************************************/
#define OBJECT_SIZE 4
#define getslots(x) getelement(x, 1)
#define getmethods(x) getelement(x, 2)
#define getparents(x) getelement(x, 3)
#define getpreclist(x) getelement(x, 4)
#define setslots(x, v) setelement(x, 1, v)
#define setmethods(w, v) setelement(x, 2, v)
#define setparents(x, v) setelement(x, 3, v)
#define setpreclist(x, v) setelement(x, 4, v)
static LVAL object_class, root_object;
int in_send = FALSE;
/***********************************************************************/
/** **/
/** Utility Functions **/
/** **/
/***********************************************************************/
/* get SELF for the current message; signal an error if not in a message */
static LVAL get_self()
{
LVAL p = xlxgetvalue(s_self);
if (! mobject_p(p)) xlerror("bad object", p);
return(p);
}
/* simple form of EQUAL test */
static int equal(x, y)
LVAL x, y;
{
if (x == y) return(TRUE);
else if (consp(x) && consp(y)
&& equal(car(x), car(y)) && equal(cdr(x), cdr(y)))
return(TRUE);
else return(FALSE);
}
/* check if x is a member of list; use simple equal test */
static int is_member(x, list)
LVAL x, list;
{
int result = FALSE;
for (; ! result && consp(list); list = cdr(list))
if (equal(x, car(list))) result = TRUE;
return(result);
}
/* check if list contains any duplicates */
static int has_duplicates(list)
LVAL list;
{
int result = FALSE;
for (; ! result && consp(list); list = cdr(list))
if (is_member(car(list), cdr(list))) result = TRUE;
return(result);
}
/* destructively delete duplicates from list x */
static LVAL delete_duplicates(x)
LVAL x;
{
LVAL last, result;
if (x == NIL) return(NIL);
else if (consp(x)) {
for (; consp(x) && is_member(car(x), cdr(x)); x = cdr(x)) ;
result = x;
for (last = x, x = cdr(x); consp(x); x = cdr(x))
if (is_member(car(x), cdr(x))) rplacd(last, cdr(x));
else last = x;
}
else xlerror("not a list", x);
return(result);
}
/* destructively append y to x */
static LVAL append_list(x, y)
LVAL x, y;
{
LVAL result;
if (x == NIL) result = y;
else if (consp(x)) {
result = x;
for (; consp(cdr(x)); x = cdr(x)) ;
rplacd(x, y);
}
else xlerror("not a list", x);
return(result);
}
/* destructively delete x from list */
static LVAL delete(x, list)
LVAL x, list;
{
return(xscallsubr2(xdelete, x, list));
}
/***********************************************************************/
/** **/
/** Predicate and Stack Access Functions **/
/** **/
/***********************************************************************/
int mobject_p(x)
LVAL x;
{
return(objectp(x) && getclass(x) == object_class && getsize(x) == 5);
}
static LVAL check_object(object)
LVAL object;
{
if (! mobject_p(object)) xlerror("bad object", object);
else return(object);
}
int kind_of_p(x, y)
LVAL x, y;
{
if (! mobject_p(x) || ! mobject_p(y)) return(FALSE);
return(is_member(y, getpreclist(x)));
}
LVAL xsgetmobject() { return(check_object(xlgetarg())); }
/***********************************************************************/
/** **/
/** Precedence List Functions **/
/** **/
/***********************************************************************/
/* find set of object and ancestors */
static LVAL find_SC(object)
LVAL object;
{
return(copylist(getpreclist(check_object(object))));
}
/* find set of object and ancestors */
static LVAL find_S(object)
LVAL object;
{
LVAL result, parents;
xlstkcheck(2);
xlprotect(object);
xlsave(result);
parents = getparents(object); /* not needed: in macro JKL */
for (/*result = NIL*/; consp(parents); parents = cdr(parents))
result = append_list(find_SC(car(parents)), result);
result = cons(object, result);
result = delete_duplicates(result);
xlpopn(2);
return(result);
}
/* find local precedence ordering */
static LVAL find_RC(object)
LVAL object;
{
LVAL list, next;
xlstkcheck(2);
xlprotect(object);
xlsave(list);
list = copylist(getparents(check_object(object)));
for (next = list; consp(next); next = cdr(next)) {
rplaca(next, cons(object, car(next)));
object = cdr(car(next));
}
xlpopn(2);
return(list);
}
/* find partial precedence ordering */
static LVAL find_R(S)
LVAL S;
{
LVAL result;
xlstkcheck(2);
xlprotect(S);
xlsave(result);
for (/*result = NIL*/; consp(S); S = cdr(S)) /* not needed JKL */
result = append_list(result, find_RC(car(S)));
result = delete_duplicates(result);
xlpopn(2);
return(result);
}
/* check if x has a predecessor according to R */
static int has_predecessor(x, R)
LVAL x, R;
{
int result = FALSE;
for (; ! result && consp(R); R = cdr(R))
if (consp(car(R)) && x == cdr(car(R))) result = TRUE;
return(result);
}
/* find list of objects in S without predecessors, by R */
static LVAL find_no_predecessor_list(S, R)
LVAL S, R;
{
LVAL result;
xlstkcheck(3);
xlprotect(S);
xlprotect(R);
xlsave(result);
for (/*result = NIL*/; consp(S); S = cdr(S))/* not needed JKL */
if (! has_predecessor(car(S), R))
result = cons(car(S), result);
xlpopn(3);
return(result);
}
/* find the position of child, if any, of x in P, the list found so far */
static int child_position(x, P)
LVAL x, P;
{
int count;
for (count = 0; consp(P); P = cdr(P), count++)
if (is_member(x, getparents(car(P)))) return(count);
return(-1);
}
/* find the next object in the precedence list from objects with no */
/* predecessor and current list. */
static LVAL next_object(no_preds, P)
LVAL no_preds, P;
{
LVAL result;
int count, tcount;
if (! consp(no_preds)) result = NIL;
else if (! consp(cdr(no_preds))) result = car(no_preds);
else {
for (count = -1, result = NIL; consp(no_preds); no_preds = cdr(no_preds)) {
tcount = child_position(car(no_preds), P);
if (tcount > count) {
result = car(no_preds);
count = tcount;
}
}
}
return(result);
}
/* remove object x from S */
static LVAL trim_S(x, S)
LVAL x, S;
{
LVAL next;
while (consp(S) && x == car(S)) S = cdr(S);
for (next = S; consp(S) && consp(cdr(next));)
if (x == car(cdr(next))) rplacd(next, cdr(cdr(next)));
else next = cdr(next);
return(S);
}
/* remove all pairs containing x from R. x is assumed to have no */
/* predecessors, so only the first position is checked. */
static LVAL trim_R(x, R)
LVAL x, R;
{
LVAL next;
while (consp(R) && consp(car(R)) && x == car(car(R))) R = cdr(R);
for (next = R; consp(R) && consp(cdr(next));)
if (consp(car(next)) && x == car(car(cdr(next))))
rplacd(next, cdr(cdr(next)));
else next = cdr(next);
return(R);
}
/* calculat the object's precedence list */
static LVAL precedence_list(object)
LVAL object;
{
LVAL R, S, P, no_preds, next;
check_object(object);
xlstkcheck(5);
xlprotect(object);
xlsave(R);
xlsave(S);
xlsave(P);
xlsave(no_preds);
S = find_S(object);
R = find_R(S);
P = NIL;
while (consp(S)) {
no_preds = find_no_predecessor_list(S, R);
next = next_object(no_preds, P);
if (next == NIL) xlfail("inconsistent precedence order");
else {
P = append_list(P, consa(next));
S = trim_S(next, S);
R = trim_R(next, R);
}
}
xlpopn(5);
return(P);
}
/***********************************************************************/
/** **/
/** Object Construction Functions **/
/** **/
/***********************************************************************/
static LVAL calculate_preclist(object)
LVAL object;
{
LVAL result, parent, parents;
parents = getparents(check_object(object));
if (consp(parents)) {
xlstkcheck(2);
xlprotect(object);
xlsave(result);
if (! consp(cdr(parents))) {
parent = check_object(car(parents));
result = getpreclist(parent);
result = cons(object, result);
}
else result = precedence_list(object);
xlpopn(2);
}
else xlerror("bad parent list", parents);
return(result);
}
static void check_parents(parents)
LVAL parents;
{
if (parents == NIL) return;
else if (mobject_p(parents)) return;
else if (consp(parents)) {
for (; consp(parents); parents = cdr(parents))
check_object(car(parents));
}
else xlerror("bad parents", parents);
if (consp(parents) && has_duplicates(parents))
xlfail("parents may not contain duplicates");
}
static LVAL make_object(parents, object)
LVAL parents, object;
{
check_parents(parents);
xlstkcheck(2);
xlprotect(parents);
xlprotect(object);
if (! mobject_p(object))
object = newobject(object_class, OBJECT_SIZE);
setpreclist(object, getpreclist(root_object));
if (parents == NIL) setparents(object, consa(root_object));
else if (mobject_p(parents)) setparents(object, consa(parents));
else setparents(object, parents);
setpreclist(object, calculate_preclist(object));
xlpopn(2);
return(object);
}
LVAL xsmake_object()
{
LVAL parents, object;
xlsave1(parents);
parents = makearglist(xlargc, xlargv);
object = make_object(parents, NIL);
xlpop();
return(object);
}
LVAL xsreparent_object()
{
LVAL parents, object;
LVAL s_hardware_object = xlenter("HARDWARE-OBJECT-PROTO");
object = xsgetmobject();
xlsave1(parents);
if (kind_of_p(object, getvalue(s_hardware_object)))
send_message(object, sk_dispose);
parents = makearglist(xlargc, xlargv);
object = make_object(parents, object);
xlpop();
return(object);
}
/***********************************************************************/
/** **/
/** Slot Access Functions **/
/** **/
/***********************************************************************/
#define make_slot_entry(x, y) cons((x), (y))
#define slot_entry_p(x) consp((x))
#define slot_entry_key(x) car((x))
#define slot_entry_value(x) cdr((x))
#define set_slot_entry_value(x, v) rplacd((x), (v))
static LVAL find_own_slot(x, slot)
LVAL x, slot;
{
LVAL slots;
if (! mobject_p(x)) return(NIL);
for (slots = getslots(x); consp(slots); slots = cdr(slots))
if (slot_entry_p(car(slots)) && slot_entry_key(car(slots)) == slot)
return(car(slots));
return(NIL);
}
static LVAL find_slot(x, slot)
LVAL x, slot;
{
LVAL slot_entry, preclist;
if (! mobject_p(x)) slot_entry = NIL;
else {
for (slot_entry = NIL, preclist = getpreclist(x);
slot_entry == NIL && consp(preclist);
preclist = cdr(preclist))
slot_entry = find_own_slot(car(preclist), slot);
}
return(slot_entry);
}
static void add_slot(x, slot, value)
LVAL x, slot, value;
{
LVAL slot_entry;
xlstkcheck(3);
xlprotect(x);
xlprotect(slot);
xlprotect(value);
check_object(x);
if (! symbolp(slot)) xlerror("not a symbol", slot);
slot_entry = find_own_slot(x, slot);
if (slot_entry != NIL) set_slot_entry_value(slot_entry, value);
else {
xlsave1(slot_entry);
slot_entry = make_slot_entry(slot, value);
setslots(x, cons(slot_entry, getslots(x)));
xlpop();
}
xlpopn(3);
}
static LVAL delete_slot(x, slot)
LVAL x, slot;
{
LVAL entry, slots;
if (! mobject_p(x)) return(NIL);
else {
entry = find_own_slot(x, slot);
if (entry == NIL) return(NIL);
else {
slots = getslots(x);
setslots(x, delete(entry, slots));
return(s_true);
}
}
}
LVAL slot_value(x, slot)
LVAL x, slot;
{
LVAL slot_entry;
check_object(x);
slot_entry = find_slot(x, slot);
if (slot_entry_p(slot_entry)) return(slot_entry_value(slot_entry));
else xlerror("no slot by this name", slot);
}
#define CONSTRAINTHOOKS
void check_hooks(object, sym, slot)
LVAL object, sym;
int slot;
{
#ifdef CONSTRAINTHOOKS
LVAL hook, hooksym, olddenv;
hooksym = (slot) ? s_set_slot_hook : s_message_hook;
hook = getvalue(hooksym);
if (hook != s_unbound && hook != NIL) {
/* rebind the hook function to nil */
olddenv = xldenv;
xldbind(hooksym,NIL);
xsfuncall2(hook, object, sym);
/* unbind the hook symbol */
xlunbind(olddenv);
}
#endif CONSTRAINTHOOKS
}
LVAL set_slot_value(x, slot, value)
LVAL x, slot, value;
{
LVAL slot_entry;
check_object(x);
slot_entry = find_own_slot(x, slot);
if (slot_entry_p(slot_entry)) {
set_slot_entry_value(slot_entry, value);
check_hooks(x, slot_entry_key(slot_entry), TRUE);
}
else {
if (find_slot(x, slot) != NIL)
xlerror("object does not own slot", slot);
else xlerror("no slot by this name", slot);
}
return(value);
}
LVAL xshas_slot()
{
LVAL x, slot, own, slot_entry;
x = xsgetmobject();
slot = xlgasymbol();
if (! xlgetkeyarg(sk_own, &own)) own = NIL;
slot_entry = (own == NIL) ? find_slot(x, slot) : find_own_slot(x, slot);
return((slot_entry != NIL) ? s_true : NIL);
}
LVAL xsadd_slot()
{
LVAL x, slot, value;
x = xsgetmobject();
slot = xlgasymbol();
value = (moreargs()) ? xlgetarg() : NIL;
xllastarg();
add_slot(x, slot, value);
return(value);
}
LVAL xsdelete_slot()
{
LVAL x, slot;
x = xsgetmobject();
slot = xlgasymbol();
xllastarg();
return(delete_slot(x, slot));
}
LVAL xsslot_value()
{
LVAL x, slot, value;
int set = FALSE;
x = get_self(); /*xsgetmobject();*/
slot = xlgasymbol();
if (moreargs()) {
set = TRUE;
value = xlgetarg();
}
xllastarg();
if (set) return(set_slot_value(x, slot, value));
else return(slot_value(x, slot));
}
/***********************************************************************/
/** **/
/** Method Access Functions **/
/** **/
/***********************************************************************/
#define make_method_entry(x, y) cons((x), (y))
#define method_entry_p(x) consp((x))
#define method_entry_key(x) car((x))
#define method_entry_method(x) cdr((x))
#define set_method_entry_method(x, v) rplacd((x), (v))
static LVAL find_own_method(x, selector)
LVAL x, selector;
{
LVAL methods;
if (! mobject_p(x)) return(NIL);
for (methods = getmethods(x); consp(methods); methods = cdr(methods))
if (method_entry_p(car(methods))
&& method_entry_key(car(methods)) == selector)
return(car(methods));
return(NIL);
}
static LVAL find_method(x, selector)
LVAL x, selector;
{
LVAL method_entry, preclist;
if (! mobject_p(x)) method_entry = NIL;
else {
for (method_entry = NIL, preclist = getpreclist(x);
method_entry == NIL && consp(preclist);
preclist = cdr(preclist))
method_entry = find_own_method(car(preclist), selector);
}
return(method_entry);
}
static void add_method(x, selector, method)
LVAL x, selector, method;
{
LVAL method_entry;
xlstkcheck(3);
xlprotect(x);
xlprotect(selector);
xlprotect(method);
check_object(x);
if (! symbolp(selector)) xlerror("not a symbol", selector);
method_entry = find_own_method(x, selector);
if (method_entry != NIL)
set_method_entry_method(method_entry, method);
else {
xlsave1(method_entry);
method_entry = make_method_entry(selector, method);
setmethods(x, cons(method_entry, getmethods(x)));
xlpop();
}
xlpopn(3);
}
static LVAL delete_method(x, selector)
LVAL x, selector;
{
LVAL entry, methods;
if (! mobject_p(x)) return(NIL);
else {
entry = find_own_method(x, selector);
if (entry == NIL) return(NIL);
else {
methods = getmethods(x);
setmethods(x, delete(entry, methods));
return(s_true);
}
}
}
static LVAL message_method(x, selector)
LVAL x, selector;
{
LVAL method_entry;
check_object(x);
method_entry = find_method(x, selector);
if (method_entry_p(method_entry))
return(method_entry_method(method_entry));
else xlfail("no method for this selector");
}
#ifdef DODO
static LVAL set_message_method(x, selector, method)
LVAL x, selector, method;
{
LVAL method_entry;
check_object(x);
method_entry = find_method(x, selector);
if (method_entry_p(method_entry))
set_method_entry_method(method_entry, method);
else xlfail("no method for this selector");
return(method);
}
#endif DODO
LVAL xshas_method()
{
LVAL x, selector, own, method_entry;
x = xsgetmobject();
selector = xlgasymbol();
if (! xlgetkeyarg(sk_own, &own)) own = NIL;
method_entry = (own == NIL)
? find_method(x, selector) : find_own_method(x, selector);
return((method_entry != NIL) ? s_true : NIL);
}
LVAL xsadd_method()
{
LVAL x, selector, method;
x = xsgetmobject();
selector = xlgasymbol();
method = (moreargs()) ? xlgetarg() : NIL;
xllastarg();
add_method(x, selector, method);
return(method);
}
LVAL xsdelete_method()
{
LVAL x, selector;
x = xsgetmobject();
selector = xlgasymbol();
xllastarg();
return(delete_method(x, selector));
}
LVAL xsmessage_method()
{
LVAL x, selector;
x = xsgetmobject();
selector = xlgasymbol();
xllastarg();
return(message_method(x, selector));
}
/***********************************************************************/
/** **/
/** Message Sending Functions **/
/** **/
/***********************************************************************/
static LVAL current_preclist = NIL;
static LVAL current_selector = NIL;
/*#define SAFEMESS*/
#ifndef SAFEMESS
static LVAL callmethod(method, object, argc, argv)
LVAL method, object, *argv;
int argc;
{
LVAL *newfp;
int i;
/* build a new argument stack frame */
newfp = xlsp;
pusharg(cvfixnum((FIXTYPE)(newfp - xlfp)));
pusharg(method);
pusharg(cvfixnum((FIXTYPE) (argc + 1)));
/* push each argument */
pusharg(object);
for (i = 0; i < argc; i++) pusharg(argv[i]);
/* establish the new stack frame */
xlfp = newfp;
return(xlapply(argc + 1));
}
#endif /* SAFEMESS */
static LVAL sendmsg(object, selector)
LVAL object, selector;
{
LVAL method_entry, method, old_preclist, preclist, val, old_selector;
LVAL tracing = NIL;
#ifdef SAFEMESS
LVAL args;
#endif
old_selector = current_selector;
current_selector = selector;
/* look for the message in the precedence list */
old_preclist = current_preclist;
for (method_entry = NIL, preclist = current_preclist;
method_entry == NIL && consp(preclist);
preclist = cdr(preclist)) {
method_entry = find_own_method(car(preclist), selector);
current_preclist = preclist;
}
if (method_entry == NIL)
xlerror("no method for this message", selector);
else if (! method_entry_p(method_entry)) xlfail("bad method entry");
else method = method_entry_method(method_entry);
/* invoke the method */
if (getvalue(s_tracelist) && is_member(selector,getvalue(s_tracelist)))
tracing = selector;
trenter(tracing,xlargc,xlargv);
#ifdef SAFEMESS
xlsave1(args);
args = makearglist(xlargc, xlargv);
args = cons(object, args);
val = xlapply(pushargs(method, args));
xlpop();
#else
val = callmethod(method, object, xlargc, xlargv);
#endif /* SAFEMESS */
trexit(tracing,val);
current_preclist = old_preclist;
current_selector = old_selector;
check_hooks(object, method_entry_key(method_entry), FALSE);
return(val);
}
/* send message with arguments on the stack */
LVAL send_message_stk(object, selector)
LVAL object, selector;
{
LVAL old_preclist, result;
int old_in_send = in_send;
old_preclist = current_preclist;
current_preclist = getpreclist(object);
in_send = TRUE;
result = sendmsg(object, selector);
current_preclist = old_preclist;
in_send = old_in_send;
return(result);
}
/* xmsendsuper - send a message to the superobject of an object */
LVAL xmsendsuper()
{
LVAL old_preclist, object, result;
int old_in_send = in_send;
object = get_self();
old_preclist = current_preclist;
if (! consp(current_preclist))
xlfail("no more objects in precedence list");
current_preclist = cdr(current_preclist);
in_send = TRUE;
result = sendmsg(object, xlgasymbol());
current_preclist = old_preclist;
in_send = old_in_send;
return(result);
}
/* xscall_next - call inherited version of current method */
LVAL xscall_next()
{
LVAL old_preclist, object, result;
int old_in_send = in_send;
object = get_self();
old_preclist = current_preclist;
if (! consp(current_preclist))
xlfail("no more objects in precedence list");
current_preclist = cdr(current_preclist);
in_send = TRUE;
result = sendmsg(object, current_selector);
current_preclist = old_preclist;
in_send = old_in_send;
return(result);
}
LVAL xmsend()
{
LVAL object, old_preclist, result;
int old_in_send = in_send;
object = xlgaobject();
if (! mobject_p(object)) return(NIL);
old_preclist = current_preclist;
current_preclist = getpreclist(object);
in_send = TRUE;
result = sendmsg(object, xlgasymbol());
current_preclist = old_preclist;
in_send = old_in_send;
return(result);
}
LVAL xscall_method()
{
LVAL object, self, old_preclist, result;
int old_in_send = in_send;
object = xlgaobject();
self = get_self();
old_preclist = current_preclist;
current_preclist = getpreclist(object);
in_send = TRUE;
result = sendmsg(self, xlgasymbol());
current_preclist = old_preclist;
in_send = old_in_send;
return(result);
}
void print_mobject(object, stream)
LVAL object, stream;
{
send_message_1L(object, sk_print, stream);
}
LVAL xsshow_object()
{
LVAL x, fptr;
x = xsgetmobject();
fptr = (moreargs() ? xlgetfile() : getvalue(s_stdout));
xllastarg();
xlputstr(fptr, "Slots = "); xlprint(fptr, getslots(x), TRUE); xlterpri(fptr);
xlputstr(fptr, "Methods = "); xlprint(fptr, getmethods(x), TRUE); xlterpri(fptr);
xlputstr(fptr, "Parents = "); xlprint(fptr, getparents(x), TRUE); xlterpri(fptr);
xlputstr(fptr, "Precedence List = "); xlprint(fptr, getpreclist(x), TRUE); xlterpri(fptr);
return(NIL);
}
LVAL xsparents()
{
LVAL x;
x = xsgetmobject();
xllastarg();
return(copylist(getparents(x)));
}
LVAL xsprecedence_list()
{
LVAL x;
x = xsgetmobject();
xllastarg();
return(copylist(getpreclist(x)));
}
static LVAL get_cars(x)
LVAL x;
{
LVAL next;
for (next = x; consp(next); next = cdr(next))
if (consp(car(next)))
rplaca(next, car(car(next)));
return(x);
}
LVAL xsobject_methods()
{
LVAL x;
x = xsgetmobject();
xllastarg();
return(get_cars(copylist(getmethods(x))));
}
LVAL xsobject_slots()
{
LVAL x;
x = xsgetmobject();
xllastarg();
return(get_cars(copylist(getslots(x))));
}
void statobsymbols()
{
object_class = getvalue(xlenter("OBJECT"));
root_object = getvalue(xlenter("*OBJECT*"));
}
int lex_slot_value(object, sym, pval)
LVAL object, sym, *pval;
{
int has = (find_slot(object, sym) != NIL);
if (has) *pval = slot_value(object, sym);
return(has);
}
void object_isnew(object)
LVAL object;
{
LVAL slots, sym, ksym, value;
for (slots = getslots(object); consp(slots); slots = cdr(slots)) {
sym = car(car(slots));
if (! symbolp(sym)) xlerror("bad slot entry", car(slots));
sprintf(buf, ":%s", getstring(getpname(sym)));
ksym = xlenter(buf);
if (xlgetkeyarg(ksym, &value)) set_slot_value(object, sym, value);
}
}
LVAL xsobject_isnew()
{
LVAL object;
object = xsgetmobject();
object_isnew(object);
return(object);
}
#define FIRST_METHOD_OFFSET 300
/* xsaddmsg - add a message to an object */
void xsaddmsg(object, str)
LVAL object;
char *str;
{
LVAL fcn;
extern FUNDEF funtab[];
static offset = FIRST_METHOD_OFFSET;
xlsave1(fcn);
fcn = cvsubr(funtab[offset].fd_subr,funtab[offset].fd_type,offset);
add_method(object, xlenter(str), fcn);
xlpop();
offset++;
}
void xsaddslot(object, str)
LVAL object;
char *str;
{
add_slot(object, xlenter(str), NIL);
}
LVAL xsnewproto(str, parents)
char *str;
LVAL parents;
{
LVAL sym = xlenter(str), object;
xlsave1(object);
object = make_object(parents, NIL);
make_prototype(object, sym, NIL, NIL, NIL, TRUE);
xlpop();
return(object);
}
LVAL init_root_object()
{
LVAL s__object_ = xlenter("*OBJECT*");
object_class = getvalue(xlenter("OBJECT"));
root_object = newobject(object_class, OBJECT_SIZE);
setvalue(s__object_, root_object);
setpreclist(root_object, consa(root_object));
add_slot(root_object, s_instance_slots, NIL);
add_slot(root_object, s_proto_name, s__object_);
return(root_object);
}
static LVAL find_documentation(x, sym, add)
LVAL x, sym;
int add;
{
LVAL doc;
if (! mobject_p(x)) return(NIL);
doc = find_own_slot(x, s_documentation);
if (doc == NIL && add) add_slot(x, s_documentation, NIL);
if (consp(doc)) doc = cdr(doc);
for (; consp(doc); doc = cdr(doc))
if (consp(car(doc)) && car(car(doc)) == sym) return(car(doc));
return(NIL);
}
/* x should be protected from gc before calling add_slot */
static void add_documentation(x, sym, value)
LVAL x, sym, value;
{
LVAL doc_entry;
xlstkcheck(3);
xlprotect(x);
xlprotect(sym);
xlprotect(value);
check_object(x);
if (! symbolp(sym)) xlerror("not a symbol", sym);
doc_entry = find_documentation(x, sym, TRUE);
if (doc_entry != NIL) rplacd(doc_entry, value);
else {
xlsave1(doc_entry);
doc_entry = cons(sym, value);
set_slot_value(x,
s_documentation,
cons(doc_entry, slot_value(x, s_documentation)));
xlpop();
}
xlpopn(3);
}
static LVAL get_documentation(x, sym)
LVAL x, sym;
{
LVAL doc_entry; /* changed JKL */
#ifdef DODO
LVAL list;
#endif DODO
check_object(x);
#ifdef DODO /* this only looks in the object itself! */
for (list = getpreclist(x); consp(list); list = cdr(list)) {
doc_entry = find_documentation(x, sym, FALSE);
if (doc_entry != NIL) break;
}
#endif DODO
doc_entry = find_documentation(x, sym, FALSE);
return (consp(doc_entry) ? cdr(doc_entry) : NIL);
}
LVAL xsobject_documentation()
{
LVAL x, sym, val;
x = xsgetmobject();
sym = xlgasymbol();
if (moreargs()) {
val = xlgetarg();
add_documentation(x, sym, val);
}
return(get_documentation(x, sym));
}
LVAL xsdefmeth()
{
LVAL object, sym, fargs, arglist, fcn;
xlstkcheck(3);
xlsave(fargs);
xlsave(arglist);
xlsave(fcn);
object = xleval(xlgetarg());
sym = xlgasymbol();
fargs = xlgalist();
arglist = makearglist(xlargc,xlargv);
if (! mobject_p(object)) xlerror("bad object", object);
/* install documentation string */
if (consp(arglist) && stringp(car(arglist)) && consp(cdr(arglist))) {
add_documentation(object, sym, car(arglist));
arglist = cdr(arglist);
}
/* create a new function definition */
fargs = cons(s_self, fargs);
fcn = xlclose(sym, s_lambda, fargs, arglist, xlenv, xlfenv);
/* add the method to the object */
add_method(object, sym, fcn);
/* restore the stack and return the symbol */
xlpopn(3);
return (sym);
}
/***********************************************************************/
/** **/
/** Prototype Construction Functions **/
/** **/
/***********************************************************************/
static LVAL instance_slots(x, slots)
LVAL x, slots;
{
LVAL parents = getparents(x), result, sym, temp, tail;
xlsave1(result);
result = copylist(slots); /* redundant equation to NIL in macro JKL */
result = delete_duplicates(result);
for (tail = result; consp(tail) && consp(cdr(tail)); tail = cdr(tail));
for (; consp(parents); parents = cdr(parents)) {
for (temp = slot_value(car(parents), s_instance_slots);
consp(temp);
temp = cdr(temp)) {
sym = car(temp);
if (! is_member(sym, result)) {
if (result == NIL) {
result = consa(sym);
tail = result;
}
else {
rplacd(tail, consa(sym));
tail = cdr(tail);
}
}
}
}
xlpop();
return(result);
}
static LVAL get_initial_slot_value(object, slot)
LVAL object, slot;
{
LVAL entry = find_slot(object, slot);
return((entry != NIL) ? cdr(entry) : NIL);
}
static void make_prototype(object, name, ivars, cvars, doc, set)
LVAL object, name, ivars, cvars, doc;
int set;
{
LVAL slot;
xlprot1(ivars);
ivars = instance_slots(object, ivars);
add_slot(object, s_instance_slots, ivars);
add_slot(object, s_proto_name, name);
for (; consp(ivars); ivars = cdr(ivars)) {
slot = car(ivars);
add_slot(object, slot, get_initial_slot_value(object, slot));
}
for (; consp(cvars); cvars = cdr(cvars))
add_slot(object, car(cvars), NIL);
if (doc != NIL && stringp(doc))
add_documentation(object, xlenter("PROTO"), doc);
if (set) setvalue(name, object);
xlpop();
}
void xsaddinstanceslot(x, s)
LVAL x;
char *s;
{
LVAL sym = xlenter(s), ivars = slot_value(x, s_instance_slots);
if (! is_member(sym, ivars)) {
add_slot(x, sym, get_initial_slot_value(x, sym));
set_slot_value(x, s_instance_slots, cons(sym, ivars));
}
}
void xssetslotval(x, s, val)
LVAL x, val;
char *s;
{
set_slot_value(x, xlenter(s), val);
}
LVAL xsdefproto()
{
LVAL object, name, ivars, cvars, parents, doc;
xlstkcheck(5);
xlsave(object);
xlsave(ivars);
xlsave(cvars);
xlsave(parents);
xlsave(doc);
name = xlgasymbol();
ivars = (moreargs()) ? xleval(ivars = xlgetarg()) : NIL;
cvars = (moreargs()) ? xleval(cvars = xlgetarg()) : NIL;
parents = (moreargs()) ? xleval(parents = xlgetarg()) : NIL;
doc = (moreargs()) ? xleval(doc = xlgetarg()) : NIL;
if (! listp(parents)) parents = consa(parents);
object = make_object(parents, NIL);
make_prototype(object, name, ivars, cvars, doc, TRUE);
xlpopn(5);
return(name);
}
LVAL xsmakeproto()
{
LVAL object, name, ivars;
object = xsgetmobject();
name = xlgasymbol();
ivars = (moreargs()) ? xlgetarg() : NIL;
make_prototype(object, name, ivars, NIL, NIL, TRUE);
return(object);
}
LVAL clanswer () { return(NIL); }
LVAL clisnew () { return(NIL); }
LVAL clnew () { return(NIL); }
void obsymbols () {}
LVAL obclass () { return(NIL); }
LVAL obshow () { return(NIL); }
LVAL obisnew () { return(NIL); }
LVAL xsend () { return(NIL); }
int xlobgetvalue (a, b, c) LVAL a,b,*c; { return(FALSE); }
int xlobsetvalue (a, b, c) LVAL a,b,c; { return(FALSE); }
LVAL xsendsuper () { return(NIL); }
void xloinit () {}