1 #include <../../nrnconf.h>
35 if (--bbs_poll_ == 0) { \
73 static std::vector<StackDatum>
stack{};
116 #define DEBUG_GARBAGE 1
117 #define TOBJ_POOL_SIZE 50
196 StackDatum& get_stack_entry_variant(std::size_t
i) {
201 template <
class... Ts>
202 struct overloaded: Ts... {
203 using Ts::operator()...;
205 template <
class... Ts>
206 overloaded(Ts...) -> overloaded<Ts...>;
208 template <
typename T>
209 [[noreturn]]
void report_type_mismatch(
StackDatum const& entry) {
211 [](
auto const& val) {
212 assert((!std::is_same_v<std::decay_t<decltype(val)>, T>) );
213 std::ostringstream oss;
214 oss <<
"bad stack access: expecting " <<
cxx_demangle(
typeid(T).
name()) <<
"; really "
216 if constexpr (!std::is_same_v<std::decay_t<decltype(val)>, std::nullptr_t>) {
228 oss <<
" -> " << sym->name;
232 [&oss](std::nullptr_t) { oss <<
" already unreffed on stack"; },
233 [](
auto const&) {}}(val);
237 throw std::logic_error(
"report_type_mismatch");
240 template <
typename T>
242 if (!std::holds_alternative<T>(entry)) {
243 report_type_mismatch<T>(entry);
247 template <
typename T>
249 check_type<T>(entry);
250 return std::get<T>(entry);
252 template <
typename T>
254 check_type<T>(entry);
255 return std::get<T>(entry);
260 template <
typename T>
262 return cast<T>(get_stack_entry_variant(
i));
269 bool stack_entry_is_tmpobject(
StackDatum const& entry) {
270 return std::holds_alternative<Object*>(entry);
272 bool stack_entry_is_tmpobject(std::size_t
i) {
273 return stack_entry_is_tmpobject(get_stack_entry_variant(
i));
277 if (stack_entry_is_tmpobject(entry)) {
278 auto* o = std::get<Object*>(entry);
285 int get_legacy_int_type(
StackDatum const& entry) {
286 if (std::holds_alternative<char**>(entry)) {
288 }
else if (std::holds_alternative<neuron::container::generic_data_handle>(entry)) {
290 }
else if (std::holds_alternative<double>(entry)) {
292 }
else if (std::holds_alternative<Object**>(entry)) {
294 }
else if (std::holds_alternative<Object*>(entry)) {
296 }
else if (std::holds_alternative<int>(entry)) {
298 }
else if (std::holds_alternative<Symbol*>(entry)) {
300 }
else if (std::holds_alternative<std::nullptr_t>(entry)) {
303 throw std::runtime_error(
"get_legacy_int_type");
311 return get_legacy_int_type(get_stack_entry_variant(0));
315 return std::holds_alternative<stack_ndim_datum>(get_stack_entry_variant(0));
340 auto& entry =
stack[stkindex];
341 if (stack_entry_is_tmpobject(entry)) {
354 for (
int i = f->
nargs - 1;
i >= 0; --
i) {
356 unref_if_tmpobject(*
s);
363 for (
Frame* f =
fp; f > ff; --f) {
365 if (sp->
type == MECHANISM) {
381 auto* ob = cast<Object*>(stkp[-
i]);
403 if (stack_entry_is_tmpobject(stkp)) {
408 }
else if (std::holds_alternative<std::nullptr_t>(stkp)) {
409 printf(
"OBJECTTMP at stack index %ld already unreffed\n",
index);
431 #define MAXINITFCNS 10
439 std::ostringstream oss;
440 oss <<
"interpreter stack: " <<
stack.size() <<
'\n';
448 oss <<
' ' <<
i <<
' ';
449 if constexpr (std::is_same_v<std::decay_t<decltype(
value)>, std::nullptr_t>) {
459 Printf(oss.str().c_str());
467 fprintf(stderr,
"increase definition for MAXINITFCNS\n");
477 fprintf(stderr,
"errno set %d times on last execution\n",
hoc_errno_count);
558 if (a3 >
stack.size()) {
559 hoc_execerror(
"oc_restore_code cannot summon stack entries from nowhere",
nullptr);
592 hoc_execerror(
"rinitcode cannot create stack entries from nowhere",
nullptr);
615 Inst *sprogbase, *sprogp, *spc, *sprog_parse_recover;
617 std::size_t sstack{}, sstackp{};
625 sstackp =
stack.size();
636 "Maybe you were in the middle of a direct command.");
645 hoc_execerror(
"incomplete statement parse not allowed\n",
nullptr);
656 if (sstackp >
stack.size()) {
657 hoc_execerror(
"hoc_ParseExec cannot summon entries from nowhere",
nullptr);
659 stack.resize(sstackp);
704 if (sstackp >
stack.size()) {
705 hoc_execerror(
"hoc_xopen_run cannot summon entries from nowhere",
nullptr);
707 stack.resize(sstackp);
713 #define HOC_TEMP_CHARPTR_SIZE 128
732 void pop_value() noexcept {
741 template <
typename T>
746 if (std::holds_alternative<T>(
stack.back())) {
751 report_type_mismatch<T>(
stack.back());
757 template <
typename T>
758 void push_value(T
value) {
760 hoc_execerror(
"Stack too deep.",
"Increase with -NSTACK stacksize option");
809 }
else if (
s->type == CSTRING) {
815 if (
s->cpublic == 2) {
861 return get_legacy_int_type(get_argument(
narg));
886 auto const& entry = get_stack_entry_variant(
i);
888 overloaded{[](
Object* o) {
return o; },
889 [](
Object** o) {
return *o; },
890 [](
auto const& val) ->
Object* {
891 throw std::runtime_error(
892 "hoc_obj_look_inside_stack expects Object* or Object** but found " +
899 return get_legacy_int_type(get_stack_entry_variant(
i));
904 return pop_value<double>();
910 container::generic_data_handle oc::detail::hoc_get_arg_helper<container::generic_data_handle>::impl(
912 return cast<container::generic_data_handle>(get_argument(
narg));
916 container::generic_data_handle oc::detail::hoc_pop_helper<container::generic_data_handle>::impl() {
917 return pop_value<neuron::container::generic_data_handle>();
924 return static_cast<double*
>(hoc_pop<neuron::container::data_handle<double>>());
929 return pop_value<Symbol*>();
934 return pop_value<stack_ndim_datum>().i;
944 if (stack_entry_is_tmpobject(0)) {
947 return pop_value<Object**>();
963 return pop_value<char**>();
968 return pop_value<int>();
973 auto const& top_entry = get_stack_entry_variant(0);
974 if (stack_entry_is_tmpobject(top_entry)) {
998 #define relative(pc) (pc + (pc)->i)
1021 if ((savepc + 2)->
i)
1032 double begin, end, *
pval = 0;
1040 switch (sym->
type) {
1092 Inst *stmtbegin, *stmtend;
1095 argcount = (
pc++)->
i;
1106 hoc_execerror(sym->
name,
"call nested too deeply, increase with -NFRAME framesize option");
1114 if (sym->
u.
u_proc->
nauto - i <= sym->u.u_proc->nobjauto) {
1115 push_value(
static_cast<Object*
>(
nullptr));
1179 hoc_execerror(
"return from within an iterator statement not allowed.",
1180 "Set a flag and use break.");
1197 double *
pval = 0, dx;
1200 switch (sym->
type) {
1225 pval = &(cast<double>(entry));
1240 for (;
i <= imax;
i++) {
1261 }
else if (
i < imax) {
1292 else if ((savepc + 1)->
i)
1314 Inst *inst, *newinst;
1325 *newinst++ = *inst++;
1340 for (
i = 5, f =
fp; f !=
frame && --
i; f = f - 1) {
1341 for (
j =
i;
j;
j--) {
1351 std::visit(overloaded{[](
double val) {
Fprintf(stderr,
"%g", val); },
1353 const char*
s = *pstr;
1354 if (strlen(
s) > 15) {
1355 Fprintf(stderr,
"\"%.10s...\"",
s);
1363 [](
auto const&) {
Fprintf(stderr,
"..."); }},
1365 if (++j <= f->nargs) {
1372 Fprintf(stderr,
"and others\n");
1379 hoc_execerror(sp->
name,
"call nested too deeply, increase with -NFRAME framesize option");
1404 hoc_execerror(sp->
name,
"call nested too deeply, increase with -NFRAME framesize option");
1413 if (sp->
type == FUN_BLTIN || sp->
type == OBJECTFUNC || sp->
type == STRINGFUNC) {
1427 if (sp->
u.
u_proc->
nauto - i <= sp->u.u_proc->nobjauto) {
1428 push_value(
static_cast<Object*
>(
nullptr));
1485 if (
s->type == BLTIN) {
1537 if (
fp->
sp->
type == HOCOBJFUNCTION)
1547 if (
fp->
sp->
type != HOCOBJFUNCTION)
1581 int iarg, itype = 0;
1584 hoc_execerror(
"argtype can only be called in a func or proc", 0);
1586 iarg = (int)
chkarg(1, -1000., 100000.);
1587 if (iarg > f->
nargs || iarg < 1) {
1590 auto const& entry = f->
argn[iarg - f->
nargs];
1592 std::visit(overloaded{[](double) {
return 0; },
1593 [](
Object*) {
return 1; },
1594 [](
Object**) {
return 1; },
1595 [](
char**) {
return 2; },
1597 [](
auto const& x) ->
int {
1598 throw std::runtime_error(
1599 "hoc_Argtype didn't expect argument of type " +
1615 auto const& arg_entry = get_argument(
narg);
1616 if (stack_entry_is_tmpobject(arg_entry)) {
1619 return cast<Object**>(arg_entry);
1624 return std::visit(overloaded{[](
char** pstr) {
return pstr; },
1626 if (sym->type == CSTRING) {
1627 return &sym->u.cstr;
1628 }
else if (sym->type ==
STRING) {
1634 [](
auto const&) ->
char** {
1637 get_argument(
narg));
1642 auto& arg_entry = get_argument(
narg);
1643 auto&
value = cast<double>(arg_entry);
1764 d = (*((
pc++)->sym->u.ptr))(d);
1781 sym = last[-10].
sym;
1793 for (pcv =
pc; pcv; --pcv) {
1807 }
else if (pcv->
in ==
STOP) {
1821 printf(
"code for hoc_autoobject()\n");
1844 switch (sym->
type) {
1920 switch (sym->
type) {
2019 }
else if (r <= -d2) {
2072 get_stack_entry_variant(0);
2073 auto const& entry2 = get_stack_entry_variant(1);
2074 auto const type2 = get_legacy_int_type(entry2);
2094 hoc_execerror(
"don't know how to compare these types",
nullptr);
2100 auto const& entry1 = get_stack_entry_variant(0);
2101 get_stack_entry_variant(1);
2102 auto const type1 = get_legacy_int_type(entry1);
2122 hoc_execerror(
"don't know how to compare these types",
nullptr);
2130 double const result = d1 != 0.0 && d2 != 0.0;
2138 d1 = (double) (d1 != 0.0 || d2 != 0.0);
2145 d = (double) (d == 0.0);
2178 switch (sym->
type) {
2188 *(sym->
u.
pval) = d2;
2220 (sym->
u.
pval)[ind] = d2;
2241 (
OPVAL(sym))[ind] = d2;
2265 *cpp = (
char*)
emalloc((
unsigned) (strlen(
buf) + 1));
2282 static char name[100];
2283 char* cp =
name + 100;
2295 for (
i = a->
nsub - 1;
i >= 0; --
i) {
2303 for (
j = n1 - 1;
j >= 0; --
j) {
2317 if (ndim_now != ndim) {
2318 hoc_execerr_ext(
"array dimension of %s now %d (at compile time it was %d)",
2335 int ndim = (
pc++)->
i;
2347 if (ndim != aray->nsub) {
2348 hoc_execerr_ext(
"array dimension of %s now %d (at compile time it was %d)",
2353 for (
int i = 0;
i < aray->nsub; ++
i) {
2354 int const d = hoc_look_inside_stack<double>(aray->nsub - 1 -
i) +
hoc_epsilon;
2355 if (d < 0 || d >= aray->sub[
i]) {
2357 "subscript %d index %d of %s out of range %d",
i, d, sp->
name, aray->sub[
i]);
2359 total = total * (aray->sub[
i]) + d;
2361 for (
int i = 0;
i < aray->nsub; ++
i) {
2390 std::snprintf(
s->buf,
s->size + 1,
"%.8g ",
hoc_xpop());
2395 std::snprintf(
s->buf,
s->size + 1,
"%s ", ss);
2404 hoc_execerror(
"Don't know how to print this type\n",
nullptr);
2417 std::snprintf(
s->buf,
s->size + 1,
"%s", *cpp);
2433 if (doomed->
type == UNDEF)
2434 fprintf(stderr,
"%s: no such variable\n", doomed->
name);
2436 fprintf(stderr,
"%s: can't be deleted\n", doomed->
name);
2516 for (
i = end - 1;
i != begin;
i--) {
2523 printf(
"insert code: what follows is the entire code so far\n");
2527 printf(
"end of insert code debugging\n");
int cxx_demangle(const char *symbol, char **funcname, size_t *funcname_sz)
int segment_limits(double *pdx)
void rangevarevalpointer()
double cable_prop_eval(Symbol *sym)
void cable_prop_assign(Symbol *sym, double *pd, int op)
double * cable_prop_eval_pointer(Symbol *sym)
static Inst * codechk(void)
Inst * hoc_prog_parse_recover
static void frameobj_clean(Frame *f)
void hoc_delete_symbol(void)
static char * stmp[HOC_TEMP_CHARPTR_SIZE]
#define HOC_TEMP_CHARPTR_SIZE
void oc_save_code(Inst **a1, Inst **a2, std::size_t &a3, Frame **a4, int *a5, int *a6, Inst **a7, Frame **a8, std::size_t &a9, Symlist **a10, Inst **a11, int *a12)
static Object ** hoc_temp_obj_pool_
static void for_segment2(Symbol *sym, int mode)
Symbol * hoc_get_last_pointer_symbol(void)
std::variant< double, Symbol *, int, stack_ndim_datum, Object **, Object *, char **, neuron::container::generic_data_handle, std::nullptr_t > StackDatum
static void ndim_chk_helper(int ndim)
static Pfrv initfcns[MAXINITFCNS]
char * hoc_strgets(char *cbuf, int nc)
static std::size_t rstack
void oc_restore_code(Inst **a1, Inst **a2, std::size_t &a3, Frame **a4, int *a5, int *a6, Inst **a7, Frame **a8, std::size_t &a9, Symlist **a10, Inst **a11, int *a12)
void hoc_argrefasgn(void)
void hoc_chk_sym_has_ndim1()
void hoc_iterator_object(Symbol *sym, int argcount, Inst *beginpc, Inst *endpc, Object *ob)
void hoc_on_init_register(Pfrv pf)
static void frame_objauto_recover_on_err(Frame *ff)
int hoc_strgets_need(void)
static int obj_pool_index_
std::ostream & operator<<(std::ostream &os, const stack_ndim_datum &d)
void hoc_codesym(Symbol *f)
HocReturnType hoc_return_type_code
Inst * hoc_codeptr(void *vp)
static const char * parsestr
void hoc_autoobject(void)
static std::vector< StackDatum > stack
The stack.
static Object * unref_defer_
void hoc_chk_sym_has_ndim2()
static void stack_obtmp_recover_on_err(int tcnt)
void hoc_insertcode(Inst *begin, Inst *end, Pfrv f)
void hoc_execute(Inst *p)
void hoc_chk_sym_has_ndim()
void hoc_define(Symbol *sp)
void hoc_object_eval(void)
void hoc_ob_pointer(void)
constexpr auto reverse(T &&iterable)
constexpr auto renumerate(T &&iterable)
double chkarg(int, double low, double high)
@ NUMBER
type of ast::Number
int hoc_is_object_arg(int narg)
void hoc_push_frame(Symbol *sp, int narg)
void hoc_plprint(const char *)
void hoc_prstack()
Print up to the 10 most-recently-pushed elements on the stack.
void hoc_push_ndim(int d)
void hoc_run_stmt(Symbol *sym)
Object ** hoc_objgetarg(int narg)
void hoc_pushstr(char **d)
void hoc_execerr_ext(const char *fmt,...)
printf style specification of hoc_execerror message.
double * hoc_getarg(int narg)
double hoc_call_func(Symbol *s, int narg)
Symbol * hoc_get_symbol(const char *var)
Object * hoc_obj_look_inside_stack(int i)
void hoc_pushpx(double *d)
std::unique_ptr< Object, TmpObjectDeleter > TmpObject
int hoc_inside_stacktype(int i)
void hoc_pushobj(Object **d)
Object ** hoc_objpop()
Pop pointer to object pointer and return top elem from stack.
int hoc_errno_check(void)
void hoc_free_string(char *)
int hoc_ParseExec(int yystart)
int hoc_stack_type()
Get the type of the top entry.
void hoc_pushs(Symbol *d)
int hoc_is_str_arg(int narg)
int hoc_is_temp_charptr(char **cpp)
bool hoc_stack_type_is_ndim()
Objectdata * hoc_objectdata
void hoc_assign_str(char **cpp, const char *buf)
Object ** hoc_temp_objptr(Object *obj)
int hoc_argtype(int narg)
double hoc_opasgn(int op, double dest, double src)
void hoc_tobj_unref(Object **p)
int hoc_is_double_arg(int narg)
void hoc_free_list(Symlist **)
char ** hoc_temp_charptr(void)
int hoc_xopen_run(Symbol *sp, const char *str)
void hoc_retpushx(double x)
void hoc_obj_ref(Object *obj)
char * hoc_object_name(Object *ob)
void hoc_fake_call(Symbol *s)
void hoc_stkobj_unref(Object *o, int stkindex)
double * hoc_pgetarg(int narg)
int hoc_araypt(Symbol *sp, int type)
int hoc_is_pdouble_arg(int narg)
T const & hoc_look_inside_stack(int i)
Get the stack entry at depth i.
void hoc_obj_unref(Object *obj)
void hoc_call_func_result_on_stack(Symbol *s, int narg)
Symbol * hoc_parse_stmt(const char *str, Symlist **psymlist)
char * hoc_araystr(Symbol *sym, int index, Objectdata *obd)
void hoc_push_object(Object *d)
int hoc_is_tempobj_arg(int narg)
void hoc_push(neuron::container::generic_data_handle handle)
TmpObject hoc_pop_object()
char ** hoc_pgargstr(int narg)
HocStr * hocstr_create(size_t size)
void hocstr_resize(HocStr *hs, size_t n)
Objectdata * hoc_objectdata_restore(Objectdata *obdsav)
Objectdata * hoc_objectdata_save(void)
bool is_array(const Symbol &sym)
Symlist * hoc_top_level_symlist
double var(InputIterator begin, InputIterator end)
double hoc_Pow(double x, double y)
void move(Item *q1, Item *q2, Item *q3)
void hoc_execerror(const char *s1, const char *s2)
static void * emalloc(size_t size)
void hoc_warning(const char *s1, const char *s2)
handle_interface< non_owning_identifier< storage > > handle
Non-owning handle to a Mechanism instance.
constexpr do_not_search_t do_not_search
In mechanism libraries, cannot use auto const token = nrn_ensure_model_data_are_sorted(); because the...
int Sprintf(char(&buf)[N], const char *fmt, Args &&... args)
Redirect sprintf to snprintf if the buffer size can be deduced.
int const size_t const size_t n
Objectdata * hoc_top_level_data
int nrnmpi_numprocs_world
HOC interpreter function declarations (included by hocdec.h)
void hoc_free_symspace(Symbol *)
void operator()(Object *) const
Non-template stable handle to a generic value.
stack_ndim_datum(int ndim)
int Fprintf(FILE *stream, const char *fmt, Args... args)
int Printf(const char *fmt, Args... args)