Formats.md — Strings, Templates, and Format Tags in U

The string model

U has three string forms and one reserved:

"hello"                                     → S (literal, no interpolation)
`hello {{name}}`                            → S (interpolation, escapes)
Tag`hello {{name}}`                         → template function → Formats.*
'...'                                       → reserved (compile error)

One rule: double quotes are literal, backticks interpolate. Tags produce typed template functions. Single quotes are reserved for future use.

1. Literal strings: "..."

Double-quoted strings are plain byte sequences. Escape sequences (\n, \t, \\, \") are processed. No interpolation — {{ inside double quotes is literal text.

name = "Greg"                   // → S
path = "C:\\Users\\Greg"        // → S (backslash-escaped)
msg = "price is {{amount}}"     // → S literally containing "price is {{amount}}"

Literal strings are for fixed text: identifiers, paths, format strings passed to other systems, keys, labels. When you write "hello", you get exactly hello — no surprises.

2. Interpolating strings: `...`

Backtick strings process escapes AND interpolate {{expr}} slots:

greeting = `Hello, {{name}}!`                    // → S (name resolved from scope)
report = `{{user.name}} has {{count}} items`     // → S

Each {{expr}} calls .__string__() on the value. The result is S.

Why backticks?

Backticks free up " and ' as plain characters inside the string:

page = HTML`<div class="container" id='main'>
    <h1>{{title}}</h1>
    <p onclick='alert("hello")'>{{body}}</p>
</div>`

No \", no \', no heredoc. Two levels of quoting for free. The only character that needs escaping inside backticks is the backtick itself (\`), which rarely appears in HTML, SQL, CSS, or prose.

This solves the same problem PHP's <<<HEREDOC was invented for — multi-line strings with embedded quotes — but with interpolation and type safety built in.

3. Tagged templates: Tag...``

A tag prefix produces a typed template function instead of a plain string:

q = SQL`SELECT * FROM users WHERE id = {{id}}`     // → ({id: I}) -> Formats.SQL
page = HTML`<p>{{text}}</p>`                        // → ({text: S}) -> Formats.HTML
style = CSS`color: {{c}}`                           // → ({c: Color}) -> Formats.CSS

Stored vs invoked

Every tagged template is a function by default. Call it to get the value:

// Stored — compile once, call many times:
q = SQL`SELECT * FROM users WHERE id = {{id}}`
result1 = q({id: 5})
result2 = q({id: 12})

// Invoked — compile and call now (parens around backtick):
id = 5
result = SQL(`SELECT * FROM users WHERE id = {{id}}`)
// id captured from scope

The rule: Tag...`` = function. Tag(...) = call.

Adapter qualification: Tag[Conn]...``

Some tags need to know the target at compile time:

q_pg   = SQL[pg]`SELECT * WHERE id = {{id}}`       // → $1
q_my   = SQL[mysql]`SELECT * WHERE id = {{id}}`    // → ?
q_lite = SQL[sqlite]`SELECT * WHERE id = {{id}}`   // → ?

The bracket selects the dialect. This is a compile-time decision — the placeholder syntax is baked into the SQL text.

The adapter also validates dialect-specific features:

SQL[pg]`SELECT * WHERE name ILIKE {{pattern}}`      // ✅ Postgres has ILIKE
SQL[mysql]`SELECT * WHERE name ILIKE {{pattern}}`   // ❌ compile error

4. Byte literals: '...'

Single-quoted strings produce bytes, not text. ASCII only.

'A'              // → N8     (65 — single character)
'\n'             // → N8     (10 — newline byte)
'\xff'           // → N8     (255 — hex byte)
'\0'             // → N8     (0 — null byte)
'hello'          // → [N8]   (5 bytes: 104, 101, 108, 108, 111)
'hello\0'        // → [N8]   (6 bytes — null-terminated, C-ready)
'\x89PNG'        // → [N8]   (4 bytes — PNG magic number)
'\x01\x00\xff'   // → [N8]   (3 bytes — binary data)
'café'           // → ❌ compile error: é is not ASCII
'\0'             // → ❌ compile error: 0 is not a natural number (N8 starts from 1)

The rule: single quotes only accept ASCII (0x01–0x7F, no null byte) and escape sequences (\n, \t, \xHH (0x01–0xFF), \\, \'). One character → N8. Multiple characters → [N8].

This is the byte world. "hello" is UTF-8 text (S). 'hello' is raw bytes ([N8]). Functions that take S reject [N8]. Explicit conversion: "hello".bytes()[N8], and S.from_utf8(bytes)S (with validation).

Use cases: C interop (null-terminated byte arrays), binary protocols (wire formats), file magic numbers, byte-level comparison (memcmp instead of Unicode-aware).

N8 and B: safe bytes vs raw bytes

U has two byte types:

Type Range Null bytes Use case
N8 1–255 ❌ impossible ASCII chars, safe byte literals
B 0–255 ✅ allowed Raw binary buffers, wire formats

Conversion between them:

// N8 → B: always safe (widening, implicit)
ch: N8 = 'A'
raw: B = ch                        // 65 → 65, no check needed

// B → N8+N: per-value nullable (0 → none)
raw: B = read_byte()
ch: N8+N = raw.to_n8()              // → N8 if ≥ 1, none if 0

// [N8] → [B]: always safe (same memory layout)
ascii: [N8] = 'hello'
buf: [B] = ascii.to_bytes()         // zero-cost cast

// [B] → [N8+N]: per-element nullable, ALWAYS succeeds
buf: [B] = read_packet()
safe: [N8+N] = buf.to_n8()          // each byte: 0→none, 1-255→N8

// [B] → [N8]: assertion, THROWS if any byte is 0
safe: [N8] = buf.assert_n8()        // throws on null bytes

// Implicit [B] → [N8]: compile WARNING + runtime exception
safe: [N8] = buf                   // ⚠️ compiler warns, runtime checks

Encoding and display:

buf.to_hex()                         // → "89504e470d0a"
buf.to_base64()                      // → "iVBORw0K..."
buf.to_base64url()                   // → URL-safe, no padding
buf.to_utf8()                        // → S+N (none if invalid UTF-8)
buf.display()                       // → "[B](6 bytes: 8950…0d0a)"

S.from_hex("89504e47")              // → [B]+N
S.from_base64("iVBORw0K")           // → [B]+N
S.from_utf8(buf)                    // → S+N

The '...' literal syntax produces N8/[N8] — the safe form. Binary protocol code that needs null bytes uses [B] and constructs byte arrays numerically:

// PNG magic number (contains null byte at position 4):
png_magic: [B] = [0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A]

// Null-terminated C string for interop:
c_str: [B] = 'hello'.to_bytes() + [0x00]

For raw text strings (no escape processing), use the raw tag:

raw`C:\Users\Greg\Documents`    // → S (backslashes are literal)
regex`\d{4}-\d{2}-\d{2}`       // → Regex (backslashes are regex syntax)

5. Escaping

Inside backtick strings and templates:

Source Output Why
{{name}} interpolates name normal interpolation
\{{name}} literal {{name}} backslash escapes opening {{
\}} literal }} backslash escapes closing
\` literal backtick backslash escapes backtick
\n newline standard escape
\t tab standard escape
{name} literal {name} single braces never interpolate

Single braces never interpolate because { collides with CSS rules, regex quantifiers, JSON, and every other format U templates embed.

6. Format specifications

Inside any interpolation, a colon applies Python-style formatting:

HTML`<td>{{price:.2f}}</td>`     // "42.50" then HTML-escaped
`Name: {{name:>20}}`            // right-aligned, width 20
`Count: {{n:04d}}`              // zero-padded to 4 digits

7. The complete tag table

Tag Input S Same-type input Returns External file
(bare) `...` .__string__() S
HTML...`` HTML-escaped Formats.HTML passed through Formats.HTML Formats.HTML.load("f.html", {...})
SQL...`` Parameterized Formats.SQL composed Formats.SQL Formats.SQL.load("f.sql", {...})
CSS...`` Typed (Color, N…) Formats.CSS composed Formats.CSS Formats.CSS.load("f.css", {...})
URL...`` URL-encoded Formats.URL composed Formats.URL Formats.URL.load("f.txt", {...})
SVG...`` HTML-escaped Formats.HTML/Formats.SVG Formats.HTML Formats.SVG.load("f.svg", {...})
Regex...flags Compile error Regex composed Regex
Markdown...`` Escaped then rendered Formats.HTML passed through Formats.HTML Formats.Markdown.load("f.md", {...})
JSON...`` JSON string-escaped Formats.JSON composed Formats.JSON Formats.JSON.load("f.json", {...})
JS...`` JS-escaped Formats.JS composed Formats.JS Formats.JS.load("f.js", {...})
Shell...`` Single-quoted Formats.Shell composed Formats.Shell Formats.Shell.load("f.sh", {...})
Command...`` Single-quoted Formats.Command composed Formats.Command
Handlebars...`` HTML-escaped Formats.HTML passed through Formats.Handlebars
GraphQL...`` JSON string-escaped Formats.GraphQL composed Formats.GraphQL
Mermaid...`` Quoted label Formats.Mermaid appended Formats.Mermaid
Protobuf...`` Formats.Protobuf composed Formats.Protobuf
Config[T]path`` T
raw...`` S (no escapes)

8. Security model

Each tag is the sole point of responsibility for its domain. You cannot construct a Formats.HTML value without going through HTML.... You cannot issue a parameterized query without going through `SQL`.... The compiler enforces the chokepoint.

A function that accepts Formats.SQL will reject plain S at compile time:

f safe_query(q: Formats.SQL) -> [Row]

safe_query(`SELECT * WHERE id = ` + id)          // ❌ compile error: S is not Formats.SQL
safe_query(SQL`SELECT * WHERE id = {{id}}`)       // ✅ parameterized

Capability gating

Template tags run at compile time but are capability-gated. A SQL...`` tag with no capabilities can parse and type-check queries — nothing else. No tag can modify another module's types, inject code, or escalate beyond its declared capabilities.

SQL statement type routing

SQLINSERT INTO users ... doesn't emit a generic `execute()`. The tag parses the SQL, determines the statement type, and emits `conn.insert()`. A function with only `+E(DbRead)` that writes `SQL`INSERT ... gets a compile error — DbRead doesn't grant DbWrite.

Dangerous combination warnings

The compiler flags capability pairs that create attack vectors:

9. External file loading

page   = Formats.HTML.load("templates/page.html", { title, content, user })
report = Formats.SQL.load("queries/report.sql", { start_date: D, end_date: D })
theme  = Formats.CSS.load("styles/theme.css", { brand: Color, spacing: R })
icon   = Formats.SVG.load("assets/star.svg", { size: R, fill: Color })
Locale = Formats.Locale.load("i18n/")

Files are read and validated at compile time. Missing placeholders, type mismatches, and syntax errors are compile errors. The runtime has no file I/O — content is baked into the binary.

10. Summary

"hello"                         // literal S — no interpolation
`hello {{name}}`                // interpolating S — resolves from scope
Tag`hello {{name}}`             // stored template function → Formats.*
Tag(`hello {{name}}`)           // invoked template — resolves from scope, returns value
Tag[adapter]`hello {{name}}`    // dialect-specific template function
'A'                             // I8 (single ASCII byte — 65)
'hello'                         // [I8] (ASCII byte array)
'\xff\x00'                     // [I8] (binary data)
raw`C:\path\to`                 // raw S — no escape processing

There is one way to write a literal string. There is one way to interpolate. There is one way to get a typed template. Four forms. "..." is text. '...' is bytes. Backtick interpolates. Tags produce typed templates. The type system enforces which is required.