NEURON
hoc_oop.cpp
Go to the documentation of this file.
1 #include <../../nrnconf.h>
2 #include <cstdlib>
3 #include <vector>
4 
5 #include "utils/formatting.hpp"
6 
7 
8 #include "classreg.h"
9 #include "neuronapi.h"
10 
11 #include "hocstr.h"
12 #include "parse.hpp"
13 #include "hocparse.h"
14 #include "code.h"
15 #include "cabcode.h"
16 #include "hocassrt.h"
17 #include "hoclist.h"
18 #include "nrn_ansi.h"
19 #include "nrnmpi.h"
20 #include "nrnpy.h"
21 #include "nrnfilewrap.h"
22 #include "ocfunc.h"
23 
24 #define PDEBUG 0
25 
27 #include "section.h"
28 #include "nrniv_mf.h"
30 struct Section* nrn_sec_pop();
31 static int connect_obsec_;
32 
33 #define PUBLIC_TYPE 1
34 #define EXTERNAL_TYPE 2
35 static void call_constructor(Object*, Symbol*, int);
36 static void free_objectdata(Objectdata*, cTemplate*);
37 
38 std::vector<const char*> py_exposed_classes{};
39 
42 
43 static Symbol* hoc_obj_;
44 
45 int (*nrnpy_call_obj_method)(Object* obj, const char* method, Object* obj2) = nullptr;
46 int (*nrnpy_call_obj_method_double)(Object* obj, const char* method, double value) = nullptr;
47 
48 
49 void hoc_install_hoc_obj(void) {
50  /* see void hoc_objvardecl(void) */
51  Object** pobj;
52  Symbol* s = hoc_install("_pysec", OBJECTVAR, 0.0, &hoc_top_level_symlist);
54  hoc_objectdata[s->u.oboff].pobj = pobj = (Object**) emalloc(sizeof(Object*));
55  pobj[0] = nullptr;
56 
57  auto const code = hoc_oc("objref hoc_obj_[2]\n");
58  assert(code == 0);
59  hoc_obj_ = hoc_lookup("hoc_obj_");
60 }
61 
64  if (p) {
65  return p[i];
66  } else {
67  return nullptr;
68  }
69 }
70 
71 void hoc_obj_set(int i, Object* obj) {
73  hoc_obj_ref(obj);
74  hoc_dec_refcount(p + i);
75  p[i] = obj;
76 }
77 
78 char* hoc_object_name(Object* ob) {
79  static char s[100];
80  if (ob) {
81  Sprintf(s, "%s[%d]", ob->ctemplate->sym->name, ob->index);
82  } else {
83  Sprintf(s, "NULLobject");
84  }
85  return s;
86 }
87 
88 size_t hoc_total_array(Symbol* s) /* total number of elements in array pointer */
89 {
90  int total = 1, i;
91  Arrayinfo* a = OPARINFO(s);
92  if (a) {
93  for (i = a->nsub - 1; i >= 0; --i) {
94  total *= a->sub[i];
95  }
96  }
97  return total;
98 }
99 
101  Objectdata* obd) /* total number of elements in array pointer */
102 {
103  Arrayinfo* a;
104  int total = 1, i;
105 
106  if (!obd) {
107  a = s->arayinfo;
108  } else
109  switch (s->type) {
110  case RANGEVAR:
111  a = s->arayinfo;
112  break;
113  default:
114  a = obd[s->u.oboff + 1].arayinfo;
115  break;
116  }
117  if (a) {
118  for (i = a->nsub - 1; i >= 0; --i) {
119  total *= a->sub[i];
120  }
121  }
122  return total;
123 }
124 
125 static int icntobjectdata = 0;
129 static int icnttoplevel;
131 
132 
135 }
136 
138  /* hoc_top_level_data changes when new vars are introduced */
140  /* a template starts out its Objectdata as 0. */
141  return (Objectdata*) 1;
142  } else {
143  return hoc_objectdata;
144  }
145 }
146 
148  if (obdsav == (Objectdata*) 1) {
149  return hoc_top_level_data;
150  ;
151  } else {
152  return obdsav;
153  }
154 }
155 
156 void hoc_obvar_declare(Symbol* sym, int type, int pmes) {
157  if (sym->type != UNDEF) {
158  return;
159  }
160  assert(sym->cpublic != 2);
161  if (pmes && hoc_symlist == hoc_top_level_symlist) {
162  int b = 0;
163  b = (hoc_fin == stdin);
164  if (nrnmpi_myid_world == 0 && (hoc_print_first_instance && b)) {
165  Printf("first instance of %s\n", sym->name);
166  }
167  sym->defined_on_the_fly = 1;
168  }
170  sym->type = type;
171  switch (type) {
172  case VAR:
173  /*printf("hoc_obvar_declare %s\n", sym->name);*/
174  OPVAL(sym) = (double*) ecalloc(1, sizeof(double));
175  break;
176  case STRING:
177  OPSTR(sym) = (char**) 0;
178  break;
179  case OBJECTVAR:
180  break;
181  case SECTION:
182  OPSECITM(sym) = nullptr; // TODO: whaa? (struct Item**)0;
183  break;
184  default:
185  hoc_execerror_fmt("'{}' can't declare this in obvar_declare", sym->name);
186  break;
187  }
188 }
189 
190 /*-----------------------------------------------*/
191 
192 /* template stack so nested templates are ok */
193 typedef union {
198  int i;
199 } Templatedatum;
200 #define NTEMPLATESTACK 20
203 
204 static Templatedatum* poptemplate(void) {
205  if (templatestackp == templatestack) {
206  hoc_execerror("templatestack underflow", nullptr);
207  }
208  return (--templatestackp);
209 }
210 
211 #define pushtemplatesym(arg) \
212  chktemplate(); \
213  (templatestackp++)->sym = arg
214 #define pushtemplatesymlist(arg) \
215  chktemplate(); \
216  (templatestackp++)->symlist = arg
217 #define pushtemplatei(arg) \
218  chktemplate(); \
219  (templatestackp++)->i = arg
220 #define pushtemplateodata(arg) \
221  chktemplate(); \
222  (templatestackp++)->odata = arg
223 #define pushtemplateo(arg) \
224  chktemplate(); \
225  (templatestackp++)->o = arg
226 
227 static void chktemplate(void) {
230  hoc_execerror("templatestack overflow", nullptr);
231  }
232 }
233 /*------------------------------------------------*/
234 
235 /* mostly to allow saving of objects */
236 
237 #define OBJ_STACK_SIZE 10
238 static Object* obj_stack_[OBJ_STACK_SIZE + 1]; /* +1 so we can see the most recent pushed */
239 static int obj_stack_loc;
240 
241 void hoc_object_push(void) {
242  Object* ob = *hoc_objgetarg(1);
243  if (ob->ctemplate->constructor) {
244  hoc_execerror("Can't do object_push for built-in class", nullptr);
245  }
246  if (obj_stack_loc >= OBJ_STACK_SIZE) {
247  hoc_execerror("too many object context stack depth", nullptr);
248  }
251  hoc_thisobject = ob;
252  if (ob) {
254  hoc_objectdata = ob->u.dataspace;
255  } else {
258  }
259  hoc_ret();
260  hoc_pushx(0.);
261 }
262 
263 void hoc_object_pushed(void) {
264  Object* ob;
265  int i = chkarg(1, 0., (double) obj_stack_loc);
266  ob = obj_stack_[obj_stack_loc - i];
267  hoc_ret();
268  hoc_push_object(ob);
269 }
270 
271 void hoc_object_pop(void) {
272  Object* ob;
273  if (obj_stack_loc < 1) {
274  hoc_execerror("object context stack underflow", nullptr);
275  }
276  obj_stack_[obj_stack_loc] = nullptr;
277  ob = obj_stack_[--obj_stack_loc];
278  hoc_thisobject = ob;
279  if (ob) {
281  hoc_objectdata = ob->u.dataspace;
282  } else {
285  }
286  hoc_ret();
287  hoc_pushx(0.);
288 }
289 /*-----------------------------------------------*/
290 int hoc_resize_toplevel(int more) {
291  if (more > 0) {
292  icnttoplevel += more;
294  icnttoplevel * sizeof(Objectdata));
295  if (templatestackp == templatestack) {
297  }
298  }
299  return icnttoplevel;
300 }
301 
303  if (!hoc_objectdata) {
304  icntobjectdata = 0;
305  }
306  sp->u.oboff = icntobjectdata;
307  icntobjectdata += 2; /* data pointer and Arrayinfo */
309  icntobjectdata * sizeof(Objectdata));
311  if (sp->arayinfo) {
312  ++sp->arayinfo->refcount;
313  }
314  if (templatestackp == templatestack) {
317  }
318 }
319 
320 int hoc_obj_run(const char* cmd, Object* ob) {
321  int err;
322  Object* objsave;
323  Objectdata* obdsave;
324  Symlist* slsave;
325  int osloc;
326  objsave = hoc_thisobject;
327  obdsave = hoc_objectdata_save();
328  slsave = hoc_symlist;
329  osloc = obj_stack_loc;
330 
331  if (ob) {
332  if (ob->ctemplate->constructor) {
333  hoc_execerror("Can't execute in a built-in class context", nullptr);
334  }
335  hoc_thisobject = ob;
336  hoc_objectdata = ob->u.dataspace;
338  } else {
339  hoc_thisobject = 0;
342  }
343 
344  err = hoc_oc(cmd);
345 
346  hoc_thisobject = objsave;
348  hoc_symlist = slsave;
349  obj_stack_loc = osloc;
350 
351  return err;
352 }
353 
354 void hoc_exec_cmd(void) { /* execute string from top level or within an object context */
355  int err;
356  char* cmd;
357  char buf[256];
358  char* pbuf;
359  Object* ob = 0;
360  HocStr* hs = 0;
361  cmd = gargstr(1);
362  pbuf = buf;
363  auto pbuf_size = 256;
364  if (strlen(cmd) > 256 - 10) {
365  hs = hocstr_create(strlen(cmd) + 10);
366  pbuf = hs->buf;
367  pbuf_size = hs->size + 1;
368  }
369  if (cmd[0] == '~') {
370  std::snprintf(pbuf, pbuf_size, "%s\n", cmd + 1);
371  } else {
372  std::snprintf(pbuf, pbuf_size, "{%s}\n", cmd);
373  }
374  if (ifarg(2)) {
375  ob = *hoc_objgetarg(2);
376  }
377  err = hoc_obj_run(pbuf, ob);
378  if (err) {
379  hoc_execerror_fmt("execute error:{}", cmd);
380  }
381  if (pbuf != buf) {
382  hocstr_delete(hs);
383  }
384  hoc_ret();
385  hoc_pushx((double) (err));
386 }
387 
388 /* call a function within the context of an object. Args must be on stack */
389 double hoc_call_objfunc(Symbol* s, int narg, Object* ob) {
390  double d; //, hoc_call_func();
391  Object* objsave;
392  Objectdata* obdsave;
393  Symlist* slsave;
394  objsave = hoc_thisobject;
395  obdsave = hoc_objectdata_save();
396  slsave = hoc_symlist;
397 
398  if (ob) {
399  hoc_thisobject = ob;
400  hoc_objectdata = ob->u.dataspace;
402  } else {
403  hoc_thisobject = 0;
406  }
407 
408  d = hoc_call_func(s, narg);
409 
410  hoc_thisobject = objsave;
412  hoc_symlist = slsave;
413 
414  return d;
415 }
416 
422  hoc_thisobject = nullptr;
423  obj_stack_loc = 0;
424  hoc_in_template = 0;
425  connect_obsec_ = 0;
426 }
427 
429  Objectdata** a2,
430  // a3 is missing, do not add it
431  int* a4,
432  Symlist** a5) {
433  *a1 = hoc_thisobject;
434  /* same style as hoc_objectdata_sav */
436  *a2 = (Objectdata*) 1;
437  } else {
438  *a2 = hoc_objectdata;
439  }
440  *a4 = obj_stack_loc;
441  *a5 = hoc_symlist;
442 }
443 
444 void oc_restore_hoc_oop(Object** a1, Objectdata** a2, int* a4, Symlist** a5) {
445  hoc_thisobject = *a1;
446  if (*a2 == (Objectdata*) 1) {
448  } else {
449  hoc_objectdata = *a2;
450  }
451  obj_stack_loc = *a4;
452  hoc_symlist = *a5;
453 }
454 
455 Object* hoc_new_object(Symbol* symtemp, void* v) {
456  Object* ob;
457 #if PDEBUG
458  printf("new object from template %s created.\n", symtemp->name);
459 #endif
460  ob = (Object*) emalloc(sizeof(Object));
461  ob->recurse = 0;
462  ob->unref_recurse_cnt = 0;
463  ob->refcount = 1; /* so template notify will not delete */
464  ob->observers = nullptr;
465  ob->ctemplate = symtemp->u.ctemplate;
466  ob->aliases = nullptr;
467  ob->itm_me = hoc_l_lappendobj(ob->ctemplate->olist, ob);
468  ob->secelm_ = (hoc_Item*) 0;
469  ob->ctemplate->count++;
470  ob->index = ob->ctemplate->index++;
471  if (symtemp->subtype & (CPLUSOBJECT | JAVAOBJECT)) {
472  ob->u.this_pointer = v;
473  if (v) {
474  hoc_template_notify(ob, 1);
475  }
476  } else {
477  ob->u.dataspace = 0;
478  }
479  ob->refcount = 0;
480  return ob;
481 }
482 
483 void hoc_new_object_asgn(Object** obp, Symbol* st, void* v) {
484  hoc_dec_refcount(obp);
485  *obp = hoc_new_object(st, v);
486  hoc_obj_ref(*obp);
487 }
488 
489 Object** hoc_temp_objvar(Symbol* symtemp, void* v) {
490  return hoc_temp_objptr(hoc_new_object(symtemp, v));
491 }
492 
493 struct guard_t {
495  if (ob) {
496  hoc_obj_unref(ob);
497  }
498  }
499  Object* ob{};
500 };
501 
503  Object* ob;
504  Objectdata* obd;
505  Symbol* s;
506  int i, total;
507 
508  guard_t guard{}; // unref the object we're creating if there is an exception before the end of
509  // this method
510  guard.ob = ob = hoc_new_object(sym, nullptr);
511  ob->refcount = 1;
512  if (sym->subtype & (CPLUSOBJECT | JAVAOBJECT)) {
513  call_constructor(ob, sym, narg);
514  } else {
516  sizeof(Objectdata));
517  for (s = ob->ctemplate->symtable->first; s; s = s->next) {
518  if (s->cpublic != 2) {
519  switch (s->type) {
520  case VAR:
521  if ((obd[s->u.oboff + 1].arayinfo = s->arayinfo) != (Arrayinfo*) 0) {
522  ++s->arayinfo->refcount;
523  }
524  total = hoc_total_array_data(s, obd);
525  obd[s->u.oboff].pval = (double*) emalloc(total * sizeof(double));
526  for (i = 0; i < total; i++) {
527  (obd[s->u.oboff].pval)[i] = 0.;
528  }
529  break;
530  case STRING:
531  obd[s->u.oboff + 1].arayinfo = (Arrayinfo*) 0;
532  obd[s->u.oboff].ppstr = (char**) emalloc(sizeof(char*));
533  *obd[s->u.oboff].ppstr = (char*) emalloc(sizeof(char));
534  **(obd[s->u.oboff].ppstr) = '\0';
535  break;
536  case OBJECTVAR:
537  if ((obd[s->u.oboff + 1].arayinfo = s->arayinfo) != (Arrayinfo*) 0) {
538  ++s->arayinfo->refcount;
539  }
540  total = hoc_total_array_data(s, obd);
541  obd[s->u.oboff].pobj = (Object**) emalloc(total * sizeof(Object*));
542  for (i = 0; i < total; i++) {
543  (obd[s->u.oboff].pobj)[i] = (Object*) 0;
544  }
545  if (strcmp(s->name, "this") == 0) {
546  obd[s->u.oboff].pobj[0] = ob;
547  }
548  break;
549  case SECTION:
550  if ((obd[s->u.oboff + 1].arayinfo = s->arayinfo) != (Arrayinfo*) 0) {
551  ++s->arayinfo->refcount;
552  }
553  total = hoc_total_array_data(s, obd);
554  obd[s->u.oboff].psecitm = (hoc_Item**) emalloc(total * sizeof(hoc_Item*));
555  new_sections(ob, s, obd[s->u.oboff].psecitm, total);
556  break;
557  }
558  }
559  }
560  if (ob->ctemplate->is_point_) {
562  }
563  if (ob->ctemplate->init) {
564  hoc_call_ob_proc(ob, ob->ctemplate->init, narg);
565  } else {
566  for (i = 0; i < narg; ++i) {
567  hoc_nopop();
568  }
569  }
570  }
571  hoc_template_notify(ob, 1);
572  guard.ob = nullptr; // do not unref, disable the guard
573  return ob;
574 }
575 
576 void hoc_newobj_arg(void) {
577  Object* ob;
578  Symbol* sym;
579  int narg;
580  sym = (pc++)->sym;
581  narg = (pc++)->i;
582  ob = hoc_newobj1(sym, narg);
583  --ob->refcount; /*not necessarily 0 since init may reference 'this' */
585 }
586 
587 void hoc_newobj_ret(void) {
588  hoc_newobj_arg();
589 }
590 
591 void hoc_newobj(void) { /* template at pc+1 */
592  Symbol* sym = (pc++)->sym;
593  int narg = (pc++)->i;
594 #if USE_PYTHON
595  /* look inside stack because of limited number of temporary objects? */
596  /* whatever. we will keep the strategy */
597  if (hoc_inside_stacktype(narg) == OBJECTVAR) {
598 #endif
599  Object** obp = hoc_look_inside_stack<Object**>(narg);
600  Object* ob = hoc_newobj1(sym, narg);
601  hoc_nopop(); /* the object pointer */
602  hoc_dec_refcount(obp);
603  *(obp) = ob;
604  hoc_pushobj(obp);
605 #if USE_PYTHON
606  } else { /* Assignment to OBJECTTMP not allowed */
608  hoc_execerror("Assignment to $o only allowed if caller arg was declared as objref",
609  nullptr);
610  }
611 #endif
612 }
613 
614 static void call_constructor(Object* ob, Symbol* sym, int narg) {
615  Inst* pcsav;
616  Symlist* slsav;
617  Objectdata* obdsav;
618  Object* obsav;
619 
620  slsav = hoc_symlist;
621  obdsav = hoc_objectdata_save();
622  obsav = hoc_thisobject;
623  pcsav = pc;
624 
625  hoc_push_frame(sym, narg);
627  [ob]() -> std::string {
628  std::string rval{hoc_object_name(ob)};
629  rval.append(" constructor");
630  return rval;
631  },
632  ob->ctemplate->constructor,
633  ob);
634  hoc_pop_frame();
635 
636  pc = pcsav;
637  hoc_symlist = slsav;
639  hoc_thisobject = obsav;
640 }
641 
642 /* When certain methods of some Objects are called, the gui-redirect macros
643  need Object* instead of Object*->u.this_pointer. Not worth changing the
644  prototype of the call as it is used in so many places. So store the Object*
645  to be obtained if needed.
646 */
647 
650  return gui_redirect_obj_;
651 }
652 
653 void hoc_call_ob_proc(Object* ob, Symbol* sym, int narg) {
654  Inst *pcsav, callcode[4];
655  Symlist* slsav;
656  Objectdata* obdsav;
657  Object* obsav;
658 
659  slsav = hoc_symlist;
660  obdsav = hoc_objectdata_save();
661  obsav = hoc_thisobject;
662  pcsav = pc;
663 
664  if (ob->ctemplate->sym->subtype & CPLUSOBJECT) {
665  hoc_thisobject = ob;
666  gui_redirect_obj_ = ob;
667  hoc_push_frame(sym, narg);
668  hoc_thisobject = obsav;
669  auto const error_prefix_generator = [ob, sym]() {
670  std::string rval{hoc_object_name(ob)};
671  rval.append(2, ':');
672  rval.append(sym->name);
673  return rval;
674  };
675  if (sym->type == OBFUNCTION) {
676  auto* const o = neuron::oc::invoke_method_that_may_throw(error_prefix_generator,
677  sym->u.u_proc->defn.pfo_vp,
678  ob->u.this_pointer);
679  if (*o) {
680  ++(*o)->refcount;
681  } /* in case unreffed below */
682  hoc_pop_frame();
683  if (*o) {
684  --(*o)->refcount;
685  }
686  hoc_pushobj(o);
687  } else if (sym->type == STRFUNCTION) {
688  auto* const s = const_cast<char**>(neuron::oc::invoke_method_that_may_throw(
689  error_prefix_generator, sym->u.u_proc->defn.pfs_vp, ob->u.this_pointer));
690  hoc_pop_frame();
691  hoc_pushstr(s);
692  } else {
693  auto x = neuron::oc::invoke_method_that_may_throw(error_prefix_generator,
694  sym->u.u_proc->defn.pfd_vp,
695  ob->u.this_pointer);
696  hoc_pop_frame();
697  hoc_pushx(x);
698  }
699  } else if (ob->ctemplate->is_point_ && special_pnt_call(ob, sym, narg)) {
700  ; /*empty since special_pnt_call did the work for get_loc, has_loc, and loc*/
701  } else {
702  callcode[0].pf = hoc_call;
703  callcode[1].sym = sym;
704  callcode[2].i = narg;
705  callcode[3].in = STOP;
706 
707  hoc_objectdata = ob->u.dataspace;
708  hoc_thisobject = ob;
710  hoc_execute(callcode);
711  if (sym->type == PROCEDURE) {
712  hoc_nopop();
713  }
714  }
715  if (hoc_errno_check()) {
716  char str[200];
717  Sprintf(str, "%s.%s", hoc_object_name(ob), sym->name);
718  hoc_warning("errno set during call of", str);
719  }
720  pc = pcsav;
721  hoc_symlist = slsav;
723  hoc_thisobject = obsav;
724 }
725 
726 static void call_ob_iter(Object* ob, Symbol* sym, int narg) {
727  Symlist* slsav;
728  Objectdata* obdsav;
729  Object* obsav;
730  Object* stmtobj;
731  Inst *stmtbegin, *stmtend;
732 
733  slsav = hoc_symlist;
734  obdsav = hoc_objectdata_save();
735  obsav = hoc_thisobject;
736 
737  hoc_objectdata = ob->u.dataspace;
738  hoc_thisobject = ob;
740 
741  stmtobj = hoc_look_inside_stack<Object*>(narg + 1);
742  stmtbegin = pc + pc->i;
743  pc++;
744  stmtend = pc + pc->i;
745  hoc_iterator_object(sym, narg, stmtbegin, stmtend, stmtobj);
746 
747  /* the stack was popped by hoc_iterator_object
748  hoc_nopop();
749  */
750 
751  hoc_symlist = slsav;
753  hoc_thisobject = obsav;
754 }
755 
756 void hoc_objvardecl(void) { /* symbol at pc+1, number of indices at pc+2 */
757  Symbol* sym;
758  int nsub, size, i;
759  Object** pobj;
760 
761  sym = (pc++)->sym;
762 #if PDEBUG
763  printf("declareing %s as objectvar\n", sym->name);
764 #endif
765  if (sym->type == OBJECTVAR) {
766  int total, i;
767  total = hoc_total_array(sym);
768  for (i = 0; i < total; i++) {
769  hoc_dec_refcount((OPOBJ(sym)) + i);
770  }
771  free(hoc_objectdata[sym->u.oboff].pobj);
772  hoc_freearay(sym);
773  } else {
774  sym->type = OBJECTVAR;
776  }
777  nsub = (pc++)->i;
778  if (nsub) {
779  size = hoc_arayinfo_install(sym, nsub);
780  } else {
781  size = 1;
782  }
783  hoc_objectdata[sym->u.oboff].pobj = pobj = (Object**) emalloc(size * sizeof(Object*));
784  for (i = 0; i < size; i++) {
785  pobj[i] = (Object*) 0;
786  }
787 }
788 
789 void hoc_cmp_otype(void) { /* NUMBER, OBJECTVAR, or STRING must be the type */
790  ++pc;
791 }
792 
793 void hoc_known_type(void) {
794  ++pc;
795 }
796 
797 void hoc_objectvar(void) { /* object variable symbol at pc+1. */
798  /* pointer to correct object left on stack */
799  Objectdata* odsav;
800  Object* obsav = 0;
801  Symlist* slsav;
802  Symbol* obs;
803  Object** obp;
804 #if PDEBUG
805  printf("code for hoc_objectvar()\n");
806 #endif
807  obs = (pc++)->sym;
808  if (obs->cpublic == 2) {
809  obs = obs->u.sym;
810  odsav = hoc_objectdata_save();
811  obsav = hoc_thisobject;
812  slsav = hoc_symlist;
814  hoc_thisobject = 0;
816  }
817  obp = OPOBJ(obs);
818  if (is_array(*obs)) {
819  hoc_pushobj(obp + hoc_araypt(obs, OBJECTVAR));
820  } else {
821  hoc_pushobj(obp);
822  }
823  if (obsav) {
825  hoc_thisobject = obsav;
826  hoc_symlist = slsav;
827  }
828 }
829 
830 void hoc_objectarg(void) { /* object arg index at pc+1. */
831  /* pointer to correct object left on stack */
832  int i;
833  Object** obp;
834 #if PDEBUG
835  printf("code for hoc_objectarg()\n");
836 #endif
837  i = (pc++)->i;
838  if (i == 0) {
839  i = hoc_argindex();
840  }
841  obp = hoc_objgetarg(i);
842  hoc_pushobj(obp);
843 }
844 
845 void hoc_constobject(void) { /* template at pc, index at pc+1, objpointer left on stack*/
846  char buf[200];
847  Object* obj;
848  hoc_Item* q;
849  cTemplate* t = (pc++)->sym->u.ctemplate;
850  int index = (int) hoc_xpop();
851  ITERATE(q, t->olist) {
852  obj = OBJ(q);
853  if (obj->index == index) {
855  return;
856  } else if (obj->index > index) {
857  break;
858  }
859  }
860  Sprintf(buf, "%s[%d]\n", t->sym->name, index);
861  hoc_execerror("Object ID doesn't exist '{}'", buf);
862 }
863 
864 Object* hoc_name2obj(const char* name, int index) {
865  char buf[200];
866  Object* obj;
867  hoc_Item* q;
868  cTemplate* t;
869  Symbol* sym;
871  if (!sym) {
873  }
874  if (!sym || sym->type != TEMPLATE) {
875  hoc_execerror_fmt("'{}' is not a template", name);
876  }
877  t = sym->u.ctemplate;
878  ITERATE(q, t->olist) {
879  obj = OBJ(q);
880  if (obj->index == index) {
881  return obj;
882  } else if (obj->index > index) {
883  break;
884  }
885  }
886  return nullptr;
887 }
888 
889 void hoc_object_id(void) {
890  Object* ob;
891 
892  ob = *(hoc_objgetarg(1));
893  if (ifarg(2) && chkarg(2, 0., 1.) == 1.) {
894  hoc_ret();
895  if (ob) {
896  hoc_pushx((double) ob->index);
897  } else {
898  hoc_pushx(-1.);
899  }
900  } else {
901  hoc_ret();
902  hoc_pushx((double) ((size_t) ob));
903  }
904 }
905 
906 static void range_suffix(Symbol* sym, int nindex, int narg) {
907  int bdim = 0;
908  if (is_array(*sym)) {
909  if (nindex != sym->arayinfo->nsub) {
910  bdim = 1;
911  }
912  /*
913  It is a bit more difficult to push ndim here since the arc length, if
914  specified, is top of stack before the index. However, waiting to fix up
915  the stack til just before range_vec_indx calls hoc_araypt seems ill
916  advised since range_vec_indx is called 6 places. And who knows what
917  kinds of user errors are possible that we want to catch.
918  So fix up below.
919  */
920  } else {
921  if (nindex != 0) {
922  bdim = 1;
923  }
924  }
925  if (bdim) {
926  hoc_execerror_fmt("'{}' wrong number of array dimensions", sym->name);
927  }
928 
929  if (sym->type == RANGEVAR) {
930  if (is_array(*sym)) { // fixup ndim here
931  double x = -1.0;
932  if (narg) { // need to pop the arc length to push ndim
933  if (narg > 1) {
934  hoc_execerror_fmt("'{}' range variable can have only one arc length parameter",
935  sym->name);
936  }
937  x = xpop();
938  }
939  if (!hoc_stack_type_is_ndim()) {
940  hoc_push_ndim(nindex);
941  }
942  if (narg) { // push back the arc length
943  hoc_pushx(x);
944  }
945  }
946  hoc_pushi(narg);
947  hoc_pushs(sym);
948  } else if (sym->subtype == USERPROPERTY) {
949  if (narg) {
950  hoc_execerror_fmt("'{}' section property can't have argument", sym->name);
951  }
952  hoc_pushs(sym);
953  } else if (sym->type == RANGEOBJ) {
954  // must return NMODLObject on stack
955  assert(sym->subtype == NMODLRANDOM); // the only possibility at the moment
956  double x{0.5};
957  if (narg) {
958  if (narg > 1) {
959  hoc_execerror_fmt("'{}' range object can have only one arg length parameter",
960  sym->name);
961  }
962  x = xpop();
963  }
964  Section* sec{nrn_sec_pop()};
965  auto const i = node_index(sec, x);
966  Prop* m = nrn_mechanism_check(sym->u.rng.type, sec, i);
967  Object* ob = nrn_nmodlrandom_wrap(m, sym);
968  hoc_push_object(ob);
969  } else {
970  hoc_execerror_fmt("'{}' suffix not a range variable or section property", sym->name);
971  }
972 }
973 
975  connect_obsec_ = 1;
976 }
977 
978 // number of indices at pc+2, number of args at pc+3, symbol at pc+1
979 // object pointer on stack after indices
980 // if component turns out to be an object then make sure pointer to correct
981 // object, symbol, etc is left on stack for evaluation, assignment, etc.
983  Symbol *sym0, *sym = 0;
984  int nindex, narg, cplus, isfunc;
985  Object *obp, *obsav;
986  Objectdata* psav;
987  int* ptid;
988  Symbol** psym;
989 
990 #if PDEBUG
991  printf("code for hoc_object_component()\n");
992 #endif
993  sym0 = (pc++)->sym;
994  nindex = (pc++)->i;
995  narg = (pc++)->i;
996  ptid = &(pc++)->i;
997  psym = &(pc++)->sym;
998  isfunc = (pc++)->i;
999 
1000  if (section_object_seen) {
1001  section_object_seen = 0;
1002  range_suffix(sym0, nindex, narg);
1003  return;
1004  }
1005  if (connect_obsec_) {
1006  narg += nindex;
1007  nindex = 0;
1008  }
1009  int expect_stack_nsub{0};
1010  if (nindex) {
1011  if (narg) {
1012  hoc_execerror("[...](...) syntax only allowed for array range variables:", sym0->name);
1013  }
1014  if (!hoc_stack_type_is_ndim()) {
1015  hoc_push_ndim(nindex);
1016  }
1017  expect_stack_nsub = 1;
1018  } else {
1019  nindex = narg;
1020  }
1021  obp = hoc_obj_look_inside_stack(nindex + expect_stack_nsub);
1022  if (obp) {
1023 #if USE_PYTHON
1024  if (obp->ctemplate->sym == nrnpy_pyobj_sym_) {
1025  if (isfunc & 2) {
1026  /* this is the final left hand side of an
1027  assignment to the method of a PythonObject
1028  and we need to put the PythonObject and the
1029  method with all its info onto the stack so that
1030  a proper __setattro__ or __setitem__ can be
1031  accomplished in the next hoc_object_asgn
1032  */
1033  if (isfunc & 1) {
1034  hoc_execerror_fmt("Cannot assign to a PythonObject function call '{}'",
1035  sym0->name);
1036  }
1037  hoc_pushi(nindex);
1038  hoc_pushs(sym0);
1039  hoc_push_object(obp);
1040  /* note obp is now on stack twice */
1041  /* hpoasgn will pop both */
1042  } else {
1043  neuron::python::methods.py2n_component(obp, sym0, nindex, isfunc);
1044  }
1045  return;
1046  }
1047 #endif
1048  if (obp->ctemplate->id == *ptid) {
1049  sym = *psym;
1050  } else {
1051  if (obp->aliases == 0 || (sym = ivoc_alias_lookup(sym0->name, obp)) == 0) {
1052  /* lookup only has to be done once if the name is not an alias
1053  and the ptid of the object is still the same. */
1054  sym = hoc_table_lookup(sym0->name, obp->ctemplate->symtable);
1055  if (!sym || sym->cpublic != PUBLIC_TYPE) {
1056  auto err = fmt::format("'{}' not a public member of '{}'",
1057  sym0->name,
1058  obp->ctemplate->sym->name);
1059  Fprintf(stderr, fmt::format("{}\n", err).c_str());
1060  hoc_execerror(err.c_str(), nullptr);
1061  }
1062  *ptid = obp->ctemplate->id;
1063  *psym = sym;
1064  }
1065  }
1066  } else {
1067  hoc_execerror_fmt("'{}' object prefix is nullptr", sym0->name);
1068  }
1069 
1070  psav = hoc_objectdata_save();
1071  obsav = hoc_thisobject;
1072  cplus = (obp->ctemplate->sym->subtype & (CPLUSOBJECT | JAVAOBJECT));
1073  if (!cplus) { /* c++ classes don't have a hoc dataspace */
1074  hoc_objectdata = obp->u.dataspace;
1075  hoc_thisobject = obp;
1076  }
1077  switch (sym->type) {
1078  case OBJECTVAR:
1079  if (nindex) {
1080  if (!is_array(*sym) || OPARINFO(sym)->nsub != nindex) {
1081  hoc_execerror_fmt("'{}' not right number of subscripts", sym->name);
1082  }
1083  nindex = hoc_araypt(sym, OBJECTVAR);
1084  }
1085  hoc_pop_defer();
1086  hoc_pushobj(OPOBJ(sym) + nindex);
1087  break;
1088  case VAR:
1089  if (cplus) {
1090  if (nindex) {
1091  if (!is_array(*sym) || sym->arayinfo->nsub != nindex) {
1092  hoc_execerror_fmt("'{}' not right number of subscripts", sym->name);
1093  }
1094  if (narg) {
1095  // there are 25 modeldb examples that use (index) instead
1096  // of [index] syntax for an array in this context. So we
1097  // have decided to keep allowing this legacy syntax for one
1098  // dimensional arrays.
1099  extern Symbol* nrn_matrix_sym;
1100  if (narg == 1) {
1101  hoc_push_ndim(1);
1102  } else if (narg == 2 && obp->ctemplate->sym == nrn_matrix_sym) {
1103  // Allow legacy syntax Matrix.x(i, j)
1104  hoc_push_ndim(2);
1105  } else {
1106  hoc_execerror_fmt("'{}.{}' is array not function. Use '{}[...]' syntax",
1107  hoc_object_name(obp),
1108  sym->name,
1109  sym->name);
1110  }
1111  }
1112  }
1113  hoc_pushs(sym);
1114  (*obp->ctemplate->steer)(obp->u.this_pointer);
1115  double* pd = hoc_pxpop();
1116  /* cannot pop a temporary object til after the pd is used in
1117  case (e.g. Vector.x) the pointer is a field in the object
1118  (often the pd has nothing to do with the object)*/
1119  hoc_pop_defer(); /* corresponding unref_defer soon */
1120  hoc_pushpx(pd);
1121  } else {
1122  if (nindex) {
1123  if (!is_array(*sym) || OPARINFO(sym)->nsub != nindex) {
1124  hoc_execerror_fmt("'{}' not right number of subscripts", sym->name);
1125  }
1126  if (narg) {
1127  // there are a few modeldb examples that use (index) instead
1128  // of [index] syntax for an array in this context. So we
1129  // have decided to keep allowing this legacy syntax for one
1130  // dimensional arrays.
1131  if (narg == 1) {
1132  hoc_push_ndim(1);
1133  } else {
1134  hoc_execerror_fmt("'{}.{}' is array not function. Use '{}[...]' syntax",
1135  hoc_object_name(obp),
1136  sym->name,
1137  sym->name);
1138  }
1139  }
1140  nindex = hoc_araypt(sym, OBJECTVAR);
1141  }
1142  hoc_pop_defer(); /*finally get rid of symbol */
1143  hoc_pushpx(OPVAL(sym) + nindex);
1144  }
1145  break;
1146  case STRING:
1147  if (nindex) {
1148  hoc_execerror_fmt("'{}' string can't have function arguments or array indices",
1149  sym->name);
1150  }
1151  hoc_pop_defer();
1152  hoc_pushstr(OPSTR(sym));
1153  break;
1154  case PROCEDURE:
1155  case FUNCTION: {
1156  if (expect_stack_nsub) {
1157  hoc_pop_ndim();
1158  hoc_execerror_fmt("'{}' is a function not a {}-dim array", sym->name, nindex);
1159  }
1160  double d = 0.;
1161  hoc_call_ob_proc(obp, sym, nindex);
1162  if (hoc_returning) {
1163  break;
1164  }
1165  if (sym->type == FUNCTION) {
1166  d = hoc_xpop();
1167  }
1168  hoc_pop_defer();
1169  hoc_pushx(d);
1170  break;
1171  }
1172  case HOCOBJFUNCTION:
1173  case OBFUNCTION: {
1174  Object** d;
1175  if (expect_stack_nsub) {
1176  hoc_pop_ndim();
1177  // for legacy reasons allow single arg [] format.
1178  // E.g. occasionally seen for List.object[index]
1179  if (nindex > 1) {
1180  hoc_execerror_fmt("'{}' is a function not a {}-dim array", sym->name, nindex);
1181  }
1182  }
1183  hoc_call_ob_proc(obp, sym, nindex);
1184  if (hoc_returning) {
1185  break;
1186  }
1187  d = hoc_objpop();
1188  if (*d) {
1189  (*d)->refcount++;
1190  } /* nopop may unref if temp obj.*/
1191  hoc_pop_defer();
1192  hoc_pushobj(d);
1193  if (*d) {
1194  (*d)->refcount--;
1195  } /* see the nopop may unref comment */
1196  hoc_tobj_unref(d);
1197  break;
1198  }
1199  case STRFUNCTION: {
1200  char** d;
1201  hoc_call_ob_proc(obp, sym, nindex);
1202  if (hoc_returning) {
1203  break;
1204  }
1205  d = hoc_strpop();
1206  hoc_pop_defer();
1207  hoc_pushstr(d);
1208  break;
1209  }
1210  case SECTIONREF: {
1211  extern Symbol* nrn_sec_sym;
1212  Section* sec;
1213  extern Section* nrn_sectionref_steer(Section * sec, Symbol * sym, int* pnindex);
1214  section_object_seen = 1;
1215  sec = (Section*) obp->u.this_pointer;
1216  if (sym != nrn_sec_sym) {
1217  sec = nrn_sectionref_steer(sec, sym, &nindex);
1218  }
1219  if (nrn_inpython_ == 2) {
1220  section_object_seen = 0;
1221  hoc_pop_defer();
1223  hoc_thisobject = obsav;
1224  return;
1225  }
1226  if (connect_obsec_) {
1227  double x = 0.0;
1228  connect_obsec_ = 0;
1229  if (nindex != 1) {
1230  hoc_execerror_fmt("'{}' bad connect syntax", sym->name);
1231  }
1232  x = hoc_xpop();
1233  hoc_pop_defer();
1234  hoc_pushx(x);
1235  } else {
1236  if (nindex) {
1237  hoc_execerror_fmt("'{}' no subscript allowed", sym->name);
1238  }
1239  hoc_pop_defer();
1240  }
1241  if (!sec->prop) {
1242  hoc_execerror("Section was deleted", nullptr);
1243  }
1244  nrn_pushsec(sec);
1245  break;
1246  }
1247  case SECTION: {
1248  double x = 0.0;
1249  section_object_seen = 1;
1250  if (connect_obsec_) {
1251  x = hoc_xpop();
1252  if (!nindex) {
1253  hoc_execerror_fmt("'{}' bad connect syntax", sym->name);
1254  }
1255  --nindex;
1256  }
1257  if (nindex) {
1258  if (!is_array(*sym) || OPARINFO(sym)->nsub != nindex) {
1259  hoc_execerror_fmt("'{}' not right number of subscripts", sym->name);
1260  }
1261  if (!hoc_stack_type_is_ndim()) {
1262  hoc_push_ndim(nindex);
1263  }
1264  nindex = hoc_araypt(sym, OBJECTVAR);
1265  }
1266  hoc_pop_defer();
1267  if (connect_obsec_) {
1268  hoc_pushx(x);
1269  connect_obsec_ = 0;
1270  }
1271  ob_sec_access_push(*(OPSECITM(sym) + nindex));
1272  break;
1273  }
1274  case ITERATOR: {
1275  if ((pc++)->i != ITERATOR) {
1276  hoc_execerror_fmt("'{}' ITERATOR can only be used in a for statement", sym->name);
1277  }
1278  call_ob_iter(obp, sym, nindex);
1279  if (hoc_returning) {
1280  break;
1281  }
1282  hoc_pop_defer();
1283  hoc_nopop(); /* get rid of iterator statement context */
1284  break;
1285  }
1286  case RANGEOBJ: {
1287  assert(sym->subtype == NMODLRANDOM);
1288  if (sym->subtype == NMODLRANDOM) { // NMODL NEURON block RANDOM var
1289  // RANGE type. The void* is a nrnran123_State*. Wrap in a
1290  // NMODLRandom and push_object
1292  hoc_pop_defer();
1293  hoc_push_object(o);
1294  }
1295  break;
1296  }
1297  default:
1298  if (cplus) {
1299  if (nindex) {
1300  if (!is_array(*sym) || sym->arayinfo->nsub != nindex) {
1301  hoc_execerror_fmt("'{}' not right number of subscripts", sym->name);
1302  }
1303  if (narg) {
1304  // there are a few modeldb examples that use (index) instead
1305  // of [index] syntax for an array in this context. So we
1306  // have decided to keep allowing this legacy syntax for one
1307  // dimensional arrays.
1308  if (narg == 1) {
1309  hoc_push_ndim(1);
1310  } else {
1311  hoc_execerror_fmt("'{}.{}' is array not function. Use '{}[...]' syntax",
1312  hoc_object_name(obp),
1313  sym->name,
1314  sym->name);
1315  }
1316  }
1317  }
1318  hoc_pushs(sym);
1319  (*obp->ctemplate->steer)(obp->u.this_pointer);
1320  auto dh = hoc_pop_handle<double>();
1321  hoc_pop_defer();
1322  hoc_push(std::move(dh));
1323  } else {
1324  hoc_execerror_fmt("{}: can't push that type onto stack", sym->name);
1325  }
1326  break;
1327  case OBJECTALIAS:
1328  if (nindex) {
1329  hoc_execerror_fmt("{}: is an alias and cannot have subscripts", sym->name);
1330  }
1331  hoc_pop_defer();
1332  hoc_push_object(sym->u.object_);
1333  break;
1334  case VARALIAS:
1335  if (nindex) {
1336  hoc_execerror_fmt("{}: is an alias and cannot have subscripts", sym->name);
1337  }
1338  hoc_pop_defer();
1339  hoc_pushpx(sym->u.pval);
1340  break;
1341  }
1343  hoc_thisobject = obsav;
1344 }
1345 
1346 void hoc_object_eval(void) {
1347  int type;
1348 #if PDEBUG
1349  printf("code for hoc_object_eval\n");
1350 #endif
1351  type = hoc_stacktype();
1352  if (type == VAR) {
1353  hoc_pushx(*(hoc_pxpop()));
1354  } else if (type == SYMBOL) {
1355  auto* d_sym = hoc_look_inside_stack<Symbol*>(0);
1356  if (d_sym->type == RANGEVAR) {
1357  Symbol* sym = hoc_spop();
1358  int narg = hoc_ipop();
1359  struct Section* sec = nrn_sec_pop();
1360  double x;
1361  if (narg) {
1362  x = hoc_xpop();
1363  } else {
1364  x = .5;
1365  }
1366  hoc_pushx(*(nrn_rangepointer(sec, sym, x)));
1367  } else if (d_sym->type == VAR && d_sym->subtype == USERPROPERTY) {
1369  }
1370  }
1371 }
1372 
1373 void hoc_ob_pointer(void) {
1374 #if PDEBUG
1375  printf("code for hoc_ob_pointer\n");
1376 #endif
1377  int type = hoc_stacktype();
1378  if (type == VAR) {
1379  } else if (type == SYMBOL) {
1380  auto* d_sym = hoc_look_inside_stack<Symbol*>(0);
1381  if (d_sym->type == RANGEVAR) {
1382  Symbol* sym = hoc_spop();
1383  int nindex = hoc_ipop();
1384  Section* sec = nrn_sec_pop();
1385  double x = nindex ? hoc_xpop() : .5;
1386  hoc_push(nrn_rangepointer(sec, sym, x));
1387  } else if (d_sym->type == VAR && d_sym->subtype == USERPROPERTY) {
1389  } else {
1390  hoc_execerror("Not a double pointer", nullptr);
1391  }
1392  } else {
1393  hoc_execerror("Not a double pointer", nullptr);
1394  }
1395 }
1396 
1397 void hoc_asgn_obj_to_str(void) { /* string on stack */
1398  char *d, **pstr;
1399  d = *(hoc_strpop());
1400  pstr = hoc_strpop();
1401  hoc_assign_str(pstr, d);
1402 }
1403 
1405  int op = (pc++)->i;
1406  int type1 = hoc_stacktype(); // type of top entry
1407  int type2 = hoc_inside_stacktype(1); // type of second-top entry
1408  if (type2 == SYMBOL) {
1409  auto* sym = hoc_look_inside_stack<Symbol*>(1);
1410  if (sym->type == RANGEVAR) {
1411  type2 = RANGEVAR;
1412  } else if (sym->type == VAR && sym->subtype == USERPROPERTY) {
1413  type2 = USERPROPERTY;
1414  }
1415  }
1416  if (type2 == RANGEVAR && type1 == NUMBER) {
1417  double d = hoc_xpop();
1418  Symbol* sym = hoc_spop();
1419  int nindex = hoc_ipop();
1420  Section* sec = nrn_sec_pop();
1421  if (nindex) {
1422  auto pd = nrn_rangepointer(sec, sym, hoc_xpop());
1423  if (op) {
1424  d = hoc_opasgn(op, *pd, d);
1425  }
1426  *pd = d;
1427  } else {
1429  sym,
1431  &d},
1432  op);
1433  }
1434  hoc_pushx(d);
1435  return;
1436  } else if (type2 == USERPROPERTY && type1 == NUMBER) {
1437  double d = hoc_xpop();
1438  cable_prop_assign(hoc_spop(), &d, op);
1439  hoc_pushx(d);
1440  return;
1441  }
1442  switch (type2) {
1443  case VAR: {
1444  double d, *pd;
1445  d = hoc_xpop();
1446  pd = hoc_pxpop();
1447  if (op) {
1448  d = hoc_opasgn(op, *pd, d);
1449  }
1450  *pd = d;
1451  hoc_pushx(d);
1452  } break;
1453  case OBJECTVAR: {
1454  if (op) {
1455  hoc_execerror("Invalid assignment operator for object", nullptr);
1456  }
1457  Object** d = hoc_objpop();
1458  Object** pd = hoc_objpop();
1459  if (d != pd) {
1460  Object* tobj = *d;
1461  if (tobj) {
1462  (tobj)->refcount++;
1463  }
1464  hoc_tobj_unref(d);
1465  hoc_dec_refcount(pd);
1466  *pd = tobj;
1467  }
1468  hoc_pushobj(pd);
1469  } break;
1470  case STRING: {
1471  if (op) {
1472  hoc_execerror("Invalid assignment operator for string", nullptr);
1473  }
1474  char* d = *(hoc_strpop());
1475  char** pd = hoc_strpop();
1476  hoc_assign_str(pd, d);
1477  hoc_pushstr(pd);
1478  } break;
1479 #if USE_PYTHON
1480  case OBJECTTMP: { /* should be PythonObject */
1483  if (op) {
1484  hoc_execerror("Invalid assignment operator for PythonObject", nullptr);
1485  }
1486  neuron::python::methods.hpoasgn(o, type1);
1487  } break;
1488 #endif
1489  default:
1490  hoc_execerror("Cannot assign to left hand side", nullptr);
1491  }
1492 }
1493 
1494 /* if the name isn't a template then look in the top level symbol table.
1495 This allows objects to create objects of any class defined at the top level
1496 */
1498  if (s->type != TEMPLATE) {
1499  Symbol* s1;
1501  if (!s1 || s1->type != TEMPLATE) {
1502  hoc_execerror(s->name, "is not a template");
1503  }
1504  s = s1;
1505  }
1506  return s;
1507 }
1508 
1509 /* pushes old symtable and template name on template stack.
1510 And creates new symtable. The new symtable
1511 is used for all non-builtin names until an endtemplate is reached
1512 */
1513 static int template_id;
1514 
1516  Symbol* t;
1517  int type;
1518  t = hoc_decl(t1);
1519 
1520 #if PDEBUG
1521  printf("begin template %s\n", t->name);
1522 #endif
1523  type = t->type;
1524  if (type == TEMPLATE) {
1525  hoc_execerror(t->name, ": a template cannot be redefined");
1526  extern void hoc_free_symspace(Symbol*);
1528  } else if (type != UNDEF) {
1529  hoc_execerror(t->name, "already used as something besides template");
1530  }
1531  t->u.ctemplate = (cTemplate*) emalloc(sizeof(cTemplate));
1532  t->type = TEMPLATE;
1533  t->u.ctemplate->sym = t;
1534  t->u.ctemplate->symtable = (Symlist*) 0;
1535  t->u.ctemplate->dataspace_size = 0;
1536  t->u.ctemplate->constructor = 0;
1537  t->u.ctemplate->destructor = 0;
1538  t->u.ctemplate->is_point_ = 0;
1539  t->u.ctemplate->steer = 0;
1540  t->u.ctemplate->id = ++template_id;
1546  pushtemplatesym(t);
1547  hoc_in_template = 1;
1548  hoc_objectdata = (Objectdata*) 0;
1549  hoc_thisobject = nullptr;
1550  hoc_symlist = t->u.ctemplate->symtable;
1551 }
1552 
1554  Symbol *ts, *s;
1555 #if PDEBUG
1556  printf("end template %s\n", t->name);
1557 #endif
1558  ts = (poptemplate())->sym;
1559  if (strcmp(ts->name, t->name) != 0) {
1560  hoc_execerror(t->name, "- end template mismatched with begin");
1561  }
1564  ts->u.ctemplate->count = 0;
1565  ts->u.ctemplate->index = 0;
1566  ts->u.ctemplate->olist = hoc_l_newlist();
1567  ts->u.ctemplate->observers = nullptr;
1570  hoc_thisobject = (poptemplate())->o;
1571  hoc_in_template = (poptemplate())->i;
1572  hoc_objectdata = (poptemplate())->odata;
1573  icntobjectdata = (poptemplate())->i;
1574  ts->u.ctemplate->init = s = hoc_table_lookup("init", ts->u.ctemplate->symtable);
1575  if (s && s->type != PROCEDURE) {
1576  hoc_execerror("'init' can only be used as the initialization procedure for new objects",
1577  nullptr);
1578  }
1579  ts->u.ctemplate->unref = s = hoc_table_lookup("unref", ts->u.ctemplate->symtable);
1580  if (s && s->type != PROCEDURE) {
1581  hoc_execerror(
1582  "'unref' can only be used as the callback procedure when the reference count is "
1583  "decremented",
1584  nullptr);
1585  }
1586 }
1587 
1588 void class2oc_base(const char* name,
1589  ctor_f* cons,
1590  dtor_f* destruct,
1591  Member_func* m,
1592  Member_ret_obj_func* mobjret,
1593  Member_ret_str_func* strret) {
1594  extern int hoc_main1_inited_;
1595  Symbol *tsym, *s;
1596  cTemplate* t;
1597  int i;
1598 
1599  if (hoc_lookup(name)) {
1600  hoc_execerror(name, "already being used as a name");
1601  }
1602 
1603  tsym = hoc_install(name, UNDEF, 0.0, &hoc_symlist);
1604  tsym->subtype = CPLUSOBJECT;
1605  hoc_begintemplate(tsym);
1606  t = tsym->u.ctemplate;
1609  }
1610  t->constructor = cons;
1611  t->destructor = destruct;
1612  t->steer = 0;
1613 
1614  if (m)
1615  for (i = 0; m[i].name; ++i) {
1616  s = hoc_install(m[i].name, FUNCTION, 0.0, &hoc_symlist);
1617  s->u.u_proc->defn.pfd_vp = m[i].member;
1619  }
1620  if (mobjret)
1621  for (i = 0; mobjret[i].name; ++i) {
1622  s = hoc_install(mobjret[i].name, OBFUNCTION, 0.0, &hoc_symlist);
1623  s->u.u_proc->defn.pfo_vp = mobjret[i].member;
1625  }
1626  if (strret)
1627  for (i = 0; strret[i].name; ++i) {
1628  s = hoc_install(strret[i].name, STRFUNCTION, 0.0, &hoc_symlist);
1629  s->u.u_proc->defn.pfs_vp = strret[i].member;
1631  }
1632  hoc_endtemplate(tsym);
1633 }
1634 
1635 
1636 void class2oc(const char* name,
1637  ctor_f* cons,
1638  dtor_f* destruct,
1639  Member_func* m,
1640  Member_ret_obj_func* mobjret,
1641  Member_ret_str_func* strret) {
1642  class2oc_base(name, cons, destruct, m, mobjret, strret);
1643  py_exposed_classes.push_back(name);
1644 }
1645 
1647  Symbol* ss;
1648  if (templatestackp == templatestack) {
1649  if (s == hoc_table_lookup(s->name, hoc_built_in_symlist)) {
1650  hoc_execerror(s->name, ": Redeclaring at top level");
1651  }
1652  return s;
1653  }
1654  ss = hoc_table_lookup(s->name, hoc_symlist);
1655  if (!ss) {
1656  ss = hoc_install(s->name, UNDEF, 0.0, &hoc_symlist);
1657  }
1658  return ss;
1659 }
1660 
1662  Symbol* ss;
1663 #if PDEBUG
1664  printf("public name %s with type %d\n", s->name, s->type);
1665 #endif
1666  if (templatestackp == templatestack) {
1667  hoc_execerror("Not in a template\n", 0);
1668  }
1669  ss = hoc_decl(s);
1670  ss->cpublic = PUBLIC_TYPE;
1671 }
1672 
1674  Symbol* s0;
1675  if (templatestackp == templatestack) {
1676  hoc_execerror("Not in a template\n", 0);
1677  }
1678  if (s->cpublic == PUBLIC_TYPE) {
1679  hoc_execerror(s->name, "can't be public and external");
1680  }
1681  s->cpublic = EXTERNAL_TYPE;
1683  if (!s0) {
1684  hoc_execerror(s->name, "not declared at the top level");
1685  }
1686  s->type = s0->type;
1687  s->subtype = s0->subtype;
1688  switch (s->type) {
1689  case FUNCTION:
1690  case PROCEDURE:
1691  case ITERATOR:
1692  case HOCOBJFUNCTION:
1693  s->u.u_proc = s0->u.u_proc;
1694  break;
1695  case TEMPLATE:
1696  s->u.ctemplate = s0->u.ctemplate;
1697  break;
1698  case STRING:
1699  case OBJECTVAR:
1700  case VAR:
1701  case SECTION:
1702  s->arayinfo = s0->arayinfo;
1703  s->u.sym = s0;
1704  break;
1705  default:
1706  hoc_execerror(s->name, "type is not allowed external");
1707  break;
1708  }
1709 }
1710 
1711 void hoc_ob_check(int type) {
1712  int t;
1713  t = hoc_ipop();
1714  if (type == -1) {
1715  if (t == OBJECTVAR) { /* don't bother to check */
1717  hoc_codei(0);
1718  }
1719  } else if (type) {
1720  if (t == OBJECTVAR) { /* must check dynamically */
1721 #if PDEBUG
1722  printf("dymnamic checking of type=%d\n", type);
1723 #endif
1725  hoc_codei(type);
1726  } else if (type != t) { /* static check */
1727  hoc_execerror("Type mismatch", (char*) 0);
1728  }
1729  } else {
1730  if (t != OBJECTVAR) {
1732  hoc_codei(t);
1733  }
1734  }
1735 }
1736 
1738  /* look in all object variables that point to
1739  objects with this template and null them */
1740  Symbol* s;
1741  int total, i;
1742  Object** obp;
1743 
1744  if (sl)
1745  for (s = sl->first; s; s = s->next) {
1746  if (s->type == OBJECTVAR && s->cpublic != 2) {
1747  total = hoc_total_array_data(s, data);
1748  for (i = 0; i < total; i++) {
1749  obp = data[s->u.oboff].pobj + i;
1750  if (*obp) {
1751 #if 1
1752  if ((*obp)->ctemplate == ctemplate) {
1753  hoc_dec_refcount(obp);
1754  } else if (s->subtype != CPLUSOBJECT) {
1755  /* descend to look for more */
1756  hoc_free_allobjects(ctemplate,
1757  (*obp)->ctemplate->symtable,
1758  (*obp)->u.dataspace);
1759  }
1760 #else
1761  if (s->subtype != CPLUSOBJECT) {
1762  /* descend to look for more */
1763  hoc_free_allobjects(ctemplate,
1764  (*obp)->ctemplate->symtable,
1765  (*obp)->u.dataspace);
1766  }
1767  if ((*obp)->ctemplate == ctemplate) {
1768  hoc_dec_refcount(obp);
1769  }
1770 #endif
1771  }
1772  }
1773  }
1774  }
1775 }
1776 
1777 #define objectpath hoc_objectpath_impl
1778 #define pathprepend hoc_path_prepend
1779 
1780 constexpr std::size_t hoc_object_pathname_bufsize = 512;
1781 void pathprepend(char* path, const char* name, const char* indx) {
1782  char buf[200];
1783  if (path[0]) {
1784  strcpy(buf, path);
1785  std::snprintf(path, hoc_object_pathname_bufsize, "%s%s.%s", name, indx, buf);
1786  } else {
1787  std::snprintf(path, hoc_object_pathname_bufsize, "%s%s", name, indx);
1788  }
1789 }
1790 
1791 int objectpath(Object* ob, Object* oblook, char* path, int depth) {
1792  /* recursively build the pathname to the object */
1793  Symbol* s;
1794  Symlist* sl;
1795  int total, i;
1796  Objectdata* od;
1797  Object** obp;
1798 
1799  if (ob == oblook) {
1800  return 1;
1801  }
1802  if (oblook) {
1803  if (depth++ > 5) {
1804  hoc_warning("objectpath depth > 4 for", oblook->ctemplate->sym->name);
1805  return 0;
1806  }
1807  if (oblook->ctemplate->constructor) {
1808  return ivoc_list_look(ob, oblook, path, depth);
1809  } else {
1810  od = oblook->u.dataspace;
1811  sl = oblook->ctemplate->symtable;
1812  }
1813  } else {
1814  od = hoc_top_level_data;
1815  sl = hoc_top_level_symlist;
1816  }
1817  if (sl)
1818  for (s = sl->first; s; s = s->next) {
1819  if (s->type == OBJECTVAR && s->cpublic != 2) {
1820  total = hoc_total_array_data(s, od);
1821  for (i = 0; i < total; i++) {
1822  obp = od[s->u.oboff].pobj + i;
1823  if (*obp && *obp != oblook && objectpath(ob, *obp, path, depth)) {
1824  pathprepend(path, s->name, hoc_araystr(s, i, od));
1825  return 1;
1826  }
1827  }
1828  }
1829  }
1830  return 0;
1831 }
1832 
1834  static char path[hoc_object_pathname_bufsize];
1835  path[0] = '\0';
1836  if (objectpath(ob, nullptr, path, 0)) {
1837  return path;
1838  } else {
1839 #if 0
1840  hoc_warning("Couldn't find a pathname to the object pointer",
1841  ob->ctemplate->sym->name);
1842  return (char*)0;
1843 #else
1844  return hoc_object_name(ob);
1845 #endif
1846  }
1847 }
1848 
1849 void hoc_obj_ref(Object* obj) {
1850  if (obj) {
1851  ++obj->refcount;
1852  }
1853 }
1854 
1855 void hoc_dec_refcount(Object** pobj) {
1856  Object* obj;
1857 
1858  obj = *pobj;
1859  if (obj == (Object*) 0) {
1860  return;
1861  }
1862  *pobj = (Object*) 0;
1863  assert(obj->refcount > 0);
1864  hoc_obj_unref(obj);
1865 }
1866 
1867 namespace {
1868 struct helper_in_case_dtor_throws {
1869  helper_in_case_dtor_throws(Object* obj)
1870  : m_obj{obj} {}
1871  ~helper_in_case_dtor_throws() {
1872  if (--m_obj->ctemplate->count <= 0) {
1873  m_obj->ctemplate->index = 0;
1874  }
1875  m_obj->ctemplate = nullptr;
1876  /* for testing purposes we don't free the object in order
1877  to make sure no object variable ever uses a freed object */
1878  hoc_free_object(m_obj);
1879  }
1880 
1881  private:
1882  Object* m_obj;
1883 };
1884 } // namespace
1885 
1886 void hoc_obj_unref(Object* obj) {
1887  Object* obsav;
1888 
1889  if (!obj) {
1890  return;
1891  }
1892 #if 0
1893 printf("unreffing %s with refcount %d\n", hoc_object_name(obj), obj->refcount);
1894 #endif
1895  --obj->refcount;
1896  if (obj->ctemplate->unref) {
1897  int i = obj->refcount;
1898  hoc_pushx((double) i);
1899  ++obj->unref_recurse_cnt;
1900  hoc_call_ob_proc(obj, obj->ctemplate->unref, 1);
1901  --obj->unref_recurse_cnt;
1902  }
1903  if (obj->refcount <= 0 && obj->unref_recurse_cnt == 0) {
1904  if (obj->aliases) {
1905  ivoc_free_alias(obj);
1906  }
1907  if (obj->observers) {
1908  hoc_obj_disconnect(obj);
1909  }
1910  hoc_l_delete(obj->itm_me);
1911  if (obj->ctemplate->observers) {
1912  hoc_template_notify(obj, 0);
1913  }
1914  // make sure that dereffing happens even if the destructor throws
1915  helper_in_case_dtor_throws _{obj};
1916  if (obj->ctemplate->sym->subtype & (CPLUSOBJECT | JAVAOBJECT)) {
1917  if (auto* const tp = obj->u.this_pointer; tp) {
1919  [obj]() {
1920  std::string rval{hoc_object_name(obj)};
1921  rval.append(" destructor");
1922  return rval;
1923  },
1924  obj->ctemplate->destructor,
1925  tp);
1926  }
1927  } else {
1928  obsav = hoc_thisobject;
1929  hoc_thisobject = obj;
1930  free_objectdata(obj->u.dataspace, obj->ctemplate);
1931  obj->u.dataspace = (Objectdata*) 0;
1932  hoc_thisobject = obsav;
1933  }
1934  }
1935 }
1936 
1937 static void free_objectdata(Objectdata* od, cTemplate* ctemplate) {
1938  Symbol* s;
1939  int i, total;
1940  Objectdata* psav;
1941  Object** objp;
1942 
1943  psav = hoc_objectdata;
1944  hoc_objectdata = od;
1945  if (ctemplate->symtable)
1946  for (s = ctemplate->symtable->first; s; s = s->next) {
1947  if (s->cpublic != 2) {
1948  switch (s->type) {
1949  case VAR:
1950  /*printf("free_objectdata %s\n", s->name);*/
1953  break;
1954  case STRING:
1957  break;
1958  case OBJECTVAR:
1959  objp = OPOBJ(s);
1960  if (strcmp("this", s->name) != 0) {
1961  total = hoc_total_array(s);
1962  for (i = 0; i < total; i++) {
1963  hoc_dec_refcount(objp + i);
1964  }
1965  }
1967  free(objp);
1968  break;
1969  case SECTION:
1970  total = hoc_total_array(s);
1971  for (i = 0; i < total; ++i) {
1972  sec_free(*(OPSECITM(s) + i));
1973  }
1974  free(OPSECITM(s));
1976  break;
1977  }
1978  }
1979  }
1980  if (ctemplate->is_point_) {
1981  void* v = od[ctemplate->dataspace_size - 1]._pvoid;
1982  if (v) {
1983  /* printf("Free point process\n");*/
1985  }
1986  }
1987  hoc_objectdata = psav;
1988  if (od) {
1989  free((char*) od);
1990  }
1991 }
1992 
1993 
1994 static void hoc_allobjects1(Symlist* sl, int nspace);
1995 static void hoc_allobjects2(Symbol* s, int nspace);
1996 
1997 void hoc_allobjects(void) {
1998  int n = 0;
1999  if (ifarg(1)) {
2000  if (hoc_is_str_arg(1)) {
2002  } else {
2003  Object** o = hoc_objgetarg(1);
2004  if (*o) {
2005  n = (*o)->refcount;
2006  }
2007  }
2008  } else {
2011  }
2012  hoc_ret();
2013  hoc_pushx((double) n);
2014 }
2015 
2016 void hoc_allobjects1(Symlist* sl, int nspace) {
2017  Symbol* s;
2018  cTemplate* t;
2019  Object* o;
2020  hoc_Item* q;
2021  int i;
2022  if (sl)
2023  for (s = sl->first; s; s = s->next) {
2024  if (s->type == TEMPLATE) {
2025  t = s->u.ctemplate;
2026  ITERATE(q, t->olist) {
2027  o = OBJ(q);
2028  for (i = 0; i < nspace; ++i) {
2029  Printf(" ");
2030  }
2031  Printf("%s with %d refs\n", hoc_object_name(o), o->refcount);
2032  }
2033  hoc_allobjects1(t->symtable, nspace + 1);
2034  }
2035  }
2036 }
2037 
2038 void hoc_allobjects2(Symbol* s, int nspace) {
2039  cTemplate* t;
2040  Object* o;
2041  hoc_Item* q;
2042  int i;
2043  if (s && s->type == TEMPLATE) {
2044  t = s->u.ctemplate;
2045  ITERATE(q, t->olist) {
2046  o = OBJ(q);
2047  for (i = 0; i < nspace; ++i) {
2048  Printf(" ");
2049  }
2050  Printf("%s with %d refs\n", hoc_object_name(o), o->refcount);
2051  }
2052  }
2053 }
2054 
2055 static void hoc_list_allobjref(Symlist*, Objectdata*, int);
2056 
2057 void hoc_allobjectvars(void) {
2059  hoc_ret();
2060  hoc_pushx(0.);
2061 }
2062 
2063 static void hoc_list_allobjref(Symlist* sl, Objectdata* data, int depth) {
2064  /* look in all object variables that point to
2065  objects and print them */
2066  Symbol* s;
2067  int total, i, id;
2068  Object** obp;
2069 
2070  if (sl)
2071  for (s = sl->first; s; s = s->next) {
2072  if (s->type == OBJECTVAR && s->cpublic != 2) {
2073  total = hoc_total_array_data(s, data);
2074  for (i = 0; i < total; i++) {
2075  obp = data[s->u.oboff].pobj + i;
2076  for (id = 0; id < depth; id++) {
2077  Printf(" ");
2078  }
2079  if (*obp) {
2080  Printf("obp %s[%d] -> %s with %d refs.\n",
2081  s->name,
2082  i,
2083  hoc_object_name(*obp),
2084  (*obp)->refcount);
2085  } else {
2086  Printf("obp %s[%d] -> NULL\n", s->name, i);
2087  }
2088  if (*obp && !(*obp)->recurse && s->subtype != CPLUSOBJECT &&
2089  (*obp)->u.dataspace != data /* not this */
2090  ) {
2091  /* descend to look for more */
2092  (*obp)->recurse = 1;
2093  hoc_list_allobjref((*obp)->ctemplate->symtable,
2094  (*obp)->u.dataspace,
2095  depth + 1);
2096  (*obp)->recurse = 0;
2097  }
2098  }
2099  }
2100  }
2101 }
2102 
2103 void check_obj_type(Object* obj, const char* type_name) {
2104  char buf[100];
2105  if (!obj || strcmp(obj->ctemplate->sym->name, type_name) != 0) {
2106  if (obj) {
2107  Sprintf(buf, "object type is %s instead of", obj->ctemplate->sym->name);
2108  } else {
2109  Sprintf(buf, "object type is nullptr instead of");
2110  }
2111  hoc_execerror(buf, type_name);
2112  }
2113 }
2114 
2115 int is_obj_type(Object* obj, const char* type_name) {
2116  if (obj && strcmp(obj->ctemplate->sym->name, type_name) == 0) {
2117  return 1;
2118  } else {
2119  return 0;
2120  }
2121 }
2122 
2123 
2125  // The PyObject* reference is not incremented. Use only as last resort
2128  }
2129  return nullptr;
2130 }
2131 
2132 // Helper functions for object arithmetic operations
2133 
2134 // Helper for object-object binary operations
2135 static void hoc_object_binary_op_helper(const char* method_name) {
2136  Object** obj2_ptr = hoc_objpop(); // Second operand
2137  Object** obj1_ptr = hoc_objpop(); // First operand (the one that has the method)
2138 
2139  Object* obj1 = *obj1_ptr;
2140  Object* obj2 = *obj2_ptr;
2141 
2142  if (!obj1) {
2143  hoc_execerror("Object arithmetic: first operand is null", nullptr);
2144  }
2145 
2146  // Try Python first if available
2147  if (nrnpy_call_obj_method && nrnpy_call_obj_method(obj1, method_name, obj2) != 0) {
2148  // Python handled the operation, result is on the stack
2149  hoc_tobj_unref(obj1_ptr);
2150  hoc_tobj_unref(obj2_ptr);
2151  return;
2152  }
2153 
2154  // Look up the method
2155  Symbol* method_sym = nrn_method_symbol(obj1, method_name);
2156  if (!method_sym) {
2157  hoc_execerror_fmt("Object arithmetic: method '{}' not found in object '{}'",
2158  method_name,
2159  obj1->ctemplate->sym->name);
2160  }
2161 
2162  // Call the HOC method: obj1.method(obj2)
2163  hoc_pushobj(obj2_ptr);
2164  nrn_method_call(obj1, method_sym, 1);
2165 
2166  // Clean up temporary object references
2167  hoc_tobj_unref(obj1_ptr);
2168  hoc_tobj_unref(obj2_ptr);
2169 }
2170 
2171 // Helper for object-number binary operations (object op number)
2172 static void hoc_object_number_binary_op_helper(const char* method_name) {
2173  double d = hoc_xpop(); // Second operand (number)
2174  Object** obj_ptr = hoc_objpop(); // First operand (object)
2175 
2176  Object* obj = *obj_ptr;
2177  if (!obj) {
2178  hoc_execerror("Object arithmetic: object operand is null", nullptr);
2179  }
2180 
2181  // Try Python first if available
2182  if (nrnpy_call_obj_method_double && nrnpy_call_obj_method_double(obj, method_name, d) != 0) {
2183  // Python handled the operation, result is on the stack
2184  hoc_tobj_unref(obj_ptr);
2185  return;
2186  }
2187 
2188  Symbol* method_sym = nrn_method_symbol(obj, method_name);
2189  if (!method_sym) {
2190  hoc_execerror_fmt("Object arithmetic: method '{}' not found in object '{}'",
2191  method_name,
2192  obj->ctemplate->sym->name);
2193  }
2194 
2195  // Push the number as argument for the method call
2196  hoc_pushx(d);
2197 
2198  // Call the method: obj.method(number)
2199  nrn_method_call(obj, method_sym, 1);
2200  hoc_tobj_unref(obj_ptr);
2201 }
2202 
2203 // Helper for number-object binary operations (number op object)
2204 // This uses the reverse magic method (e.g., __radd__ for addition)
2205 static void hoc_number_object_binary_op_helper(const char* method_name) {
2206  Object** obj_ptr = hoc_objpop(); // Second operand (object)
2207  double d = hoc_xpop(); // First operand (number)
2208 
2209  Object* obj = *obj_ptr;
2210  if (!obj) {
2211  hoc_execerror("Object arithmetic: object operand is null", nullptr);
2212  }
2213 
2214  // Try Python first if available
2215  if (nrnpy_call_obj_method_double && nrnpy_call_obj_method_double(obj, method_name, d) != 0) {
2216  // Python handled the operation, result is on the stack
2217  hoc_tobj_unref(obj_ptr);
2218  return;
2219  }
2220 
2221  Symbol* method_sym = nrn_method_symbol(obj, method_name);
2222  if (!method_sym) {
2223  hoc_execerror_fmt("Object arithmetic: method '{}' not found in object '{}'",
2224  method_name,
2225  obj->ctemplate->sym->name);
2226  }
2227 
2228  // Push the number as argument for the method call
2229  hoc_pushx(d);
2230 
2231  // Call the method: obj.method(number)
2232  nrn_method_call(obj, method_sym, 1);
2233  hoc_tobj_unref(obj_ptr);
2234 }
2235 
2236 // Object arithmetic functions that call HOC object methods
2238  hoc_object_binary_op_helper("__add__");
2239 }
2240 
2242  hoc_object_binary_op_helper("__sub__");
2243 }
2244 
2246  hoc_object_binary_op_helper("__mul__");
2247 }
2248 
2250  hoc_object_binary_op_helper("__div__");
2251 }
2252 
2254  hoc_object_binary_op_helper("__pow__");
2255 }
2256 
2257 // Helper for comparison operations
2258 // Handles common setup, null checks, and Python attempts
2259 // Returns true if the operation was handled (caller should return)
2260 // Returns false if caller needs to handle HOC method lookup
2261 static bool hoc_object_comparison_setup(Object**& obj1_ptr,
2262  Object**& obj2_ptr,
2263  Object*& obj1,
2264  Object*& obj2,
2265  const char* method_name,
2266  bool is_equality) {
2267  obj2_ptr = hoc_objpop(); // Second operand
2268  obj1_ptr = hoc_objpop(); // First operand
2269 
2270  obj1 = *obj1_ptr;
2271  obj2 = *obj2_ptr;
2272 
2273  // Handle null object cases with pointer comparison fallback
2274  if (!obj1 || !obj2) {
2275  double result = is_equality ? ((*obj1_ptr == *obj2_ptr) ? 1.0 : 0.0)
2276  : ((*obj1_ptr != *obj2_ptr) ? 1.0 : 0.0);
2277  hoc_tobj_unref(obj1_ptr);
2278  hoc_tobj_unref(obj2_ptr);
2279  hoc_pushx(result);
2280  return true; // Handled
2281  }
2282 
2283  // Try Python first if available
2284  if (nrnpy_call_obj_method && nrnpy_call_obj_method(obj1, method_name, obj2) != 0) {
2285  // Python handled the operation, result is on the stack
2286  hoc_tobj_unref(obj1_ptr);
2287  hoc_tobj_unref(obj2_ptr);
2288  return true; // Handled
2289  }
2290 
2291  return false; // Not handled, caller should proceed with HOC method lookup
2292 }
2293 
2294 // Helper to call a comparison method and cleanup
2295 static void hoc_object_comparison_call(Object** obj1_ptr,
2296  Object** obj2_ptr,
2297  Object* obj1,
2298  Symbol* method_sym) {
2299  hoc_pushobj(obj2_ptr);
2300  nrn_method_call(obj1, method_sym, 1);
2301  hoc_tobj_unref(obj1_ptr);
2302  hoc_tobj_unref(obj2_ptr);
2303 }
2304 
2305 // Helper for pointer comparison fallback
2306 static void hoc_object_comparison_fallback(Object** obj1_ptr, Object** obj2_ptr, bool is_equality) {
2307  double result = is_equality ? ((*obj1_ptr == *obj2_ptr) ? 1.0 : 0.0)
2308  : ((*obj1_ptr != *obj2_ptr) ? 1.0 : 0.0);
2309  hoc_tobj_unref(obj1_ptr);
2310  hoc_tobj_unref(obj2_ptr);
2311  hoc_pushx(result);
2312 }
2313 
2315  Object** obj1_ptr;
2316  Object** obj2_ptr;
2317  Object* obj1;
2318  Object* obj2;
2319 
2320  if (hoc_object_comparison_setup(obj1_ptr, obj2_ptr, obj1, obj2, "__eq__", true)) {
2321  return; // Already handled by setup (Python or null case)
2322  }
2323 
2324  // Look up the __eq__ method
2325  Symbol* method_sym = nrn_method_symbol(obj1, "__eq__");
2326  if (!method_sym) {
2327  // No __eq__ method found, fall back to pointer equality
2328  hoc_object_comparison_fallback(obj1_ptr, obj2_ptr, true);
2329  return;
2330  }
2331 
2332  // Call the method and cleanup
2333  hoc_object_comparison_call(obj1_ptr, obj2_ptr, obj1, method_sym);
2334 }
2335 
2337  Object** obj1_ptr;
2338  Object** obj2_ptr;
2339  Object* obj1;
2340  Object* obj2;
2341 
2342  if (hoc_object_comparison_setup(obj1_ptr, obj2_ptr, obj1, obj2, "__ne__", false)) {
2343  return; // Already handled by setup (Python or null case)
2344  }
2345 
2346  // Look up the __ne__ method first
2347  Symbol* method_sym = nrn_method_symbol(obj1, "__ne__");
2348  if (method_sym) {
2349  hoc_object_comparison_call(obj1_ptr, obj2_ptr, obj1, method_sym);
2350  return;
2351  }
2352 
2353  // No __ne__ method, try __eq__ method and negate result
2354  method_sym = nrn_method_symbol(obj1, "__eq__");
2355  if (method_sym) {
2356  hoc_pushobj(obj2_ptr);
2357  nrn_method_call(obj1, method_sym, 1);
2358  // Negate the result
2359  double eq_result = hoc_xpop();
2360  hoc_tobj_unref(obj1_ptr);
2361  hoc_tobj_unref(obj2_ptr);
2362  hoc_pushx(eq_result ? 0.0 : 1.0);
2363  return;
2364  }
2365 
2366  // No magic methods found, fall back to pointer inequality
2367  hoc_object_comparison_fallback(obj1_ptr, obj2_ptr, false);
2368 }
2369 
2370 // Mixed-type arithmetic functions (object with number)
2373 }
2374 
2377 }
2378 
2381 }
2382 
2385 }
2386 
2389 }
2390 
2393 }
2394 
2397 }
2398 
2401 }
2402 
2405 }
2406 
2409 }
#define STRING
Definition: bbslsrv.cpp:9
void nrn_pushsec(Section *sec)
Definition: cabcode.cpp:130
double cable_prop_eval(Symbol *sym)
Definition: cabcode.cpp:1447
void cable_prop_assign(Symbol *sym, double *pd, int op)
Definition: cabcode.cpp:1512
void nrn_rangeconst(Section *sec, Symbol *s, neuron::container::data_handle< double > pd, int op)
Definition: cabcode.cpp:935
int node_index(Section *sec, double x)
returns nearest index to x
Definition: cabcode.cpp:1406
void new_sections(Object *ob, Symbol *sym, Item **pitm, int size)
Definition: cabcode.cpp:304
Prop * nrn_mechanism_check(int type, Section *sec, int inode)
returns prop given mech type, section, and inode error if mech not at this position
Definition: cabcode.cpp:1050
neuron::container::data_handle< double > nrn_rangepointer(Section *sec, Symbol *s, double d)
Definition: cabcode.cpp:1274
void ob_sec_access_push(hoc_Item *qsec)
Definition: cabcode.cpp:827
#define symlist
Definition: cabcode.cpp:49
double * cable_prop_eval_pointer(Symbol *sym)
Definition: cabcode.cpp:1461
void *(Object *) ctor_f
Definition: classreg.h:5
void(void *) dtor_f
Definition: classreg.h:6
Symbol * hoc_table_lookup(const char *, Symlist *)
Definition: symbol.cpp:48
char * gargstr(int narg)
Definition: code2.cpp:227
Inst * hoc_Code(Pfrv f)
Definition: code.cpp:2605
Inst * hoc_codei(int f)
Definition: code.cpp:2610
void hoc_iterator_object(Symbol *sym, int argcount, Inst *beginpc, Inst *endpc, Object *ob)
Definition: code.cpp:1102
#define v
Definition: md1redef.h:11
#define sec
Definition: md1redef.h:20
#define id
Definition: md1redef.h:41
#define i
Definition: md1redef.h:19
static int indx
Definition: deriv.cpp:289
double chkarg(int, double low, double high)
Definition: code2.cpp:626
void hoc_execerror_fmt(const char *fmt, T &&... args)
Definition: formatting.hpp:8
static void destruct(void *v)
Definition: grglyph.cpp:207
static void * cons(Object *o)
Definition: grglyph.cpp:200
#define NMODLRANDOM
Definition: modl.h:226
char buf[512]
Definition: init.cpp:13
char * hoc_object_pathname(Object *ob)
Definition: hoc_oop.cpp:1833
double hoc_xpop()
Definition: code.cpp:903
void hoc_push_frame(Symbol *sp, int narg)
Definition: code.cpp:1376
Object * hoc_name2obj(const char *name, int index)
Definition: hoc_oop.cpp:864
void hoc_obj_set(int i, Object *obj)
Definition: hoc_oop.cpp:71
void hoc_push_ndim(int d)
Definition: code.cpp:855
void hoc_construct_point(Object *, int)
Definition: hocmech.cpp:68
int hoc_obj_run(const char *cmd, Object *ob)
Brief explanation of hoc_obj_run.
Definition: hoc_oop.cpp:320
void * nrn_opaque_obj2pyobj(Object *ho)
Definition: hoc_oop.cpp:2124
void hoc_pushstr(char **d)
Definition: code.cpp:800
Object * nrn_nmodlrandom_wrap(Prop *prop, Symbol *sym)
double hoc_call_func(Symbol *s, int narg)
Definition: code.cpp:1477
int hoc_argindex(void)
Definition: code.cpp:1647
int ivoc_list_look(Object *ob, Object *oblook, char *path, int)
Definition: oclist.cpp:462
void hoc_new_object_asgn(Object **obp, Symbol *st, void *v)
Definition: hoc_oop.cpp:483
size_t hoc_total_array_data(const Symbol *s, Objectdata *obd)
Definition: hoc_oop.cpp:100
void hoc_ret()
int hoc_arayinfo_install(Symbol *sp, int nsub)
Definition: hoc.cpp:528
Object ** hoc_temp_objvar(Symbol *symtemp, void *v)
Definition: hoc_oop.cpp:489
void hoc_template_notify(Object *ob, int message)
Definition: ocobserv.cpp:37
void hoc_pushpx(double *d)
Definition: code.cpp:834
int hoc_inside_stacktype(int i)
Definition: code.cpp:898
void hoc_pushobj(Object **d)
Definition: code.cpp:784
int hoc_errno_check(void)
Definition: math.cpp:257
void hoc_call_ob_proc(Object *ob, Symbol *sym, int narg)
Definition: hoc_oop.cpp:653
Object * hoc_obj_get(int i)
Definition: hoc_oop.cpp:62
void hoc_freearay(Symbol *sp)
Definition: hoc.cpp:567
Symbol * hoc_install(const char *, int, double, Symlist **)
Definition: symbol.cpp:77
void hoc_free_object(Object *)
Definition: symbol.cpp:283
int hoc_is_str_arg(int narg)
Definition: code.cpp:872
int hoc_stacktype()
Definition: code.cpp:774
void hoc_free_pstring(char **)
Definition: symbol.cpp:294
double * hoc_pxpop()
Definition: code.cpp:922
bool hoc_stack_type_is_ndim()
Definition: code.cpp:314
void hoc_oop_initaftererror(void)
Definition: hoc_oop.cpp:417
Object * nrn_pntproc_nmodlrandom_wrap(void *v, Symbol *sym)
Objectdata * hoc_objectdata
Definition: hoc_oop.cpp:127
void hoc_assign_str(char **cpp, const char *buf)
Definition: code.cpp:2380
double hoc_opasgn(int op, double dest, double src)
Definition: code.cpp:1674
double hoc_call_objfunc(Symbol *s, int narg, Object *ob)
Definition: hoc_oop.cpp:389
Object * hoc_new_object(Symbol *symtemp, void *v)
Definition: hoc_oop.cpp:455
int hoc_ipop()
Definition: code.cpp:967
int is_obj_type(Object *obj, const char *type_name)
Definition: hoc_oop.cpp:2115
int hoc_oc(const char *buf)
Definition: hoc.cpp:1314
void check_obj_type(Object *obj, const char *type_name)
Definition: hoc_oop.cpp:2103
void hoc_obj_disconnect(Object *ob)
Definition: ocobserv.cpp:5
void hoc_pop_defer()
Definition: code.cpp:318
int hoc_pop_ndim()
Definition: code.cpp:933
void hoc_obj_ref(Object *obj)
Definition: hoc_oop.cpp:1849
char * hoc_object_name(Object *ob)
Definition: hoc_oop.cpp:78
void ivoc_free_alias(Object *ob)
Definition: strfun.cpp:149
void hoc_dec_refcount(Object **pobj)
Definition: hoc_oop.cpp:1855
void hoc_free_val_array(double *, std::size_t)
void hoc_install_object_data_index(Symbol *sp)
Definition: hoc_oop.cpp:302
Symbol * hoc_spop()
Definition: code.cpp:928
size_t hoc_total_array(Symbol *s)
Definition: hoc_oop.cpp:88
Symbol * hoc_lookup(const char *)
Definition: symbol.cpp:59
void hoc_free_arrayinfo(Arrayinfo *a)
Definition: hoc.cpp:579
void hoc_pop_frame(void)
Definition: code.cpp:1387
void hoc_nopop()
Definition: code.cpp:972
void hoc_obj_unref(Object *obj)
Definition: hoc_oop.cpp:1886
Symbol * ivoc_alias_lookup(const char *name, Object *ob)
Definition: strfun.cpp:140
void hoc_free_allobjects(cTemplate *ctemplate, Symlist *sl, Objectdata *data)
Definition: hoc_oop.cpp:1737
void hoc_pushi(int d)
Definition: code.cpp:846
char * hoc_araystr(Symbol *sym, int index, Objectdata *obd)
Definition: code.cpp:2398
void hoc_push_object(Object *d)
Definition: code.cpp:793
void hoc_push(neuron::container::generic_data_handle handle)
Definition: code.cpp:850
HocStr * hocstr_create(size_t size)
Definition: hoc.cpp:828
int hoc_main1_inited_
Definition: hoc.cpp:780
void hocstr_delete(HocStr *hs)
Definition: hoc.cpp:842
void hoc_number_mul_object()
Definition: hoc_oop.cpp:2391
void hoc_object_ne()
Definition: hoc_oop.cpp:2336
#define pushtemplatesym(arg)
Definition: hoc_oop.cpp:211
void oc_save_hoc_oop(Object **a1, Objectdata **a2, int *a4, Symlist **a5)
Definition: hoc_oop.cpp:428
Objectdata * hoc_objectdata_restore(Objectdata *obdsav)
Definition: hoc_oop.cpp:147
void hoc_object_pow()
Definition: hoc_oop.cpp:2253
static void call_constructor(Object *, Symbol *, int)
Definition: hoc_oop.cpp:614
void hoc_objectvar(void)
Definition: hoc_oop.cpp:797
#define pushtemplatesymlist(arg)
Definition: hoc_oop.cpp:214
void hoc_allobjects(void)
Definition: hoc_oop.cpp:1997
static bool hoc_object_comparison_setup(Object **&obj1_ptr, Object **&obj2_ptr, Object *&obj1, Object *&obj2, const char *method_name, bool is_equality)
Definition: hoc_oop.cpp:2261
#define pushtemplatei(arg)
Definition: hoc_oop.cpp:217
#define OBJ_STACK_SIZE
Definition: hoc_oop.cpp:237
static Object * obj_stack_[OBJ_STACK_SIZE+1]
Definition: hoc_oop.cpp:238
static void hoc_number_object_binary_op_helper(const char *method_name)
Definition: hoc_oop.cpp:2205
static Templatedatum * poptemplate(void)
Definition: hoc_oop.cpp:204
int(* nrnpy_call_obj_method_double)(Object *obj, const char *method, double value)
Definition: hoc_oop.cpp:46
static Symbol * hoc_obj_
Definition: hoc_oop.cpp:43
static int connect_obsec_
Definition: hoc_oop.cpp:31
void hoc_allobjectvars(void)
Definition: hoc_oop.cpp:2057
static Templatedatum templatestack[NTEMPLATESTACK]
Definition: hoc_oop.cpp:201
void hoc_object_pow_number()
Definition: hoc_oop.cpp:2403
void hoc_install_hoc_obj(void)
Definition: hoc_oop.cpp:49
static void call_ob_iter(Object *ob, Symbol *sym, int narg)
Definition: hoc_oop.cpp:726
Symbol * hoc_decl(Symbol *s)
Definition: hoc_oop.cpp:1646
int hoc_in_template
Definition: hoc_oop.cpp:130
Objectdata * hoc_objectdata_save(void)
Definition: hoc_oop.cpp:137
void hoc_external_var(Symbol *s)
Definition: hoc_oop.cpp:1673
void hoc_number_div_object()
Definition: hoc_oop.cpp:2399
Symbol * nrnpy_pyobj_sym_
Definition: hoc_oop.cpp:26
void hoc_newobj(void)
Definition: hoc_oop.cpp:591
static int template_id
Definition: hoc_oop.cpp:1513
void hoc_asgn_obj_to_str(void)
Definition: hoc_oop.cpp:1397
int hoc_max_builtin_class_id
Definition: hoc_oop.cpp:41
void hoc_object_div()
Definition: hoc_oop.cpp:2249
static void hoc_object_comparison_fallback(Object **obj1_ptr, Object **obj2_ptr, bool is_equality)
Definition: hoc_oop.cpp:2306
Symbol * hoc_which_template(Symbol *s)
Definition: hoc_oop.cpp:1497
void hoc_constobject(void)
Definition: hoc_oop.cpp:845
#define objectpath
Definition: hoc_oop.cpp:1777
void hoc_number_sub_object()
Definition: hoc_oop.cpp:2383
static void free_objectdata(Objectdata *, cTemplate *)
Definition: hoc_oop.cpp:1937
void hoc_obvar_declare(Symbol *sym, int type, int pmes)
Definition: hoc_oop.cpp:156
void hoc_object_mul()
Definition: hoc_oop.cpp:2245
void hoc_exec_cmd(void)
Definition: hoc_oop.cpp:354
std::vector< const char * > py_exposed_classes
Definition: hoc_oop.cpp:38
int hoc_print_first_instance
Definition: hoc_oop.cpp:40
void class2oc_base(const char *name, ctor_f *cons, dtor_f *destruct, Member_func *m, Member_ret_obj_func *mobjret, Member_ret_str_func *strret)
Definition: hoc_oop.cpp:1588
void hoc_number_add_object()
Definition: hoc_oop.cpp:2375
struct Section * nrn_sec_pop()
Definition: cabcode.cpp:753
void hoc_object_id(void)
Definition: hoc_oop.cpp:889
void hoc_object_add()
Definition: hoc_oop.cpp:2237
static void hoc_list_allobjref(Symlist *, Objectdata *, int)
Definition: hoc_oop.cpp:2063
void hoc_object_add_number()
Definition: hoc_oop.cpp:2371
void hoc_cmp_otype(void)
Definition: hoc_oop.cpp:789
#define pushtemplateo(arg)
Definition: hoc_oop.cpp:223
void hoc_ob_check(int type)
Definition: hoc_oop.cpp:1711
void hoc_endtemplate(Symbol *t)
Definition: hoc_oop.cpp:1553
void hoc_object_sub_number()
Definition: hoc_oop.cpp:2379
Object * hoc_newobj1(Symbol *sym, int narg)
Definition: hoc_oop.cpp:502
static Templatedatum * templatestackp
Definition: hoc_oop.cpp:202
static void hoc_object_binary_op_helper(const char *method_name)
Definition: hoc_oop.cpp:2135
int(* nrnpy_call_obj_method)(Object *obj, const char *method, Object *obj2)
Definition: hoc_oop.cpp:45
void hoc_object_eq()
Definition: hoc_oop.cpp:2314
void hoc_object_push(void)
Definition: hoc_oop.cpp:241
void hoc_newobj_ret(void)
Definition: hoc_oop.cpp:587
void hoc_object_component()
Definition: hoc_oop.cpp:982
static void hoc_allobjects2(Symbol *s, int nspace)
Definition: hoc_oop.cpp:2038
static void hoc_object_number_binary_op_helper(const char *method_name)
Definition: hoc_oop.cpp:2172
void hoc_object_eval(void)
Definition: hoc_oop.cpp:1346
void hoc_object_pushed(void)
Definition: hoc_oop.cpp:263
static int icntobjectdata
Definition: hoc_oop.cpp:125
void hoc_object_sub()
Definition: hoc_oop.cpp:2241
int section_object_seen
Definition: hoc_oop.cpp:29
Object * nrn_get_gui_redirect_obj()
Definition: hoc_oop.cpp:649
static void chktemplate(void)
Definition: hoc_oop.cpp:227
void hoc_begintemplate(Symbol *t1)
Definition: hoc_oop.cpp:1515
#define NTEMPLATESTACK
Definition: hoc_oop.cpp:200
void class2oc(const char *name, ctor_f *cons, dtor_f *destruct, Member_func *m, Member_ret_obj_func *mobjret, Member_ret_str_func *strret)
Definition: hoc_oop.cpp:1636
#define PUBLIC_TYPE
Definition: hoc_oop.cpp:33
static int obj_stack_loc
Definition: hoc_oop.cpp:239
void oc_restore_hoc_oop(Object **a1, Objectdata **a2, int *a4, Symlist **a5)
Definition: hoc_oop.cpp:444
void hoc_object_pop(void)
Definition: hoc_oop.cpp:271
void hoc_objvardecl(void)
Definition: hoc_oop.cpp:756
void hoc_ob_pointer(void)
Definition: hoc_oop.cpp:1373
static void range_suffix(Symbol *sym, int nindex, int narg)
Definition: hoc_oop.cpp:906
void hoc_add_publiclist(Symbol *s)
Definition: hoc_oop.cpp:1661
void connect_obsec_syntax(void)
Definition: hoc_oop.cpp:974
void hoc_object_div_number()
Definition: hoc_oop.cpp:2395
constexpr std::size_t hoc_object_pathname_bufsize
Definition: hoc_oop.cpp:1780
static void hoc_allobjects1(Symlist *sl, int nspace)
Definition: hoc_oop.cpp:2016
static int icnttoplevel
Definition: hoc_oop.cpp:129
void hoc_object_asgn()
Definition: hoc_oop.cpp:1404
void hoc_number_pow_object()
Definition: hoc_oop.cpp:2407
Objectdata * hoc_top_level_data
Definition: hoc_oop.cpp:128
void hoc_newobj_arg(void)
Definition: hoc_oop.cpp:576
#define pathprepend
Definition: hoc_oop.cpp:1778
#define pushtemplateodata(arg)
Definition: hoc_oop.cpp:220
void hoc_push_current_object(void)
Definition: hoc_oop.cpp:133
void hoc_objectarg(void)
Definition: hoc_oop.cpp:830
void hoc_known_type(void)
Definition: hoc_oop.cpp:793
void hoc_object_mul_number()
Definition: hoc_oop.cpp:2387
int hoc_resize_toplevel(int more)
Definition: hoc_oop.cpp:290
static Object * gui_redirect_obj_
Definition: hoc_oop.cpp:648
#define EXTERNAL_TYPE
Definition: hoc_oop.cpp:34
static void hoc_object_comparison_call(Object **obj1_ptr, Object **obj2_ptr, Object *obj1, Symbol *method_sym)
Definition: hoc_oop.cpp:2295
Object * hoc_thisobject
Definition: hoc_oop.cpp:126
#define assert(ex)
Definition: hocassrt.h:24
#define OBJECTALIAS
Definition: hocdec.h:94
#define USERPROPERTY
Definition: hocdec.h:85
#define JAVAOBJECT
Definition: hocdec.h:92
#define OBJECTTMP
Definition: hocdec.h:88
#define OPOBJ(sym)
Definition: hocdec.h:236
#define OPARINFO(sym)
Definition: hocdec.h:239
#define CPLUSOBJECT
Definition: hocdec.h:91
#define OPSECITM(sym)
Definition: hocdec.h:237
bool is_array(const Symbol &sym)
Definition: hocdec.h:136
#define OPSTR(sym)
Definition: hocdec.h:235
#define OPVAL(sym)
Definition: hocdec.h:234
#define STOP
Definition: hocdec.h:57
#define VARALIAS
Definition: hocdec.h:95
#define OBJ(q)
Definition: hoclist.h:88
hoc_List * hoc_l_newlist()
hoc_Item * hoc_l_lappendobj(hoc_List *, struct Object *)
void hoc_l_delete(hoc_Item *)
int special_pnt_call(Object *ob, Symbol *sym, int narg)
Definition: hocmech.cpp:107
Object ** hoc_objgetarg(int)
Definition: code.cpp:1614
static int narg()
Definition: ivocvect.cpp:121
Symlist * hoc_top_level_symlist
Definition: code2.cpp:677
int hoc_araypt(Symbol *, int)
Definition: code.cpp:2457
void hoc_pushx(double)
Definition: code.cpp:779
#define ITERATE(itm, lst)
Definition: model.h:18
#define SYMBOL
Definition: model.h:91
#define RANGEOBJ
Definition: model.h:124
printf
Definition: extdef.h:5
const char * name
Definition: init.cpp:16
void move(Item *q1, Item *q2, Item *q3)
Definition: list.cpp:200
void hoc_execerror(const char *s1, const char *s2)
Definition: nrnoc_aux.cpp:39
void * erealloc(void *ptr, size_t size)
Definition: nrnoc_aux.cpp:94
void * ecalloc(size_t n, size_t size)
Definition: nrnoc_aux.cpp:85
static void * emalloc(size_t size)
Definition: mpispike.cpp:30
void hoc_warning(const char *s1, const char *s2)
Definition: nrnoc_aux.cpp:44
constexpr do_not_search_t do_not_search
Definition: data_handle.hpp:11
decltype(auto) invoke_method_that_may_throw(Callable message_prefix, Args &&... args)
Execute C++ code that may throw and propagate HOC information.
Definition: oc_ansi.h:76
impl_ptrs methods
Collection of pointers to functions with python-version-specific implementations.
Definition: nrnpy.cpp:21
int Sprintf(char(&buf)[N], const char *fmt, Args &&... args)
Type-safe sprintf replacement using snprintf with automatic buffer size deduction.
Definition: wrap_sprintf.h:28
if(ncell==0)
Definition: cellorder.cpp:785
void nrn_method_call(Object *obj, Symbol *method_sym, int narg)
Definition: neuronapi.cpp:352
Symbol * nrn_method_symbol(const Object *obj, char const *const name)
Definition: neuronapi.cpp:348
void sec_free(hoc_Item *)
Definition: solve.cpp:467
int const size_t const size_t n
Definition: nrngsl.h:10
#define FUNCTION(a, b)
Definition: nrngsl.h:5
size_t q
size_t p
s
Definition: multisend.cpp:521
void destroy_point_process(void *)
Definition: point.cpp:67
int ifarg(int)
Definition: code.cpp:1607
short index
Definition: cabvars.h:11
short type
Definition: cabvars.h:10
char ** hoc_strpop()
Definition: code.cpp:962
Object * hoc_obj_look_inside_stack(int)
Definition: code.cpp:885
void hoc_call()
Definition: code.cpp:1398
int nrn_inpython_
Definition: hoc.cpp:52
Object ** hoc_objpop()
Pop pointer to object pointer and return top elem from stack.
Definition: code.cpp:943
void hoc_pushs(Symbol *)
Definition: code.cpp:841
void hoc_tobj_unref(Object **)
Definition: code.cpp:160
static void * opaque_obj2pyobj(Object *ho)
Definition: nrnpy_p2h.cpp:54
FILE * hoc_fin
Definition: hoc.cpp:152
Symlist * hoc_symlist
Definition: symbol.cpp:34
int nrnmpi_myid_world
void hoc_execute(Inst *)
Definition: code.cpp:2648
static uint32_t value
Definition: scoprand.cpp:25
int hoc_returning
Definition: code.cpp:81
Section * nrn_sectionref_steer(Section *sec, Symbol *sym, int *pnindex)
Definition: secref.cpp:301
Symbol * nrn_sec_sym
Definition: secref.cpp:25
#define xpop
Definition: section.h:36
#define pc
Definition: section.h:37
Object ** hoc_temp_objptr(Object *)
Definition: code.cpp:151
Symbol * nrn_matrix_sym
Definition: matrix.cpp:15
void hoc_free_symspace(Symbol *)
Definition: symbol.cpp:166
Symlist * hoc_built_in_symlist
Definition: symbol.cpp:28
int nsub
Definition: hocdec.h:61
int refcount
Definition: hocdec.h:62
int sub[1]
Definition: hocdec.h:63
Definition: hocstr.h:6
size_t size
Definition: hocstr.h:8
char * buf
Definition: hocstr.h:7
const char * name
Definition: classreg.h:9
double(* member)(void *)
Definition: classreg.h:10
const char * name
Definition: classreg.h:14
struct Object **(* member)(void *)
Definition: classreg.h:15
const char * name
Definition: classreg.h:19
const char **(* member)(void *)
Definition: classreg.h:20
Definition: hocdec.h:173
hoc_Item * itm_me
Definition: hocdec.h:183
void * aliases
Definition: hocdec.h:181
void * this_pointer
Definition: hocdec.h:178
Objectdata * dataspace
Definition: hocdec.h:177
int index
Definition: hocdec.h:175
short unref_recurse_cnt
Definition: hocdec.h:187
void * observers
Definition: hocdec.h:185
int refcount
Definition: hocdec.h:174
cTemplate * ctemplate
Definition: hocdec.h:180
hoc_Item * secelm_
Definition: hocdec.h:184
union Object::@47 u
short recurse
Definition: hocdec.h:186
Inst defn
Definition: hocdec.h:67
Definition: section.h:231
int refcount
Definition: section.h:51
Definition: model.h:47
Proc * u_proc
Definition: hocdec.h:120
union Symbol::@28 u
short cpublic
Definition: hocdec.h:107
struct Symbol::@45::@46 rng
Object * object_
Definition: hocdec.h:113
short type
Definition: model.h:48
long subtype
Definition: model.h:49
Symbol * sym
Definition: hocdec.h:127
cTemplate * ctemplate
Definition: hocdec.h:126
char * name
Definition: model.h:61
double * pval
Definition: hocdec.h:112
int oboff
Definition: hocdec.h:111
Arrayinfo * arayinfo
Definition: hocdec.h:130
short defined_on_the_fly
Definition: hocdec.h:108
Definition: hocdec.h:75
Symbol * first
Definition: hocdec.h:76
Symbol * sym
Definition: hocdec.h:147
int dataspace_size
Definition: hocdec.h:149
Symbol * unref
Definition: hocdec.h:152
Symlist * symtable
Definition: hocdec.h:148
Symbol * init
Definition: hocdec.h:151
int id
Definition: hocdec.h:156
hoc_List * olist
Definition: hocdec.h:155
void * observers
Definition: hocdec.h:157
int count
Definition: hocdec.h:154
void(* destructor)(void *)
Definition: hocdec.h:159
void *(* constructor)(struct Object *)
Definition: hocdec.h:158
int is_point_
Definition: hocdec.h:150
int index
Definition: hocdec.h:153
void(* steer)(void *)
Definition: hocdec.h:160
Object * ob
Definition: hoc_oop.cpp:499
~guard_t()
Definition: hoc_oop.cpp:494
void(* hpoasgn)(Object *, int)
Definition: nrnpy.h:41
void *(* opaque_obj2pyobj)(Object *)
Definition: nrnpy.h:46
void(* py2n_component)(Object *, Symbol *, int, int)
Definition: nrnpy.h:52
Definition: hocdec.h:42
Pfrv pf
Definition: hocdec.h:43
int i
Definition: hocdec.h:54
Pfrs_vp pfs_vp
Definition: hocdec.h:50
Pfro_vp pfo_vp
Definition: hocdec.h:49
Symbol * sym
Definition: hocdec.h:52
Pfrd_vp pfd_vp
Definition: hocdec.h:48
Inst * in
Definition: hocdec.h:51
char ** ppstr
Definition: hocdec.h:165
void * _pvoid
Definition: hocdec.h:170
hoc_Item ** psecitm
Definition: hocdec.h:167
Arrayinfo * arayinfo
Definition: hocdec.h:169
double * pval
Definition: hocdec.h:164
Object ** pobj
Definition: hocdec.h:166
Objectdata * odata
Definition: hoc_oop.cpp:196
Symlist * symlist
Definition: hoc_oop.cpp:195
Symbol * sym
Definition: hoc_oop.cpp:194
Object * o
Definition: hoc_oop.cpp:197
int Fprintf(FILE *stream, const char *fmt, Args... args)
Definition: logger.hpp:8
int Printf(const char *fmt, Args... args)
Definition: logger.hpp:18