scrml.dev v0.7.1
Reference › Contexts

${ ... }

The logic context. Switches grammar from markup mode to expression / statement mode. Where reactive computation, control flow, and inline state writes happen.

Core since v0.1 SPEC §7 (normative)

Syntax

${ statementOrExpression }
${ @cell }
${ @count + 1 }
${ function name() { ... } }
${ if (cond) { ... } }

Inside a logic context, the grammar is statement-and- expression scrml. Outside (markup mode), text and elements are the grammar. ${...} is the universal switch from markup → logic; the closing } returns to markup. Inside logic, markup may re-open via element literals like <span>...</span> (markup-as-value per L1).

Worked example

A counter with derived computation, an event handler, and markup-as-value. Three uses of ${...} in one snippet.

<count> = 0
const <label> = ${ "Clicked " + @count + " times" }

<button onclick=${ @count = @count + 1 }>
  ${ @label }
</button>

<p>Last bump: ${ @count > 0 ? <strong>${@count}</strong> : "never" }</p>

The button's onclick=${...} wraps a single assignment statement; the body's ${@label} is a reactive interpolation; the the paragraph's ternary returns either markup (markup-as-value) or a string. Each use is a logic context the compiler tracks for dependency wiring.

Semantics

  • V5-strict access inside logic. @name reads or writes a reactive state cell; name (bare) resolves to a function-scoped local. Bare names NEVER resolve to reactive state — that is the load-bearing point of the @ marker.
  • Reactive interpolation tracks dependencies at compile time. Every ${ @cell } in markup-mode position subscribes the surrounding node to that cell. Writes to the cell trigger re-emit of exactly that node. No runtime diffing. Per SPEC §31 (Dependency Graph).
  • Statement vs expression position. ${...} in markup body position accepts statements (declarations, control flow, blocks) AND expressions. In attribute-value position (onclick=${...}), the body must be a single expression unless wrapped in a function (E-MULTI-STATEMENT-HANDLER on inline multi-statement). Per SPEC §5.2.3 + L19.
  • Markup-as-value is bidirectional. Inside a logic context, element literals (<div>...</div>) are first-class expressions. They can be passed as arguments, returned from functions, stored in cells. Per L1 (markup-as-first-class-value).
  • File-level logic context. A ${...} at file top level is the canonical place for module-scope declarations (function, fn, const, type, import). Hoisting per SPEC §6.9; pinned per §6.10.
  • Assignment is an expression. Per SPEC §50, @count = @count + 1 returns the assigned value. Useful for inline event handlers and lift accumulation. The composition with markup-as-value lands in §50.14.

Common errors from logic context misuse

Edge cases

  • Nested ${ <el>${...}</el> }. Logic can open markup which can open more logic. The compiler tokenizes brace depth per context; arbitrary nesting is legal. Per SPEC §7.7 (logic-markup interleaving canonical form, M8).
  • Bare names are locals, not state. The most common new-adopter mistake: ${ count } instead of ${ @count }. The first reads a function-local count; if no such local is in scope, fires E-SCOPE-001 with a "did you mean @count?" hint.
  • pure scope. pure marks a logic region that cannot read reactive state, cannot perform server-fn calls, cannot have failable effects. fn is the pure-function form (no implicit reactive deps). Per SPEC §33 + §48.
  • Comments. // line comments and /* ... */ block comments are valid inside logic contexts. The universal // line-comment form per SPEC §27 also works in markup mode.

Related contexts

  • ?{ ... } — SQL context. Per-handler coalescing, N+1 loop hoist, multi-database adaptation.
  • #{ ... } — CSS context. Inline styles + scoped classes. Reference page queued.
  • ^{ ... } — meta context. Compile-time code execution + splicing. Reference page queued.
  • _{ ... } — foreign code context. Level-marked braces; WASM / sidecar interop. Reference page queued.

Availability

Surface Since Notes
${} logic context Core since v0.1 The foundational context; SPEC §7
V5-strict access (@ + bare) v0.2.0 ratification SPEC §6.1 — bare names are locals only
Bare-form event handlers D4 (2026-05-04) SPEC §5.2.3 — single-expression discipline + E-MULTI-STATEMENT-HANDLER
Assignment as expression composes SPEC §50.14 / .15 Composes with markup-as-value (L1) + bare-form handlers (L19)

Specification

This page summarizes SPEC §7 (Logic Contexts), plus the V5-strict access discipline from §6.1 + §1.6. The normative text lives at compiler/SPEC.md in the scrmlTS repository.

Quick-lookup anchors: SPEC-INDEX.md entries — logic context, V5-strict access, markup-as-expr, file-level scope sharing, logic-markup interleaving, assignment as expression.