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