#include <../../nrnconf.h> #include "hoc.h" #include "hocstr.h" #include "parse.h" #include "hocassrt.h" #include "hoclist.h" #include "nrnmpi.h" #include #define PDEBUG 0 extern Symlist *hoc_symlist; extern Symlist* hoc_built_in_symlist; extern Object **hoc_objpop(); extern double *hoc_pxpop(); extern double hoc_opasgn(); extern double chkarg(); extern char **hoc_strpop(); extern Symbol *hoc_table_lookup(); extern Symbol *hoc_install(); extern Object** hoc_objgetarg(); extern Object** hoc_temp_objptr(); extern Object* hoc_pop_object(); extern Datum* hoc_look_inside_stack(); extern Object* hoc_obj_look_inside_stack(); #define JAVA2NRN 1 #if JAVA2NRN /* #include "java2nrn.h" */ extern Symbol* java2nrn_class(); void* (*p_java2nrn_cons)(); /* returns pointer to java object */ void (*p_java2nrn_destruct)(); Pfrd p_java2nrn_dmeth; Pfrs p_java2nrn_smeth; Pfro p_java2nrn_ometh; #endif #if USE_PYTHON Symbol* nrnpy_pyobj_sym_; void (*nrnpy_py2n_component)(Object* o, Symbol* s, int nindex, int isfunc); void (*nrnpy_hpoasgn)(Object* o, int type); #endif #if CABLE #include "section.h" int section_object_seen; struct Section* nrn_sec_pop(); double* nrn_rangepointer(); static int connect_obsec_; #endif #define PUBLIC_TYPE 1 #define EXTERNAL_TYPE 2 static call_constructor(); static free_objectdata(); extern Symbol* hoc_decl(); int hoc_print_first_instance = 1; extern FILE* hoc_fin; static Symbol* hoc_obj_; hoc_install_hoc_obj() { hoc_oc("objref hoc_obj_[2]\n"); hoc_obj_ = hoc_lookup("hoc_obj_"); } Object* hoc_obj_get(i) int i; { Object** p = hoc_objectdata[hoc_obj_->u.oboff].pobj; if (p) { return p[i]; }else{ return (Object*)0; } } void hoc_obj_set(i, obj) int i; Object* obj; { Object** p = hoc_objectdata[hoc_obj_->u.oboff].pobj; hoc_obj_ref(obj); hoc_dec_refcount(p + i); p[i] = obj; } char* hoc_object_name(ob) Object* ob; { static char s[100]; if (ob) { Sprintf(s, "%s[%d]", ob->template->sym->name, ob->index); }else{ Sprintf(s, "NULLobject"); } return s; } int hoc_total_array(s) /* total number of elements in array pointer */ Symbol *s; { int total = 1, i; Arrayinfo* a = OPARINFO(s); if (a) { for (i = a->nsub-1; i>=0; --i) { total *= a->sub[i]; } } return total; } int hoc_total_array_data(s, obd) /* total number of elements in array pointer */ Symbol *s; Objectdata* obd; { Arrayinfo* a; int total = 1, i; if (!obd) { a = s->arayinfo; }else switch (s->type) { #if CABLE case RANGEVAR: a = s->arayinfo; break; #endif default: a = obd[s->u.oboff + 1].arayinfo; break; } if (a) { for (i = a->nsub-1; i>=0; --i) { total *= a->sub[i]; } } return total; } static int icntobjectdata=0; Object* hoc_thisobject; Objectdata *hoc_objectdata = (Objectdata *)0; Objectdata *hoc_top_level_data; extern Symlist *hoc_top_level_symlist; static int icnttoplevel; int hoc_in_template=0; hoc_push_current_object() { hoc_push_object(hoc_thisobject); } Objectdata* hoc_objectdata_save() { if (hoc_objectdata == hoc_top_level_data) { return 0; }else{ return hoc_objectdata; } } Objectdata* hoc_objectdata_restore(obdsav) Objectdata* obdsav; { if (obdsav) { return obdsav; }else{ return hoc_top_level_data; } } hoc_obvar_declare(sym, type, pmes) Symbol *sym; int type, pmes; { if (sym->type != UNDEF) { return; } assert(sym->public != 2); if (pmes && hoc_symlist == hoc_top_level_symlist) { if (nrnmpi_myid == 0 &&(hoc_print_first_instance || (hoc_fin == stdin))) { NOT_PARALLEL_SUB(printf("first instance of %s\n", sym->name);) } sym->defined_on_the_fly = 1; } hoc_install_object_data_index(sym); sym->type = type; switch (type) { case VAR: /*printf("hoc_obvar_declare %s\n", sym->name);*/ OPVAL(sym) = (double *)ecalloc(1, sizeof(double)); break; case STRING: OPSTR(sym) = (char **)0; break; case OBJECTVAR: break; #if CABLE case SECTION: OPSECITM(sym) = (struct Item**)0; break; #endif default: hoc_execerror(sym->name, "can't declare this in obvar_declare"); break; } } /*-----------------------------------------------*/ /* template stack so nested templates are ok */ typedef union { Symbol *sym; Symlist *symlist; Objectdata *odata; Object* o; int i; }Templatedatum; #define NTEMPLATESTACK 20 static Templatedatum templatestack[NTEMPLATESTACK]; static Templatedatum *templatestackp = templatestack; static Templatedatum *poptemplate() { if (templatestackp == templatestack) { hoc_execerror("templatestack underflow", (char *)0); } return (--templatestackp); } #define pushtemplatesym(arg) chktemplate(); (templatestackp++)->sym = arg #define pushtemplatesymlist(arg) chktemplate(); (templatestackp++)->symlist = arg #define pushtemplatei(arg) chktemplate(); (templatestackp++)->i = arg #define pushtemplateodata(arg) chktemplate(); (templatestackp++)->odata = arg #define pushtemplateo(arg) chktemplate(); (templatestackp++)->o = arg static chktemplate(){ if (templatestackp == templatestack+NTEMPLATESTACK) { templatestackp = templatestack; hoc_execerror("templatestack overflow", (char *)0); } } /*------------------------------------------------*/ /* mostly to allow saving of objects */ #define OBJ_STACK_SIZE 10 static Object* obj_stack_[OBJ_STACK_SIZE+1]; /* +1 so we can see the most recent pushed */ static obj_stack_loc; hoc_object_push() { Object* ob = *hoc_objgetarg(1); if (ob->template->constructor) { hoc_execerror("Can't do object_push for built-in class", 0); } if (obj_stack_loc >= OBJ_STACK_SIZE) { hoc_execerror("too many object context stack depth", 0); } obj_stack_[obj_stack_loc++] = hoc_thisobject; obj_stack_[obj_stack_loc] = ob; hoc_thisobject = ob; if (ob) { hoc_symlist = ob->template->symtable; hoc_objectdata = ob->u.dataspace; }else{ hoc_symlist = hoc_top_level_symlist; hoc_objectdata = hoc_top_level_data; } hoc_ret(); pushx(0.); } hoc_object_pushed() { Object* ob; int i = chkarg(1, 0., (double)obj_stack_loc); ob = obj_stack_[obj_stack_loc - i]; hoc_ret(); hoc_push_object(ob); } hoc_object_pop() { Object* ob; if (obj_stack_loc < 1) { hoc_execerror("object context stack underflow", 0); } obj_stack_[obj_stack_loc] = (Object*)0; ob = obj_stack_[--obj_stack_loc]; hoc_thisobject = ob; if (ob) { hoc_symlist = ob->template->symtable; hoc_objectdata = ob->u.dataspace; }else{ hoc_symlist = hoc_top_level_symlist; hoc_objectdata = hoc_top_level_data; } hoc_ret(); pushx(0.); } /*-----------------------------------------------*/ int hoc_resize_toplevel(more) int more; { if (more > 0) { icnttoplevel += more; hoc_top_level_data = (Objectdata *)erealloc((char *)hoc_top_level_data, icnttoplevel*sizeof(Objectdata)); if (templatestackp == templatestack) { hoc_objectdata = hoc_top_level_data; } } return icnttoplevel; } hoc_install_object_data_index(sp) Symbol *sp; { if (!hoc_objectdata) { icntobjectdata = 0; } sp->u.oboff = icntobjectdata; icntobjectdata += 2; /* data pointer and Arrayinfo */ hoc_objectdata = (Objectdata *)erealloc((char *)hoc_objectdata, icntobjectdata*sizeof(Objectdata)); hoc_objectdata[icntobjectdata-1].arayinfo = sp->arayinfo; if (sp->arayinfo) { ++sp->arayinfo->refcount; } if (templatestackp == templatestack) { hoc_top_level_data = hoc_objectdata; icnttoplevel = icntobjectdata; } } int hoc_obj_run(cmd, ob) char* cmd; Object* ob; { int err; Object* objsave; Objectdata* obdsave; Symlist* slsave; int osloc; objsave = hoc_thisobject; obdsave = hoc_objectdata_save(); slsave = hoc_symlist; osloc = obj_stack_loc; if (ob) { if (ob->template->constructor) { hoc_execerror("Can't execute in a built-in class context", 0); } hoc_thisobject = ob; hoc_objectdata = ob->u.dataspace; hoc_symlist = ob->template->symtable; }else{ hoc_thisobject = 0; hoc_objectdata = hoc_top_level_data; hoc_symlist = hoc_top_level_symlist; } err = hoc_oc(cmd); hoc_thisobject = objsave; hoc_objectdata = hoc_objectdata_restore(obdsave); hoc_symlist = slsave; obj_stack_loc = osloc; return err; } hoc_exec_cmd() { /* execute string from top level or within an object context */ int err; char* cmd; char buf[256]; char* pbuf; Object* ob = 0; HocStr* hs; cmd = gargstr(1); pbuf = buf; if (strlen(cmd) > 256 - 10) { hs = hocstr_create(strlen(cmd) + 10); pbuf = hs->buf; } if (cmd[0] == '~') { sprintf(pbuf, "%s\n", cmd+1); }else{ sprintf(pbuf, "{%s}\n", cmd); } if (ifarg(2)) { ob = *hoc_objgetarg(2); } err = hoc_obj_run(pbuf, ob); if (err) { hoc_execerror("execute error:", cmd); } if (pbuf != buf) { hocstr_delete(hs); } hoc_ret(); pushx((double)(err)); } /* call a function within the context of an object. Args must be on stack */ double hoc_call_objfunc(s, narg, ob) Symbol* s; int narg; Object* ob; { double d, hoc_call_func(); Object* objsave; Objectdata* obdsave; Symlist* slsave; objsave = hoc_thisobject; obdsave = hoc_objectdata_save(); slsave = hoc_symlist; if (ob) { hoc_thisobject = ob; hoc_objectdata = ob->u.dataspace; hoc_symlist = ob->template->symtable; }else{ hoc_thisobject = 0; hoc_objectdata = hoc_top_level_data; hoc_symlist = hoc_top_level_symlist; } d = hoc_call_func(s, narg); hoc_thisobject = objsave; hoc_objectdata = hoc_objectdata_restore(obdsave); hoc_symlist = slsave; return d; } hoc_oop_initaftererror() { hoc_symlist = hoc_top_level_symlist; templatestackp = templatestack; icntobjectdata = icnttoplevel; hoc_objectdata = hoc_top_level_data; hoc_thisobject = (Object*)0; obj_stack_loc = 0; hoc_in_template = 0; #if CABLE connect_obsec_ = 0; #endif } oc_save_hoc_oop(a1, a2, a3, a4, a5) Object* *a1; Objectdata* *a2; int *a4; Symlist* *a5; { *a1 = hoc_thisobject; *a2 = hoc_objectdata; *a4 = obj_stack_loc; *a5 = hoc_symlist; } oc_restore_hoc_oop(a1, a2, a3, a4, a5) Object* *a1; Objectdata* *a2; int *a4; Symlist* *a5; { hoc_thisobject = *a1; hoc_objectdata = *a2; obj_stack_loc = *a4; hoc_symlist = *a5; } Object* hoc_new_object(symtemp, v) Symbol* symtemp; void* v; { Object* ob; #if PDEBUG printf("new object from template %s created.\n", symtemp->name); #endif ob = (Object *)emalloc(sizeof(Object)); ob->recurse = 0; ob->unref_recurse_cnt = 0; ob->refcount = 1; /* so template notify will not delete */ ob->observers = (void*)0; ob->template = symtemp->u.template; ob->aliases = (void*)0; ob->itm_me = hoc_l_lappendobj(ob->template->olist, ob); ob->secelm_ = (hoc_Item*)0; ob->template->count++; ob->index = ob->template->index++; if (symtemp->subtype & (CPLUSOBJECT | JAVAOBJECT)) { ob->u.this_pointer = v; if (v) { hoc_template_notify(ob, 1); } }else{ ob->u.dataspace = 0; } ob->refcount = 0; return ob; } hoc_new_object_asgn(obp, st, v) Object** obp; Symbol* st; void* v; { hoc_dec_refcount(obp); *obp = hoc_new_object(st, v); hoc_obj_ref(*obp); } Object** hoc_temp_objvar(symtemp, v) Symbol* symtemp; void* v; { return hoc_temp_objptr(hoc_new_object(symtemp, v)); } Object* hoc_newobj1(sym, narg) Symbol* sym; int narg; { Object *ob; Objectdata *obd; Symbol *s; int i, total; ob = hoc_new_object(sym, (void*)0); ob->refcount = 1; if (sym->subtype & (CPLUSOBJECT | JAVAOBJECT)) { call_constructor(ob, sym, narg); }else{ ob->u.dataspace = obd = (Objectdata *)ecalloc(ob->template->dataspace_size, sizeof(Objectdata)); for (s = ob->template->symtable->first; s; s = s->next) { if (s->public != 2) { switch (s->type) { case VAR: if ((obd[s->u.oboff + 1].arayinfo = s->arayinfo) != (Arrayinfo*)0) { ++s->arayinfo->refcount; } total = hoc_total_array_data(s, obd); obd[s->u.oboff].pval = (double *)emalloc(total*sizeof(double)); for(i=0; iu.oboff].pval)[i] = 0.; } break; case STRING: obd[s->u.oboff + 1].arayinfo = (Arrayinfo*)0; obd[s->u.oboff].ppstr = (char**)emalloc(sizeof(char*)); *obd[s->u.oboff].ppstr = (char *)emalloc(sizeof(char)); **(obd[s->u.oboff].ppstr) = '\0'; break; case OBJECTVAR: if ((obd[s->u.oboff + 1].arayinfo = s->arayinfo) != (Arrayinfo*)0) { ++s->arayinfo->refcount; } total = hoc_total_array_data(s, obd); obd[s->u.oboff].pobj = (Object **)emalloc(total*sizeof(Object *)); for (i=0; iu.oboff].pobj)[i] = (Object *)0; } if (strcmp(s->name, "this") == 0) { obd[s->u.oboff].pobj[0] = ob; } break; #if CABLE case SECTION: if ((obd[s->u.oboff + 1].arayinfo = s->arayinfo) != (Arrayinfo*)0) { ++s->arayinfo->refcount; } total = hoc_total_array_data(s, obd); obd[s->u.oboff].psecitm = (struct Item **)emalloc(total*sizeof(struct Item*)); new_sections(ob, s, obd[s->u.oboff].psecitm, total); break; #endif } } } if (ob->template->is_point_) { hoc_construct_point(ob, narg); } if (ob->template->init) { call_ob_proc(ob, ob->template->init, narg); }else{ for (i=0; i < narg; ++i) { hoc_nopop(); } } } hoc_template_notify(ob, 1); return ob; } hoc_newobj_arg() { Object* ob; Symbol* sym; int narg; sym = (pc++)->sym; narg = (pc++)->i; ob = hoc_newobj1(sym, narg); ob->refcount = 0; hoc_pushobj(hoc_temp_objptr(ob)); } hoc_newobj_ret() { hoc_newobj_arg(); } hoc_newobj() { /* template at pc+1 */ Object *ob, **obp; Objectdata *obd; Symbol *sym, *s; int i, total; int narg; sym = (pc++)->sym; narg = (pc++)->i; #if USE_PYTHON /* look inside stack because of limited number of temporary objects? */ /* whatever. we will keep the strategy */ if (hoc_inside_stacktype(narg) == OBJECTVAR) { #endif obp = hoc_look_inside_stack(narg, OBJECTVAR)->pobj; ob = hoc_newobj1(sym, narg); hoc_nopop(); /* the object pointer */ hoc_dec_refcount(obp); *(obp) = ob; hoc_pushobj(obp); #if USE_PYTHON }else{ /* PythonObject assignment */ Object* o = hoc_obj_look_inside_stack(narg); assert(o->template->sym == nrnpy_pyobj_sym_); ob = hoc_newobj1(sym, narg); hoc_push_object(ob); (*nrnpy_hpoasgn)(o, OBJECTTMP); } #endif } static call_constructor(ob, sym, narg) Object *ob; Symbol *sym; int narg; { Inst *pcsav; Symlist *slsav; Objectdata *obdsav; Object* obsav; slsav = hoc_symlist; obdsav = hoc_objectdata_save(); obsav = hoc_thisobject; pcsav = pc; push_frame(sym, narg); ob->u.this_pointer = (ob->template->constructor)(ob); pop_frame(); pc = pcsav; hoc_symlist = slsav; hoc_objectdata = hoc_objectdata_restore(obdsav); hoc_thisobject = obsav; } call_ob_proc(ob, sym, narg) Object *ob; Symbol *sym; int narg; { Inst *pcsav, callcode[4]; Symlist *slsav; Objectdata *obdsav; Object* obsav; extern int call(); slsav = hoc_symlist; obdsav = hoc_objectdata_save(); obsav = hoc_thisobject; pcsav = pc; if (ob->template->sym->subtype & CPLUSOBJECT) { hoc_thisobject = ob; push_frame(sym, narg); hoc_thisobject = obsav; if (sym->type == OBFUNCTION) { Object** o; o = (*(sym->u.u_proc->defn.pfo))(ob->u.this_pointer); if (*o) {++(*o)->refcount;} /* in case unreffed below */ pop_frame(); if (*o) {--(*o)->refcount;} hoc_pushobj(o); }else if (sym->type == STRFUNCTION) { char** s; s = (*(sym->u.u_proc->defn.pfs))(ob->u.this_pointer); pop_frame(); hoc_pushstr(s); }else{ double x; x = (*(sym->u.u_proc->defn.pfd))(ob->u.this_pointer); pop_frame(); hoc_pushx(x); } #if JAVA2NRN }else if (ob->template->sym->subtype & JAVAOBJECT) { hoc_thisobject = ob; push_frame(sym, narg); hoc_thisobject = obsav; if (sym->type == OBFUNCTION) { Object** o; o = (*(p_java2nrn_ometh))(ob, sym); if (*o) {++(*o)->refcount;} /* in case unreffed below */ pop_frame(); if (*o) {--(*o)->refcount;} hoc_pushobj(o); }else if (sym->type == STRFUNCTION) { char** s; s = (*(p_java2nrn_smeth))(ob, sym); pop_frame(); hoc_pushstr(s); }else{ double x; x = (*(p_java2nrn_dmeth))(ob, sym); pop_frame(); hoc_pushx(x); } #endif /*JAVA2NRN*/ #if CABLE }else if (ob->template->is_point_ && special_pnt_call(ob, sym, narg)) { ;/*empty since special_pnt_call did the work for get_loc, has_loc, and loc*/ #endif }else{ callcode[0].pf = call; callcode[1].sym = sym; callcode[2].i = narg; callcode[3].in = STOP; hoc_objectdata = ob->u.dataspace; hoc_thisobject = ob; hoc_symlist = ob->template->symtable; execute(callcode); if (sym->type == PROCEDURE) { hoc_nopop(); } } if (hoc_errno_check()) { char str[200]; sprintf(str, "%s.%s", hoc_object_name(ob), sym->name); hoc_warning("errno set during call of", str); } pc = pcsav; hoc_symlist = slsav; hoc_objectdata = hoc_objectdata_restore(obdsav); hoc_thisobject = obsav; } static call_ob_iter(ob, sym, narg) Object *ob; Symbol *sym; int narg; { Symlist *slsav; Objectdata *obdsav; Object* obsav; Object* stmtobj; Inst* stmtbegin, *stmtend; slsav = hoc_symlist; obdsav = hoc_objectdata_save(); obsav = hoc_thisobject; hoc_objectdata = ob->u.dataspace; hoc_thisobject = ob; hoc_symlist = ob->template->symtable; stmtobj = hoc_look_inside_stack(narg+1, OBJECTTMP)->obj; stmtbegin = pc + pc->i; pc++; stmtend = pc + pc->i; hoc_iterator_object(sym, narg, stmtbegin, stmtend, stmtobj); /* the stack was popped by hoc_iterator_object hoc_nopop(); */ hoc_symlist = slsav; hoc_objectdata = hoc_objectdata_restore(obdsav); hoc_thisobject = obsav; } hoc_objvardecl() {/* symbol at pc+1, number of indices at pc+2 */ Symbol *sym; int nsub, size, i; Object **pobj; sym = (pc++)->sym; #if PDEBUG printf("declareing %s as objectvar\n", sym->name); #endif if (sym->type == OBJECTVAR) { int total, i; total = hoc_total_array(sym); for (i=0; iu.oboff].pobj); hoc_freearay(sym); }else{ sym->type = OBJECTVAR; hoc_install_object_data_index(sym); } nsub = (pc++)->i; if (nsub) { size = hoc_arayinfo_install(sym, nsub); }else{ size = 1; } hoc_objectdata[sym->u.oboff].pobj = pobj = (Object **)emalloc(size*sizeof(Object *)); for (i=0; ii; } hoc_known_type() { int type; type = ((pc++)->i); } hoc_objectvar() { /* object variable symbol at pc+1. */ /* pointer to correct object left on stack */ Objectdata* odsav; Object* obsav = 0; Symlist* slsav; Symbol *obs; Object **obp; #if PDEBUG printf("code for hoc_objectvar()\n"); #endif obs = (pc++)->sym; if (obs->public == 2) { obs = obs->u.sym; odsav = hoc_objectdata_save(); obsav = hoc_thisobject; slsav = hoc_symlist; hoc_objectdata = hoc_top_level_data; hoc_thisobject = 0; hoc_symlist = hoc_top_level_symlist; } obp = OPOBJ(obs); if (ISARRAY(obs)) { hoc_pushobj(obp + araypt(obs, OBJECTVAR)); }else{ hoc_pushobj(obp); } if (obsav) { hoc_objectdata = hoc_objectdata_restore(odsav); hoc_thisobject = obsav; hoc_symlist = slsav; } } hoc_objectarg() { /* object arg index at pc+1. */ /* pointer to correct object left on stack */ int i; Object **obp, **hoc_objgetarg(); #if PDEBUG printf("code for hoc_objectarg()\n"); #endif i = (pc++)->i; if (i == 0) { i = hoc_argindex(); } obp = hoc_objgetarg(i); hoc_pushobj(obp); } hoc_constobject() { /* template at pc, index at pc+1, objpointer left on stack*/ char buf[200]; Object *obj; Item* q; Template* t = (pc++)->sym->u.template; int index = (int)hoc_xpop(); ITERATE (q, t->olist) { obj = OBJ(q); if (obj->index == index) { hoc_pushobj(hoc_temp_objptr(obj)); return; }else if (obj->index > index) { break; } } sprintf(buf, "%s[%d]\n", t->sym->name, index); hoc_execerror("Object ID doesn't exist:", buf); } Object* hoc_name2obj(char* name, int index) { char buf[200]; Object *obj; Item* q; Template* t; Symbol* sym; sym = hoc_table_lookup(name, hoc_top_level_symlist); if (!sym) { sym = hoc_table_lookup(name, hoc_built_in_symlist); } if (!sym || sym->type != TEMPLATE) { hoc_execerror(name, "is not a template"); } t = sym->u.template; ITERATE (q, t->olist) { obj = OBJ(q); if (obj->index == index) { return obj; }else if (obj->index > index) { break; } } return (Object*)0; } hoc_object_id() { Object *ob, **hoc_objgetarg(); ob = *(hoc_objgetarg(1)); if (ifarg(2) && chkarg(2, 0., 1.) == 1.) { hoc_ret(); if (ob) { pushx((double)ob->index); }else{ pushx(-1.); } }else{ hoc_ret(); pushx((double)((long)ob)); } } #if CABLE static range_suffix(sym, nindex, narg) Symbol* sym; int nindex, narg; { int bdim = 0; if (ISARRAY(sym)) { if (nindex != sym->arayinfo->nsub) { bdim = 1; } }else{ if (nindex != 0) { bdim = 1; } } if (bdim) { hoc_execerror(sym->name, "wrong number of array dimensions"); } if (sym->type == RANGEVAR) { hoc_pushi(narg); hoc_pushs(sym); }else if (sym->subtype == USERPROPERTY) { if (narg) { hoc_execerror(sym->name, "section property can't have argument"); } hoc_pushs(sym); }else{ hoc_execerror(sym->name, "suffix not a range variable or section property"); } } connect_obsec_syntax() { connect_obsec_ = 1; } #endif hoc_object_component() { /* number of indices at pc+2, number of args at pc+3, symbol at pc+1 */ /* object pointer on stack after indices */ /* if component turns out to be an object then make sure pointer to correct object, symbol, etc is left on stack for evaluation, assignment, etc. */ extern Symbol* ivoc_alias_lookup(); Symbol *sym0, *sym; extern int hoc_returning; int nindex, narg, cplus, isfunc; Object *obp, *obsav; Objectdata *psav; int* ptid; Symbol** psym; #if PDEBUG printf("code for hoc_object_component()\n"); #endif sym0 = (pc++)->sym; nindex = (pc++)->i; narg = (pc++)->i; ptid = &(pc++)->i; psym = &(pc++)->sym; isfunc = (pc++)->i; #if CABLE if (section_object_seen) { section_object_seen = 0; range_suffix(sym0, nindex, narg); return; } if (connect_obsec_) { narg += nindex; nindex = 0; } #endif if (nindex) { if (narg) { hoc_execerror("[...](...) syntax only allowed for array range variables:", sym0->name); } }else{ nindex = narg; } obp = hoc_obj_look_inside_stack(nindex); if (obp) { #if USE_PYTHON if (obp->template->sym == nrnpy_pyobj_sym_) { extern int hoc_object_asgn(); if (isfunc & 2) { /* this is the final left hand side of an assignment to the method of a PythonObject and we need to put the PythonObject and the method with all its info onto the stack so that a proper __setattro__ or __setitem__ can be accomplished in the next hoc_object_asgn */ if (isfunc&1) { hoc_execerror("Cannot assign to a PythonObject function call:", sym0->name); } pushi(nindex); pushs(sym0); hoc_push_object(obp); }else{ (*nrnpy_py2n_component)(obp, sym0, nindex, isfunc); } return; } #endif if (obp->template->id == *ptid) { sym = *psym; }else{ if (obp->aliases == 0 || (sym = ivoc_alias_lookup(sym0->name, obp)) == 0) { /* lookup only has to be done once if the name is not an alias and the ptid of the object is still the same. */ sym = hoc_table_lookup(sym0->name, obp->template->symtable); if (!sym || sym->public != PUBLIC_TYPE) { fprintf(stderr, "%s not a public member of %s\n", sym0->name, obp->template->sym->name); hoc_execerror(obp->template->sym->name, sym0->name); } *ptid = obp->template->id; *psym = sym; } } }else{ hoc_execerror(sym0->name, ": object prefix is NULL"); } psav = hoc_objectdata_save(); obsav = hoc_thisobject; cplus = (obp->template->sym->subtype & (CPLUSOBJECT | JAVAOBJECT)); if (!cplus) { /* c++ classes don't have a hoc dataspace */ hoc_objectdata = obp->u.dataspace; hoc_thisobject = obp; } switch (sym->type) { case OBJECTVAR: if (nindex) { if (!ISARRAY(sym) || OPARINFO(sym)->nsub != nindex) { hoc_execerror(sym->name, ":not right number of subscripts"); } nindex = araypt(sym, OBJECTVAR); } hoc_pop_defer(); hoc_pushobj(OPOBJ(sym) + nindex); break; case VAR: if (cplus) { double* pd; if (nindex) { if (!ISARRAY(sym) || sym->arayinfo->nsub != nindex) { hoc_execerror(sym->name, ":not right number of subscripts"); } } hoc_pushs(sym); (*obp->template->steer)(obp->u.this_pointer); pd = hoc_pxpop(); /* cannot pop a temporary object til after the pd is used in case (e.g. Vector.x) the pointer is a field in the object (often the pd has nothing to do with the object)*/ hoc_pop_defer(); /* corresponding unref_defer soon */ hoc_pushpx(pd); }else{ if (nindex) { if (!ISARRAY(sym) || OPARINFO(sym)->nsub != nindex) { hoc_execerror(sym->name, ":not right number of subscripts"); } nindex = araypt(sym, OBJECTVAR); } hoc_pop_defer(); /*finally get rid of symbol */ hoc_pushpx(OPVAL(sym) + nindex); } break; case STRING: if (nindex) { hoc_execerror(sym->name, ": string can't have function arguments or array indices"); } hoc_pop_defer(); hoc_pushstr(OPSTR(sym)); break; case PROCEDURE: case FUNCTION: { double d=0.; call_ob_proc(obp, sym, nindex); if (hoc_returning) { break; } if (sym->type == FUNCTION) { d = hoc_xpop(); } hoc_pop_defer(); hoc_pushx(d); break;} case HOCOBJFUNCTION: case OBFUNCTION: { Object** d; call_ob_proc(obp, sym, nindex); if (hoc_returning) { break; } d = hoc_objpop(); if (*d) {(*d)->refcount++;} /* nopop may unref if temp obj.*/ hoc_pop_defer(); hoc_pushobj(d); if (*d) {(*d)->refcount--;} /* see the nopop may unref comment */ hoc_tobj_unref(d); break;} case STRFUNCTION: { char** d; call_ob_proc(obp, sym, nindex); if (hoc_returning) { break; } d = hoc_strpop(); hoc_pop_defer(); hoc_pushstr(d); break;} #if CABLE case SECTIONREF: { extern Symbol* nrn_sec_sym; Section* sec, *nrn_sectionref_steer(); section_object_seen = 1; sec = (Section*)obp->u.this_pointer; if (sym != nrn_sec_sym) { sec = nrn_sectionref_steer(sec, sym, &nindex); } if ( connect_obsec_) { double x; connect_obsec_ = 0; if (nindex != 1) { hoc_execerror(sym->name, ": bad connect syntax"); } x = hoc_xpop(); hoc_pop_defer(); hoc_pushx(x); }else{ if (nindex) { hoc_execerror(sym->name, ":no subscript allowed"); } hoc_pop_defer(); } if (!sec->prop) { hoc_execerror("Section was deleted", (char*)0); } nrn_pushsec(sec); break; } case SECTION: { double x; section_object_seen = 1; if (connect_obsec_) { x = hoc_xpop(); if (!nindex) { hoc_execerror(sym->name, ": bad connect syntax"); } --nindex; } if (nindex) { if (!ISARRAY(sym) || OPARINFO(sym)->nsub != nindex) { hoc_execerror(sym->name, ":not right number of subscripts"); } nindex = araypt(sym, OBJECTVAR); } hoc_pop_defer(); if (connect_obsec_) { hoc_pushx(x); connect_obsec_ = 0; } ob_sec_access_push(*(OPSECITM(sym) + nindex)); break; } #endif /*CABLE*/ case ITERATOR: { if ((pc++)->i != ITERATOR) { hoc_execerror(sym->name, ":ITERATOR can only be used in a for statement"); } call_ob_iter(obp, sym, nindex); if (hoc_returning) { break; } hoc_pop_defer(); hoc_nopop(); /* get rid of iterator statement context */ break;} default: if (cplus) { double* pd; if (nindex) { if (!ISARRAY(sym) || sym->arayinfo->nsub != nindex) { hoc_execerror(sym->name, ":not right number of subscripts"); } } hoc_pushs(sym); (*obp->template->steer)(obp->u.this_pointer); pd = hoc_pxpop(); hoc_pop_defer(); hoc_pushpx(pd); }else{ hoc_execerror(sym->name, ": can't push that type onto stack"); } break; case OBJECTALIAS: if (nindex) { hoc_execerror(sym->name, ": is an alias and cannot have subscripts"); } hoc_pop_defer(); hoc_push_object(sym->u.object_); break; case VARALIAS: if (nindex) { hoc_execerror(sym->name, ": is an alias and cannot have subscripts"); } hoc_pop_defer(); hoc_pushpx(sym->u.pval); break; } hoc_objectdata = hoc_objectdata_restore(psav); hoc_thisobject = obsav; } hoc_object_eval() { int type; #if PDEBUG printf("code for hoc_object_eval\n"); #endif type = hoc_stacktype(); if (type == VAR) { hoc_pushx(*(hoc_pxpop())); }else if (type == SYMBOL) { #if CABLE Datum* d = hoc_look_inside_stack(0, SYMBOL); if (d->sym->type == RANGEVAR) { double* nrn_rangepointer(); Symbol* sym = hoc_spop(); int narg = hoc_ipop(); struct Section* sec = nrn_sec_pop(); double x; if (narg) { x = hoc_xpop(); }else{ x = .5; } hoc_pushx(*(nrn_rangepointer(sec, sym, x))); }else if (d->sym->type == VAR && d->sym->subtype == USERPROPERTY) { double cable_prop_eval(); hoc_pushx(cable_prop_eval(hoc_spop())); } #endif } } hoc_ob_pointer() { int type; Symbol* sym; #if PDEBUG printf("code for hoc_ob_pointer\n"); #endif type = hoc_stacktype(); if (type == VAR) { }else if (type == SYMBOL) { #if CABLE Datum* d = hoc_look_inside_stack(0, SYMBOL); if (d->sym->type == RANGEVAR) { double* nrn_rangepointer(); Symbol* sym = hoc_spop(); int nindex = hoc_ipop(); struct Section* sec = nrn_sec_pop(); double x; if (nindex) { x = hoc_xpop(); }else{ x = .5; } hoc_pushpx(nrn_rangepointer(sec, sym, x)); }else if (d->sym->type == VAR && d->sym->subtype == USERPROPERTY) { double* cable_prop_eval_pointer(); hoc_pushpx(cable_prop_eval_pointer(hoc_spop())); }else{ hoc_execerror("Not a double pointer", 0); } #else hoc_execerror("Not a double pointer", 0); #endif }else{ hoc_execerror("Not a double pointer", 0); } } hoc_asgn_obj_to_str() { /* string on stack */ char *d, **pstr; d = *(hoc_strpop()); pstr = hoc_strpop(); hoc_assign_str(pstr, d); } hoc_object_asgn() { int type1, type2, op; op = (pc++)->i; type1 = hoc_stacktype(); type2 = hoc_inside_stacktype(1); #if CABLE if (type2 == SYMBOL) { Datum* d = hoc_look_inside_stack(1, SYMBOL); if (d->sym->type == RANGEVAR) { type2 = RANGEVAR; }else if (d->sym->type == VAR && d->sym->subtype == USERPROPERTY) { type2 = USERPROPERTY; } } if (type2 == RANGEVAR && type1 == NUMBER) { double d = hoc_xpop(); struct Section* sec; Symbol* sym = hoc_spop(); int nindex = hoc_ipop(); sec = nrn_sec_pop(); if (nindex) { double* pd; pd = nrn_rangepointer(sec, sym, hoc_xpop()); if (op) { d = hoc_opasgn(op, *pd, d); } *pd = d; }else{ nrn_rangeconst(sec, sym, &d, op); } hoc_pushx(d); return; }else if (type2 == USERPROPERTY && type1 == NUMBER) { double d = hoc_xpop(); cable_prop_assign(hoc_spop(), &d, op); hoc_pushx(d); return; } #endif switch (type2) { case VAR: { double d, *pd; d = hoc_xpop(); pd = hoc_pxpop(); if (op) { d = hoc_opasgn(op, *pd, d); } *pd = d; hoc_pushx(d); } break; case OBJECTVAR: { Object **d, **pd; if (op) { hoc_execerror("Invalid assignment operator for object", (char*)0); } d = hoc_objpop(); pd = hoc_objpop(); if (d != pd) { Object* tobj = *d; if (tobj) { (tobj)->refcount++; } hoc_tobj_unref(d); hoc_dec_refcount(pd); *pd = tobj; } hoc_pushobj(pd); } break; case STRING: { char *d, **pd; if (op) { hoc_execerror("Invalid assignment operator for string", (char*)0); } d = *(hoc_strpop()); pd = hoc_strpop(); hoc_assign_str(pd, d); hoc_pushstr(pd); } break; #if USE_PYTHON case OBJECTTMP: { /* should be PythonObject */ Object* o; o = hoc_obj_look_inside_stack(1); assert(o->template->sym == nrnpy_pyobj_sym_); if (op) { hoc_execerror("Invalid assignment operator for PythonObject", (char*)0); } (*nrnpy_hpoasgn)(o, type1); } break; #endif default: hoc_execerror("Cannot assign to left hand side", (char*)0); } } /* if the name isn't a template then look in the top level symbol table. This allows objects to create objects of any class defined at the top level */ Symbol* hoc_which_template(s) Symbol* s; { if (s->type != TEMPLATE) { Symbol* s1; s1 = hoc_table_lookup(s->name, hoc_top_level_symlist); if (!s1 || s1->type != TEMPLATE) { hoc_execerror(s->name, "is not a template"); } s = s1; } return s; } /* pushes old symtable and template name on template stack. And creates new symtable. The new symtable is used for all non-builtin names until an endtemplate is reached */ static int template_id; hoc_begintemplate(t1) Symbol *t1; { Symbol* t; int type; t = hoc_decl(t1); #if PDEBUG printf("begin template %s\n", t->name); #endif type = t->type; if (type == TEMPLATE) { hoc_execerror(t->name, ": a template cannot be redefined"); hoc_free_symspace(t); }else if (type != UNDEF) { hoc_execerror(t->name, "already used as something besides template"); } t->u.template = (Template *)emalloc(sizeof(Template)); t->type = TEMPLATE; t->u.template->sym = t; t->u.template->symtable = (Symlist *)0; t->u.template->dataspace_size = 0; t->u.template->constructor = 0; t->u.template->destructor = 0; t->u.template->is_point_ = 0; t->u.template->steer = 0; t->u.template->checkpoint = 0; t->u.template->id = ++template_id; pushtemplatei(icntobjectdata); pushtemplateodata(hoc_objectdata); pushtemplatei(hoc_in_template); pushtemplateo(hoc_thisobject); pushtemplatesymlist(hoc_symlist); pushtemplatesym(t); hoc_in_template = 1; hoc_objectdata = (Objectdata *)0; hoc_thisobject = (Object*)0; hoc_symlist = t->u.template->symtable; } hoc_endtemplate(t) Symbol *t; { Symbol *ts, *s; #if PDEBUG printf("end template %s\n", t->name); #endif ts = (poptemplate())->sym; if (strcmp(ts->name, t->name) != 0) { hoc_execerror(t->name, "- end template mismatched with begin"); } ts->u.template->dataspace_size = icntobjectdata; ts->u.template->symtable = hoc_symlist; ts->u.template->count = 0; ts->u.template->index = 0; ts->u.template->olist = hoc_l_newlist(); ts->u.template->observers = (void*)0; hoc_symlist = (poptemplate())->symlist; free_objectdata(hoc_objectdata, ts->u.template); hoc_thisobject = (poptemplate())->o; hoc_in_template = (poptemplate())->i; hoc_objectdata = (poptemplate())->odata; icntobjectdata = (poptemplate())->i; ts->u.template->init = s = hoc_table_lookup("init", ts->u.template->symtable); if (s && s->type != PROCEDURE) { hoc_execerror("'init' can only be used as the initialization procedure for new objects", (char *)0); } ts->u.template->unref = s = hoc_table_lookup("unref", ts->u.template->symtable); if (s && s->type != PROCEDURE) { hoc_execerror("'unref' can only be used as the callback procedure when the reference count is decremented", (char *)0); } } typedef struct Member_func { char* name; double (*member)(); }Member_func; typedef struct Member_ret_obj_func { char* name; Object** (*omember)(); }Member_ret_obj_func; typedef struct Member_ret_str_func { char* name; char** (*smember)(); }Member_ret_str_func; void class2oc(name, cons, destruct, m, checkpoint, mobjret, strret) char* name; void* (*cons)(); void (*destruct)(); Member_func* m; int (*checkpoint)(); Member_ret_obj_func* mobjret; Member_ret_str_func* strret; { Symbol* tsym, *s; Template* t; int i; if (hoc_lookup(name)) { hoc_execerror(name, "already being used as a name"); } tsym = hoc_install(name, UNDEF, 0.0, &hoc_symlist); tsym->subtype = CPLUSOBJECT; hoc_begintemplate(tsym); t = tsym->u.template; t->constructor = cons; t->destructor = destruct; t->steer = 0; t->checkpoint = checkpoint; if (m) for (i=0; m[i].name; ++i) { s = hoc_install(m[i].name, FUNCTION, 0.0, &hoc_symlist); s->u.u_proc->defn.pfd = m[i].member; hoc_add_publiclist(s); } if (mobjret) for (i=0; mobjret[i].name; ++i) { s = hoc_install(mobjret[i].name, OBFUNCTION, 0.0, &hoc_symlist); s->u.u_proc->defn.pfo = mobjret[i].omember; hoc_add_publiclist(s); } if (strret) for (i=0; strret[i].name; ++i) { s = hoc_install(strret[i].name, STRFUNCTION, 0.0, &hoc_symlist); s->u.u_proc->defn.pfs = strret[i].smember; hoc_add_publiclist(s); } hoc_endtemplate(tsym); } #if JAVA2NRN Symbol* java2nrn_class(name, id, meth) char* name; int id; char* meth; { Symbol* tsym, *s; Template* t; int i, mid; char mname[256], signature[256], *cp, *cn, *buf; if (hoc_lookup(name)) { hoc_execerror(name, "already being used as a name"); } tsym = hoc_install(name, UNDEF, 0.0, &hoc_symlist); printf("class %s methods:\n", tsym->name); tsym->subtype = JAVAOBJECT; hoc_begintemplate(tsym); t = tsym->u.template; t->id = -(id + 1); /* all others incremented from 1, must not be 0 */ t->constructor = p_java2nrn_cons; t->destructor = p_java2nrn_destruct; t->steer = 0; t->checkpoint = 0; mid = 0; /* meth is a "type name signature ..." space separated string constructed by Neuron.java and the order gives mid */ for (cp = meth; *cp; ++cp) { int type; switch (*cp) { case 'd': type = FUNCTION; break; case 's': type = STRFUNCTION; break; case 'o': type = OBFUNCTION; break; default: printf("|%s|\n", meth); assert(0); } ++cp; /* now at space */ ++cp;/* skip the space between type and name */ for (cn = mname; *cp != ' '; ++cn, ++cp) { if (*cp == '.') { *cn = '_'; }else{ *cn = *cp; } } *cn = '\0'; ++cp;/* skip the space between name and signature */ /* get the signature */ for (cn = signature; *cp != ' ' && *cp != '\0'; ++cn, ++cp) { *cn = *cp; } *cn = '\0'; if (*cp == '\0') { --cp; /* for increment will put it back for test */ } s = hoc_lookup(mname); if (s) { /* indicate overloading with s_varn */ s->s_varn = 1; }else{ s = hoc_install(mname, type, 0.0, &hoc_symlist); /* init will be removed later so don't add */ if (strcmp(mname, "init") != 0) { hoc_add_publiclist(s); s->s_varn = 0; /* not overloaded --- yet */ }else{ /* but force init to be overloaded */ s->s_varn = 1; } s->u.u_auto = mid; /*printf("installed %s %d\n", s->name, s->u.u_auto);*/ } mid++; } /* pass again and take care of overloading. */ mid = 0; for (cp = meth; *cp; ++cp) { int type; switch (*cp) { case 'd': type = FUNCTION; break; case 's': type = STRFUNCTION; break; case 'o': type = OBFUNCTION; break; default: printf("|%s|\n", meth); assert(0); } ++cp; /* now at space */ ++cp;/* skip the space between type and name */ for (cn = mname; *cp != ' '; ++cn, ++cp) { if (*cp == '.') { *cn = '_'; }else{ *cn = *cp; } } *cn = '\0'; ++cp;/* skip the space between name and signature */ /* get the signature */ for (cn = signature; *cp != ' ' && *cp != '\0'; ++cn, ++cp) { *cn = *cp; } *cn = '\0'; if (*cp == '\0') { --cp; /* for increment will put it back for test */ } s = hoc_lookup(mname); if (s->s_varn > 0) { sprintf(mname + strlen(mname), "%d%s", strlen(signature), signature); if (hoc_lookup(mname)) { printf("%s derived from overloaded %s already exists\n", mname, s->name); }else{ Symbol* so; so = hoc_install(mname, type, 0.0, &hoc_symlist); hoc_add_publiclist(so); so->s_varn = 0; /* not overloaded --- yet */ so->u.u_auto = mid; ++s->s_varn; /*printf("installed %s %d\n", so->name, so->u.u_auto);*/ } } ++mid; } /* get rid of init if it exists. That's only for a hoc constructor */ s = hoc_lookup("init"); if (s) { hoc_unlink_symbol(s, hoc_symlist); if (s->name) { free(s->name); } free((char*)s); } hoc_endtemplate(tsym); i = 0; for (s = tsym->u.template->symtable->first; s; s = s->next) { i += strlen(s->name) + 1; if (i >= 80) { printf("\n"); i = strlen(s->name) + 1; } printf(" %s", s->name); } printf("\n"); return tsym; } #endif /* JAVA2NRN */ Symbol* hoc_decl(s) Symbol* s; { Symbol* ss; if (templatestackp == templatestack) { if (s == hoc_table_lookup(s->name, hoc_built_in_symlist)) { hoc_execerror(s->name, ": Redeclaring at top level"); } return s; } ss = hoc_table_lookup(s->name, hoc_symlist); if (!ss) { ss = hoc_install(s->name, UNDEF, 0.0, &hoc_symlist); } return ss; } hoc_add_publiclist(s) Symbol *s; { Symbol* ss; #if PDEBUG printf("public name %s with type %d\n", s->name, s->type); #endif if (templatestackp == templatestack) { hoc_execerror("Not in a template\n", 0); } ss = hoc_decl(s); ss->public = PUBLIC_TYPE; } hoc_external_var(s) Symbol *s; { Symbol* s0; if (templatestackp == templatestack) { hoc_execerror("Not in a template\n", 0); } if (s->public == PUBLIC_TYPE) { hoc_execerror(s->name, "can't be public and external"); } s->public = EXTERNAL_TYPE; s0 = hoc_table_lookup(s->name, hoc_top_level_symlist); if (!s0) { hoc_execerror(s->name, "not declared at the top level"); } s->type = s0->type; s->subtype = s0->subtype; switch(s->type) { case FUNCTION: case PROCEDURE: case ITERATOR: case HOCOBJFUNCTION: s->u.u_proc = s0->u.u_proc; break; case TEMPLATE: s->u.template = s0->u.template; break; case STRING: case OBJECTVAR: case VAR: case SECTION: s->arayinfo = s0->arayinfo; s->u.sym = s0; break; default: hoc_execerror(s->name, "type is not allowed external"); break; } } hoc_ob_check(type) int type; { int t; t = ipop(); if (type == -1) { if (t == OBJECTVAR) {/* don't bother to check */ Code(hoc_cmp_otype); codei(0); } }else if (type) { if (t == OBJECTVAR) {/* must check dynamically */ #if PDEBUG printf("dymnamic checking of type=%d\n", type); #endif Code(hoc_cmp_otype); codei(type); }else if (type != t) { /* static check */ hoc_execerror("Type mismatch", (char *)0); } }else{ if (t != OBJECTVAR) { Code(hoc_known_type); codei(t); } } } hoc_free_allobjects(template, sl, data) Template *template; Symlist *sl; Objectdata *data; { /* look in all object variables that point to objects with this template and null them */ Symbol *s; int total, i; Object **obp; if (sl) for (s = sl->first; s; s = s->next) { if (s->type == OBJECTVAR && s->public != 2) { total = hoc_total_array_data(s, data); for (i=0; iu.oboff].pobj + i; if (*obp) { #if 1 if ((*obp)->template == template) { hoc_dec_refcount(obp); }else if (s->subtype != CPLUSOBJECT) { /* descend to look for more */ hoc_free_allobjects(template, (*obp)->template->symtable, (*obp)->u.dataspace); } #else if (s->subtype != CPLUSOBJECT) { /* descend to look for more */ hoc_free_allobjects(template, (*obp)->template->symtable, (*obp)->u.dataspace); } if ((*obp)->template == template) { hoc_dec_refcount(obp); } #endif } } } } } #define objectpath hoc_objectpath_impl #define pathprepend hoc_path_prepend pathprepend(path, name, indx) char* path, *name, *indx; { char buf[200]; if (path[0]) { strcpy(buf, path); sprintf(path, "%s%s.%s",name, indx, buf); }else{ sprintf(path, "%s%s", name, indx); } } int objectpath(ob, oblook, path, depth) Object* ob; Object* oblook; char* path; { /* recursively build the pathname to the object */ Symbol *s; Symlist* sl; int total, i; Objectdata* od; Object **obp; extern char* hoc_araystr(); if (ob == oblook) { return 1; } if (oblook) { if (depth++ > 5) { hoc_warning("objectpath depth > 4 for", oblook->template->sym->name); return 0; } if (oblook->template->constructor) { return ivoc_list_look(ob, oblook, path, depth); }else{ od = oblook->u.dataspace; sl = oblook->template->symtable; } }else{ od = hoc_top_level_data; sl = hoc_top_level_symlist; } if (sl) for (s = sl->first; s; s = s->next) { if (s->type == OBJECTVAR && s->public != 2) { total = hoc_total_array_data(s, od); for (i=0; iu.oboff].pobj + i; if (*obp && *obp != oblook && objectpath(ob, *obp, path, depth)) { pathprepend(path, s->name, hoc_araystr(s, i, od)); return 1; } } } } return 0; } char* hoc_object_pathname(ob) Object* ob; { static char path[200]; path[0] = '\0'; if (objectpath(ob, (Object*)0, path, 0)) { return path; }else{ #if 0 hoc_warning("Couldn't find a pathname to the object pointer", ob->template->sym->name); return (char*)0; #else return hoc_object_name(ob); #endif } } hoc_obj_ref(obj) Object* obj; { if (obj) { ++obj->refcount; } } hoc_dec_refcount(pobj) Object **pobj; { Object* obj; obj = *pobj; if (obj == (Object *)0) { return; } *pobj = (Object *)0; assert(obj->refcount > 0); hoc_obj_unref(obj); } hoc_obj_unref(obj) Object* obj; { Object *obsav; if (!obj) { return; } #if 0 printf("unreffing %s with refcount %d\n", hoc_object_name(obj), obj->refcount); #endif --obj->refcount; if (obj->template->unref) { int i = obj->refcount; pushx((double)i); ++obj->unref_recurse_cnt; call_ob_proc(obj, obj->template->unref, 1); --obj->unref_recurse_cnt; } if (obj->refcount <= 0 && obj->unref_recurse_cnt == 0) { if (obj->aliases) { ivoc_free_alias(obj); } if (obj->observers) { hoc_obj_disconnect(obj); } hoc_l_delete(obj->itm_me); if (obj->template->observers) { hoc_template_notify(obj, 0); } if (obj->template->sym->subtype & (CPLUSOBJECT | JAVAOBJECT)) { (obj->template->destructor)(obj->u.this_pointer); }else{ obsav = hoc_thisobject; hoc_thisobject = obj; free_objectdata(obj->u.dataspace, obj->template); obj->u.dataspace = (Objectdata *)0; hoc_thisobject = obsav; } if (--obj->template->count <= 0) { obj->template->index = 0; } obj->template = (Template *)0; /* for testing purposes we don't free the object in order to make sure no object variable ever uses a freed object */ #if 1 hoc_free_object(obj); #endif } } static free_objectdata(od, template) Objectdata *od; Template *template; { Symbol *s; int i, total; Objectdata *psav; Object **objp; psav = hoc_objectdata; hoc_objectdata = od; if (template->symtable) for (s=template->symtable->first; s; s=s->next) { if (s->public != 2) { switch (s->type) { case VAR: /*printf("free_objectdata %s\n", s->name);*/ hoc_free_val_array(OPVAL(s), hoc_total_array(s)); free_arrayinfo(OPARINFO(s)); break; case STRING: hoc_free_pstring(OPSTR(s)); free_arrayinfo(OPARINFO(s)); break; case OBJECTVAR: objp = OPOBJ(s); if (strcmp("this", s->name) != 0) { total = hoc_total_array(s); for (i = 0; i < total; i++) { hoc_dec_refcount(objp + i); } } free_arrayinfo(OPARINFO(s)); free((char*)objp); break; #if CABLE case SECTION: total = hoc_total_array(s); for (i = 0; i < total; ++i) { extern void sec_free(); sec_free(*(OPSECITM(s) + i)); } free((char*)OPSECITM(s)); free_arrayinfo(OPARINFO(s)); break; #endif } } } #if CABLE if (template->is_point_) { void* v = od[template->dataspace_size-1]._pvoid; if (v) { /* printf("Free point process\n");*/ destroy_point_process(v); } } #endif hoc_objectdata = psav; if (od) { free((char *)od); } } hoc_allobjects() { int n = 0; if (ifarg(1)) { if (hoc_is_str_arg(1)) { hoc_allobjects2(hoc_lookup(gargstr(1)), 0); }else{ Object** o = hoc_objgetarg(1); if (*o) { n = (*o)->refcount; } } }else{ hoc_allobjects1(hoc_built_in_symlist, 0); hoc_allobjects1(hoc_top_level_symlist, 0); } hoc_ret(); pushx((double)n); } hoc_allobjects1(sl, nspace) Symlist* sl; int nspace; { Symbol* s; Template* t; Object* o; Item* q; int i; if (sl) for (s = sl->first; s; s = s->next) { if (s->type == TEMPLATE) { t = s->u.template; ITERATE(q, t->olist) { o = OBJ(q); for (i=0; i < nspace; ++i) { printf(" "); } printf("%s with %d refs\n", hoc_object_name(o), o->refcount); } hoc_allobjects1(t->symtable, nspace+1); } } } hoc_allobjects2(s, nspace) Symbol* s; int nspace; { Template* t; Object* o; Item* q; int i; if (s && s->type == TEMPLATE) { t = s->u.template; ITERATE(q, t->olist) { o = OBJ(q); for (i=0; i < nspace; ++i) { printf(" "); } printf("%s with %d refs\n", hoc_object_name(o), o->refcount); } } } hoc_allobjectvars() { hoc_list_allobjref(hoc_top_level_symlist, hoc_top_level_data, 0); hoc_ret(); pushx(0.); } hoc_list_allobjref(sl, data, depth) Symlist *sl; Objectdata *data; int depth; { /* look in all object variables that point to objects and print them */ Symbol *s; int total, i, id; Object **obp; if (sl) for (s = sl->first; s; s = s->next) { if (s->type == OBJECTVAR && s->public != 2) { total = hoc_total_array_data(s, data); for (i=0; iu.oboff].pobj + i; for (id=0; id %s with %d refs.\n", s->name, i, hoc_object_name(*obp), (*obp)->refcount); }else{ printf("obp %s[%d] -> NULL\n", s->name, i); } if (*obp && !(*obp)->recurse && s->subtype != CPLUSOBJECT && (*obp)->u.dataspace != data /* not this */ ) { /* descend to look for more */ (*obp)->recurse = 1; hoc_list_allobjref((*obp)->template->symtable, (*obp)->u.dataspace, depth+1); (*obp)->recurse = 0; } } } } } check_obj_type(obj, typename) Object* obj; char* typename; { char buf[100]; if (!obj || strcmp(obj->template->sym->name, typename) != 0) { if (obj) { sprintf(buf, "object type is %s instead of", obj->template->sym->name); }else{ sprintf(buf, "object type is nil instead of"); } hoc_execerror(buf, typename); } } int is_obj_type(obj, typename) Object* obj; char* typename; { if (obj && strcmp(obj->template->sym->name, typename) == 0) { return 1; }else{ return 0; } }