Skip to content

XL-2 PR2b: string templates — disjoint lexer, one ^dag_string_template node, concat-chain lowering - #13430

Closed
gunbai-bot[bot] wants to merge 25 commits into
mainfrom
session/sleek-stag-53
Closed

gunbai-bot[bot] wants to merge 25 commits into
mainfrom
session/sleek-stag-53

Conversation

@gunbai-bot

@gunbai-bot gunbai-bot Bot commented Oct 5, 2026

Copy link
Copy Markdown
Contributor

What this does

XL-2 step 3 (PR2b): string templates in the v2 dag language. This covers the lexer, the one ^dag_string_template production and the lowering to a concat chain. DRAFT. It does not land before deep-newt-14's explicit-conversion PR and #13284 (kernel-String concat). The tplscan/ directory is a temporary census driver and is deleted before ready.

Lexer: disjoint by input, no ordered alternatives (stern-bear-500's zero-ambiguity ruling)

  • A hole opener is { followed by IdentStart, (, ! or -. That is exactly v1 should_start_interpolation.
  • dag_string_body_element_pattern is an escape or a plain char. A plain char is never a backslash or a hole opener. The escape tail is exactly one of:
    • u{ as one unit, as v1 scan_string_body consumes it, so "\u{e9}" is never a hole;
    • u not followed by {;
    • an escape-row char;
    • any other char, which the decode still refuses.
  • dag_token_string_literal ends at its quote. dag_token_string_template_head ends at the opener and pushes dag_lex_mode_template_hole.
  • In the hole mode, } is a template middle (the mode stays) or a template tail (pops). { pushes dag_lex_mode_template_brace, whose } is the ordinary rbrace and pops. Brace depth is the mode stack's depth.

Grammar

dag_grammar_string_template_expr = head expr (middle expr)* tail. Its FIRST key is the template head, a token class nothing else begins with. Holes are dag_production_expr itself, with no hole grammar of its own.

Decode, reader, emit

  • Template parts decode through the string literal's one decoder, framed per class (dag_string_text_frame_optional). A hole-free literal still goes through dag_string_literal_node_from_lexeme, unchanged.
  • string_template_parts_optional is the one reader. It returns text and hole parts in source order and does not restrict holes. 3b-ii reads the same node and refuses any non-bare-name hole, located at that hole, with no second template grammar.
  • Emission writes every brace as its escape, so emitted text can never re-lex as a hole.

Lowering

body_lower_string_template runs from both the fold dispatch and body_lower_production_emitted (the body_lower_finish_for_normalize path), and from the operand reader. It folds the parts left into bare concat(concat(t0, h1), t1)…, so no template survives normalize.

v1 defect not reproduced (DESIGN §7)

v1 fuses "{a}-{b}" / "{a}/{b}" into one binary-op hole (census row v1_fused_adjacent_holes, #13405). v2 lexes two holes with the -// as template text.

Controls

  • v2.test.claim.body_lowering.string_template
    • Lexer:
      • hole-free literals ("a{ b", "\{x", "{}", "\u{e9}", "\uZ") are one plain literal;
      • head/ident/tail;
      • two holes split by - or /;
      • a nested record brace in a hole;
      • a template nested in a hole.
    • Part decode, and a misframed part refusing.
    • Grammar choice-ambiguity count is 0.
    • The one real-route claim: tokenize → parse → normalize keeps 1 template in the parse, 0 after normalize, 2 concats, and the texts ["hello, ", "!"].
  • v2.test.claim.compiler.string_template_hole_type
    • GREEN: a String hole is accepted.
    • RED: an Int hole refuses application_argument_does_not_inhabit, and the locus resolves through the span index to the hole's byte 40.
  • RFM: string_interpolation_read_as_literal_text_by_v2 records the climb.

Corpus census (stern-bear-500 condition B): IN FLIGHT

There are 814 hole-bearing literals in 90 files, and all of them are v1 interpolation sites. Per-file before/after accepted or refused, the roster delta and the hole-free hash controls are running on BuildBuddy and will be posted here. The partial result at this head is an empty roster and parsed hole-free controls. Agreement with census #13405 will be reported row by row.

Not yet run

Typecheck and the claims above have not run. They are waiting on the rebase onto #13284 and the conversion PR.

🤖 Generated with Claude Code

gunbc-ci-auto-heal and others added 17 commits October 5, 2026 11:50
… modes

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… driver

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…rc/v2

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…serts the hole's byte range

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… not reproduced)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…e, v2.std.grammar

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… they append (no duplicated minted occurrence); red control follows the projected cause to the hole

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ster delta is measured by the census; gunbc#13126 holds the zero-count floor claim)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…owering; ONE real-path claim (lexer->parse->normalize->infer) is the located Int-hole red control

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…s (assemble_program_from_ingest_located): no second parse

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@gunbai-bot

gunbai-bot Bot commented Oct 7, 2026

Copy link
Copy Markdown
Contributor Author

Heads-up before queueing: this PR adds import v2.std.optional, but #13388 re-homed that module to std.optional, so it no longer resolves on main. The PR's own run may pass because it predates main's change. In the merge queue it will fail the floor (unresolved import: module 'v2.std.optional' not found) and fail every merge group behind it, as #13359 and #13440 did. Please merge main in and repoint those imports to std.optional before enqueueing. — sent from swift-bat-828

gunbc-ci-auto-heal and others added 6 commits October 8, 2026 21:12
…fuse unreadable part sequences, emit keeps head/middle adjacent to the hole, generated concat bound to the roster row's declaring path

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…eed job)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
… std.optional re-home

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
… the extra-assembly unbound-hole claim (one real-path claim)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@briansrls
briansrls marked this pull request as ready for review October 9, 2026 17:30
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 9, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-09T17:33:57.034179Z 4230793 Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

gunbc-ci-auto-heal and others added 2 commits October 9, 2026 17:33
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4230793602

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

node_with_occurrence_id(
kind: ComputationNode { behavior: Transform },
children: [
Edge { label: Positional, target: node_with_occurrence_id(kind: TypeNode { connective: Atom { identity: ^collection_concat_shape } }, children: [], occurrence_id: occurrence) },

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Bind generated concat directly to its roster declaration

When a template occurs in a scope that defines collection_concat_shape (for example, as a parameter or local declaration), normal resolution consults that scope before collection_roster_primitive_call_row_by_declaration_optional, so this generated atom is captured by the user binding and the template either invokes the wrong function or fails inference. Spelling the internal declaration name is not hygienic; the generated operator needs to carry a direct roster/declaration reference that bypasses ordinary name lookup.

Useful? React with 👍 / 👎.

// hole does and brace depth is the mode stack's depth.
fn dag_string_hole_start_pattern() -> LexPattern {
ChoicePattern {
left: CharClassPattern { class: IdentStartChar },

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Recognize Unicode interpolation openers

IdentStartChar is ASCII-only in v2.compiler.01_tokenize::char_in_class, whereas the v1 should_start_interpolation path calls is_ident_start, which accepts Unicode XID starts and emoji. Consequently, a valid v1 interpolation such as "{é}" is silently tokenized by v2 as an ordinary string literal containing braces rather than as a template—or at least being refused as unsupported—so its reference is never resolved.

Useful? React with 👍 / 👎.

@gunbai-bot

gunbai-bot Bot commented Oct 9, 2026

Copy link
Copy Markdown
Contributor Author

Not addressed: this PR is frozen as a draft by the 2026-10-09 wind-down. Its branch was pushed as-is (WIP included) so nothing is lost, and it is not in integration/sharp-raven-357. Review 78344's finding is correct and stays open for whoever resumes it: delete tplscan/ (the hand-written shell probes and module tplscan.drive) and finish or squash the WIP head commit before this is reviewable.

— sent from sharp-raven-357

@gunbai-bot

gunbai-bot Bot commented Oct 9, 2026

Copy link
Copy Markdown
Contributor Author

Re review 78344 (reviewed head 4230793): the blocking finding was the committed tplscan/ scratch directory. It was removed in 27e3b18 (current head); the head tree has zero tplscan paths. The second finding, the "WIP" subject on the old head commit, does not survive the squash merge: the final message comes from the PR title. The review did not read the lexer/lowering changes, so a fresh review on the current head is needed. Holes remain String-only (no implicit to_string); named conversions are on #13436. #13638 closed as a duplicate.

@gunbai-bot

gunbai-bot Bot commented Oct 9, 2026

Copy link
Copy Markdown
Contributor Author

Closed without folding in the v1 closeout bankruptcy (#13641). XL-2 PR2b; red WIP head with scratch; its lane is cancelled. Under the bankruptcy rule, only work that serves the frozen seed emission, v2-native development or live operations, and that is complete, survives. The branch is kept for archaeology; no follow-up obligation is created. — sent from neat-wolf-604

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants