Skip to content

feat(builtins): RFC 8259 json exponents, read_line stdin primitive, is_dir (#557 #558 #576)#586

Merged
InauguralPhysicist merged 1 commit into
mainfrom
feat/core-builtins-557-558-576
Jul 13, 2026
Merged

feat(builtins): RFC 8259 json exponents, read_line stdin primitive, is_dir (#557 #558 #576)#586
InauguralPhysicist merged 1 commit into
mainfrom
feat/core-builtins-557-558-576

Conversation

@InauguralPhysicist

Copy link
Copy Markdown
Collaborator

Three consumer-filed core-builtin gaps, one per issue.

#557 — json_decode accepts RFC 8259 exponent notation

The number scanner accepted e/E/+ but never the - of a negative exponent, so 1e-06 (Python json.dumps, JS JSON.stringify, serde — and EigenScript's own json_encode, whose %.15g emits scientific notation for tiny/huge magnitudes) failed at the sign: encode→decode did not round-trip. eigs_json_parse_number now scans the exact RFC §6 grammar ([minus] int [frac] [exp]) and raises on malformed tails ("1e", "1e+", "1.") instead of letting atof() guess silently. Deliberately retained laxity: leading zeros (01) stay accepted, as before.

Tests (tests/test_json_hard.eigs JH44–JH55): decode of 1e-06, 1E+5, 2.5e3, the issue's DeslanStudio value -6.179673164297128e-06, exponent inside an object; malformed tails raise catchable errors; both-direction round-trips for tiny/huge/negative-tiny magnitudes through json_encode.

(DeslanStudio's exponent-free oracle-generator workaround can now be dropped — deliberately NOT touched here, that's DeslanStudio's repo.)

#558read_line: stream-safe stdin read

read_line of null — blocking getline(3) on stdin: returns the next line without its trailing newline (\r\n stripped as one unit), null at EOF, "" for an empty line (distinguishable from EOF). Closes the pipeline hole: read_text of "/dev/stdin" sizes with fseek/ftell, which fails on unseekable fds, so gen | eigenscript client.eigs silently read "".

Tape-first: nondeterministic input, wrapped with the TRACE_NONDET_TAKE/TRACE_NONDET_RECORD pair like read_bytes — under EIGS_REPLAY the recorded lines are served and no live stdin read runs. Freestanding profile excludes it like the other IO builtins. Docs: BUILTINS.md row, TRACE.md wrapped-sources list.

Tests (tests/test_read_line.sh, new suite section [42a2], 7 checks): pipe delivery, empty-line-vs-EOF, unterminated final line, CRLF, seekable redirect, and the replay contract — record under piped stdin, replay with stdin at /dev/null must serve the recorded lines; tape carries exactly one N record per call (2 lines + EOF null).

NOT done (deliberate): the issue's alternative read_text chunked-read fallback for unseekable fds — read_line covers the consumer need (line-based CLI), and changing read_text's pipe behavior is a separate semantic decision.

#576is_dir

is_dir of path → 1/0 via stat(2) + S_ISDIR, next to the file_exists/ls/mkdir/rename family; replaces DeslanStudio's file_exists of f"{path}/." probe. Non-string / missing / plain file → 0.

Tape treatment + the consistency finding the brief asked for: I checked how file_exists is traced first — it is NOT traced (and not replay-blocked either; same for ls, mkdir, getcwd, exe_path — they appear in neither of TRACE.md's lists and run live under EIGS_REPLAY). Per the standing tape-first veto for NEW nondet builtins, is_dir is trace-recorded (TRACE_NONDET_RET) rather than matching the untraced legacy convention; the pre-existing inconsistency is filed as #585 rather than silently resolved either way here.

Tests: functional checks in tests/test_file_rename.eigs (dir / nested dir / plain file / missing / non-string; section count 12 → 17) and a replay check in tests/test_replay.sh (record with the directory present, delete it, replay must still answer 1).

Also

Gates

  • release suite green (incl. new [42a2] + extended [42a]/file-ops sections)
  • ASan+UBSan suite detect_leaks=1: tally 0, [87] clean
  • make jit-smoke, make freestanding-check green (core touched)
  • tools/doc_drift_check.sh rc=0 ([99b] discoverability gate covers the two new BUILTINS.md rows)

Closes #557
Closes #558
Closes #576

🤖 Generated with Claude Code

…s_dir (#557 #558 #576)

- json_decode: exact RFC 8259 number grammar — negative exponents parse
  (1e-06; json_encode's own %.15g output round-trips); malformed tails
  (1e, 1e+, 1.) raise instead of atof-guessing (#557)
- read_line of null: blocking getline(3) on stdin, line without trailing
  newline, null at EOF; tape-first (TAKE/RECORD like read_bytes — replay
  serves recorded lines, no live read); freestanding-excluded (#558);
  test_read_line.sh + suite [42a2]
- is_dir of path: stat(2)+S_ISDIR next to file_exists; trace-recorded
  per the tape-first veto — the untraced legacy fs predicates
  (file_exists/ls/mkdir/getcwd/exe_path) are flagged as #585 instead of
  being silently matched (#576); replay test proves the recorded answer
  wins after the directory is deleted
- LSP completions for both new builtins; BUILTINS.md/TRACE.md/CHANGELOG

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@InauguralPhysicist InauguralPhysicist merged commit 13395f5 into main Jul 13, 2026
17 checks passed
@InauguralPhysicist InauguralPhysicist deleted the feat/core-builtins-557-558-576 branch July 13, 2026 02:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant