Skip to content

--target web: nested while loop with let-from-parameter counter never advances #135

Description

@proggeramlug

Follow-up to #133 (thanks for the quick turnaround on v0.5.158!). Shipping Bloom Jump to web uncovered another --target web bug not covered by that fix.

Perry version: 0.5.158 (built from source, b6d3cb9).

Symptom

A while loop inside a user function, where the loop variable is a function-scoped let initialized from a parameter, hangs on web — the loop never advances even though the increment statement is reached. The same code pattern works on native targets and works at the outer function scope in the same file.

Minimal repro

function parseSimple(s: string, start: number): number {
  let i = start;
  while (i < s.length) {
    const c = s.charCodeAt(i);
    if (c === 32 || c === 10 || c === 13) {
      i = i + 1;
    } else {
      break;
    }
  }
  return i;
}

const idx = parseSimple("   hello", 0);
console.log("stopped at " + idx.toString());  // native: 3. web: hangs.

With a 200-iteration guard, observed behavior is i stays at start forever — the i = i + 1 assignment doesn't persist across iterations.

Context / scope

  • Same pattern in the caller function (a top-level while (idx < dlen) { ...; idx = idx + 1.0; }) executes correctly.
  • Substituting a module-level const SCRATCH = [0] + SCRATCH[0] = SCRATCH[0] + 1.0 in place of i doesn't help — array-slot mutation doesn't persist either inside this nested loop.
  • Switching the counter type (let i = start | 0;) didn't help.
  • Splitting the compound || condition into separate if statements didn't help.
  • Collapsing the loop to a single condition (if (c === 32) { i = i + 1; } else { break; }) still hangs.

Possibly related: the problem surfaced on parsing level files for Bloom Jump (parseNumberAt), which is invoked 5–10 times in a Pass-1 loop. If this is a single-entry-point optimizer issue, the function being called repeatedly could be relevant.

Workaround used

Rewrote the hot path to avoid the nested while-loop entirely by pre-slicing the substring and delegating to native parseInt. But parseInt on its own still needs a small while-loop to find the end-of-number, which also hangs — so currently blocked on having any level-load path working on web.

Happy to provide more instrumentation if useful; also willing to test a fix candidate directly against the Bloom Jump repro.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions