Skip to content

Commit 387afea

Browse files
hyperpolymathclaude
andcommitted
fix(interp): wire missing string_length builtin (Refs #332, #329)
`string_length : String -> Int / Pure` is declared as a primitive in three places that AffineScript programs traverse during the compile pipeline: * stdlib/effects.affine — the surface declaration * lib/resolve.ml — recognises the name during resolution * lib/typecheck.ml — types it as String -> Int / EPure …but the runtime `VBuiltin` entry in lib/interp.ml's `create_initial_env` was missing. Programs calling `string_length` compiled cleanly and failed at run with: Unbound variable: string_length This broke two E2E test suites on main: - E2E STDLIB-04e Pure #332 / "string_length(\"hello\") == 5" - E2E STDLIB-04b error #329 / divergence assertion (`lookup` used `string_length(k) > 0` as a guard — the missing binding produced the wrong eval_error variant, so the test `RuntimeError "empty key"` assertion saw an Unbound variable instead.) Wire the builtin as `String.length` of an OCaml `VString`. Matches the codegen-Deno path (`(s).length`) and the resolve/typecheck layers' existing assumptions about the surface. Found via affinescript#361's build-job CI red after the bench/dune + fixture-exemption fixes cleared the other two baselines; this stdlib bug was latent under those failures. Refs #332 (STDLIB-04e pure externs), Refs #329 (STDLIB-04b throws extern). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent b89eb1a commit 387afea

1 file changed

Lines changed: 14 additions & 0 deletions

File tree

lib/interp.ml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -623,6 +623,20 @@ let create_initial_env () : env =
623623
| [VFloat f] -> Ok (VString (string_of_float f))
624624
| _ -> Error (TypeMismatch "float_to_string expects Float")
625625
));
626+
(* STDLIB-04e (Refs #332): `string_length : String -> Int / Pure` is
627+
declared in stdlib/effects.affine, resolved by lib/resolve.ml, and
628+
typed by lib/typecheck.ml — but the runtime VBuiltin entry was
629+
missing here. Programs that call `string_length` would compile
630+
cleanly and fail at run with `Unbound variable: string_length`
631+
(broke E2E STDLIB-04e #332 + STDLIB-04b #329 — the latter uses
632+
`string_length(k) > 0` as a guard, so the missing binding masked
633+
the divergence-vs-RuntimeError assertion as an Unbound variable
634+
error instead). Wire it as the canonical String.length surface. *)
635+
("string_length", VBuiltin ("string_length", fun args ->
636+
match args with
637+
| [VString s] -> Ok (VInt (String.length s))
638+
| _ -> Error (TypeMismatch "string_length expects String")
639+
));
626640
(* STDLIB-04e (Refs #332): `string_to_int` is the typed-alias surface
627641
declared in stdlib/effects.affine. Same semantics as `parse_int`
628642
(the canonical name) — the alias was unwired before this PR, so

0 commit comments

Comments
 (0)