Files

5 lines
14 B
Plaintext
Raw Permalink Normal View History

Give each DEF call its own environment, so recursion returns The function's environment was owned by the funcdef and re-initialised on every call, which made a function not re-entrant and cost two silent defects: DEF DBL(N#) = N# * 2 PRINT DBL(10) + DBL(1) was 4, should be 22 The result was a pointer into the funcdef's own environment, so the second call overwrote the first before the operator saw it -- both operands became the last call's answer. Two *different* functions in one expression were fine, which is most of why it was invisible. DEF FACT(N#) IF N# <= 1 THEN RETURN 1 RETURN N# * FACT(N# - 1) PRINT FACT(5) never returned The recursive call re-initialised the environment the outer call was still using, so the loop waiting for control to come back could not see it. No error, no bound, no diagnostic -- the one place in this interpreter that looped forever rather than raising. A call takes an environment from the pool now, exactly as GOSUB does. The result is copied into a caller-scope scratch before that environment goes back, because handing back a pointer into the callee is what made two calls collide and would now be a pointer into a released slot as well. RETURN parks its result on the *parent* rather than on the environment it is about to release, so nothing reads a freed slot to find it. Recursion depth answers to AKBASIC_MAX_ENVIRONMENTS like every other nesting, so too deep is "Environment pool exhausted" -- a diagnosis where there was none. akbasic_FunctionDef.environment goes with it, as dead state. One thing this exposed but did not cause, measured against a stashed build and recorded rather than fixed: a statement containing a failed multi-line DEF call still completes and prints a junk value. It is visible more often now only because runaway recursion reaches it where it used to hang. tests/language/functions/recursion.bas deliberately does not pin that answer. Chapter 16 loses its "walk a list with a loop, not a recursive DEF" caveat and gains the one that is still true: a function cannot take a structure parameter yet, so it reaches a record by name. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-01 12:29:35 -04:00
120
10
22
222