# Strings and template literals

## Usage

Single- and double-quoted string literals use the same DSL syntax; pick whichever avoids the delimiter you need inside the text. There are no backslash escape sequences.

```ops
log.info("plain message")
log.info('version: 1.0')
```

Template literals use backticks. Interpolation is `{expression}` where `expression` is either a variable reference or a literal (per grammar).

```ops
throw release-complete `released {$bump.version}`
throw count-report `count {42}`
```

Variable references use `$IDENT` with optional dotted fields (`$step.output.key`). Undeclared `$UPPER_CASE` references are compile errors.

`throw` accepts either a string literal or a template literal (see `ThrowStmt` in the grammar).

## Grammar

```peg
STRING_LIT      = '"' [^"]* '"' | "'" [^']* "'"   # no escape sequences; use the other quote type or template strings
MULTILINE_STR   = '"""' .* '"""' | "'''" .* "'''" # multiline string literals (plain text, no interpolation)
TEMPLATE_LIT    = '`' (TEXT | '{' InterpolExpr '}')* '`'
MULTILINE_TMPL  = '```' (TEXT | '{' InterpolExpr '}')* '```' # multiline template (allows embedded single backticks)
InterpolExpr    = VarRef | Literal
VarRef          = '$' IDENT ('.' IDENT)*
Literal         = STRING_LIT | TEMPLATE_LIT | NUMBER | 'true' | 'false'
```

## IR representation

Canonical value and template-fragment shapes live in [values-and-types](../ir/values-and-types.md).

- String literals lower to a single string value in IR / codegen (content only; quote style is not preserved).
- Template literals are represented as a sequence of static text segments and interpolated expressions after parsing: each `{InterpolExpr}` becomes a structured fragment; the lexer only guarantees balanced `{`…`}` inside the backtick span so the parser can recover `InterpolExpr` (see Implementation).

## Types

`InterpolExpr` is intentionally narrow: only `VarRef` or `Literal` (not arbitrary expressions). Nested template literals inside `{…}` are allowed by the `Literal` production.

## Runtime (bash API surface)

- Emitted bash uses double-quoted strings for DSL string literals regardless of whether the source used `'` or `"`.
- Template interpolation is lowered to safe concatenation / expansion consistent with that emission strategy (no raw backticks in bash output for the DSL template syntax itself).

## Implementation

| | |
|---|---|
| **Tier** | Tier 1 — Lexer (tokenization); full `InterpolExpr` parsing in later parser tiers |
| **Crate / files** | `engine/src/lexer.rs` (scanner); `engine/src/token.rs` (`StringLit`, `TemplateLit`); `engine/src/parser.rs` + `engine/src/ast.rs` for literal / template AST nodes |
| **Validation** | Lexer: tokenize string/template boundaries and spans. Parser: reject unclosed string/template delimiters. Parser / resolver: undeclared `$UPPER_CASE` references. Unit tests: token spans and template segment boundaries per `planning/docs/build_tiers.md` (Tier 1 lexer tests) |

Lexer behavior: emit `StringLit` for both `'...'` and `"..."` with no semantic distinction. For `` `...` ``, emit `TemplateLit` (or equivalent) such that `{…}` regions are delimited for the parser; balance braces within each interpolation segment. Full expression parsing inside `{…}` is deferred to the parser, not the lexer.

## Design decisions

- Both `'...'` and `"..."` are valid with **identical** semantics because the runtime only has bash double-quoted strings; quote choice is ergonomic, not semantic.
- Templates use backticks and `{expr}` so interpolated values are explicit and easy to tokenize.
- Literals inside templates (e.g. `{42}`) are valid but redundant in many cases; they keep the interpolation grammar uniform.

## Caveats

- **Bash**: only double-quoted strings at runtime; no DSL escape sequences in `STRING_LIT`. Use the other quote kind or a template literal if the payload contains the same quote character.
- **Parser vs bash**: unclosed quotes in bash can yield partial tokens; the engine must fail with a clear parser error instead.

## Open questions

- **Multiline strings** (settled): `'''` and `"""` are multiline string literals. ` ``` ` is a multiline **template** literal (supports `{expr}` interpolation, same as single-backtick templates but spanning multiple lines and allowing embedded single backticks).

- **Dedentation** (deferred): Multiline string/template literals currently preserve content verbatim including leading whitespace. A future tier should strip the minimum indentation of non-empty lines (a la Kotlin `trimIndent`), likely in a parser or lowering pass rather than the lexer.

- **Top-level typed declarations** (settled — see [type-system.md](type-system.md)): multiline strings are a natural fit for top-level declarations — e.g. `@string NOTICE = '''...'''` as a private constant outside `env`.
