Skip to content

fix(#1954): split on real newlines in _strip_single_line_comments, not str.splitlines() - #2385

Merged
squid-protocol merged 2 commits into
mainfrom
fix/issue-1954-splitlines-phantom-newlines
Aug 28, 2026
Merged

fix(#1954): split on real newlines in _strip_single_line_comments, not str.splitlines()#2385
squid-protocol merged 2 commits into
mainfrom
fix/issue-1954-splitlines-phantom-newlines

Conversation

@squid-protocol

Copy link
Copy Markdown
Owner

Closes #1954.

Problem

_strip_single_line_comments — the comment stripper for the entire
"line_exclusive" lexical family (~20 languages: assembly, python, ruby,
shell, perl, makefile, yaml, …) — split its input with
for line in text.splitlines(): and rejoined with "\n".join(...).

str.splitlines() breaks on far more than \n / \r\n: vertical tab,
form feed, \x1c\x1e, NEL (\x85), U+2028, U+2029. Any of those
inside what a human reads as one physical line — most often inside a
comment — was silently converted to a literal \n on rejoin. Every
downstream line-number computation that counts \n in the resulting
stream (detector.py's _slice_by_labels line tracker, etc.) then
drifted by the cumulative count of such characters — a monotonic drift
that never resets.

Confirmed evidence

language-crucible/data/assembly/cosmopolitan/ape.S (real Cosmopolitan
libc, which uses form feed as a deliberate page-break idiom in its
comments — 9 of them) reproduced this exactly. Every function's recorded
start_line was too high by precisely the number of form feeds before
it:

function real (ctags) before after (this PR)
stub 216 217 216
pc 251 253 251
dsknfo 346 348 346
realmodeloader 1283 1290 1283
longmodeloader 1365 1373 1365
kernel 1743 1752 1743

Fix

Normalise \r\n / \r\n (the one useful thing splitlines() was
doing), then split("\n"). Form feed / vertical tab / the other
splitlines()-special characters now stay inline as ordinary content,
matching how ctags and tree-sitter read the file.

Verification

  • New test_prism_issue_1954_form_feed_in_comment_preserves_line_count
    (python/shell/ruby with form feeds in comments + a CRLF round-trip
    check). Confirmed fails without the fix, passes with it.
  • 561 tests/core_engine/ pass; ruff / mypy / dead-key / ast-accuracy
    clean.
  • crucible_check.py --update: all drift confined to ape.S and its
    assembly-ecosystem aggregates — every function line number moves toward
    the correct ctags value, no other corpus file touched. Both golden
    masters re-blessed.
  • tri_comparison_chart.py --all --ci: all OK, no precision regressions.

🤖 Generated with Claude Code

squid-protocol and others added 2 commits August 28, 2026 12:30
…t str.splitlines()

_strip_single_line_comments (the comment stripper for the whole
"line_exclusive" family -- ~20 languages) split its input with
str.splitlines(), which also breaks on vertical tab, form feed, the
file/group/record separators, NEL and U+2028/U+2029. Any of those inside
a physical line -- most often inside a comment -- became a literal "\n"
when the code/comment streams were rejoined with "\n".join(...), so every
downstream newline-counting line-number calculation (detector.py's
_slice_by_labels line tracker, etc.) drifted by the cumulative count of
such characters -- a monotonic drift that never resets.

Confirmed on language-crucible's assembly/cosmopolitan/ape.S (real
Cosmopolitan libc, which uses form feed as a page-break idiom in its
comments): every function's recorded start_line was too high by exactly
the number of form feeds before it (kernel: 1752 vs the real 1743, +9).

Fix: normalise CR/CRLF the way splitlines() did, then split on "\n" only.
Form feed / vertical tab / the other splitlines()-special characters now
stay inline as ordinary content, matching how ctags and tree-sitter read
the file.

Closes #1954.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
crucible_check.py --update: all changes confined to
assembly/cosmopolitan/ape.S (the only corpus file with form feeds) and
its assembly-ecosystem aggregates. Every ape.S function's start_line/
end_line drops by its preceding form-feed count, now matching ctags
exactly (e.g. kernel 1752 -> 1743, dsknfo 348 -> 346, realmodeloader
1290 -> 1283). Structural Tab Indentations 1029 -> 1021 and small
downstream impact/mass recalcs follow from the corrected line structure.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@squid-protocol squid-protocol added core-engine Modifications to the central physics and parsing engine bug Unintended behavior or logic failure in the engine labels Aug 28, 2026
@github-actions

Copy link
Copy Markdown
Contributor

🐦‍⬛ Muninn Security Scan

✅ No security issues found.

🐦‍⬛ Powered by Muninn · Skald Lab

@squid-protocol
squid-protocol merged commit b477968 into main Aug 28, 2026
53 of 54 checks passed
@squid-protocol
squid-protocol deleted the fix/issue-1954-splitlines-phantom-newlines branch August 28, 2026 17:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Unintended behavior or logic failure in the engine core-engine Modifications to the central physics and parsing engine

Projects

None yet

Development

Successfully merging this pull request may close these issues.

prism.py: _strip_single_line_comments's str.splitlines() inserts phantom newlines on Form Feed/Vertical Tab (20 line_exclusive languages)

1 participant