Invisible link to canonical for Microformats

ADR-038 Structural Brace Disambiguation for Maps and Blocks


Status

Accepted

Context

Slug currently uses { ... } syntax for both map literals and executable blocks.

Historically the parser has treated brace forms after constructs such as match arms as blocks by default, which led to awkward syntax when returning maps directly from expression positions:

match value {
  :ok  => 
  :err => 
}

This created several issues:

  • Reduced readability and visual clarity
  • Poor ergonomics for nested maps
  • Confusing semantics for both humans and AI systems
  • Prevented blocks from naturally behaving as scoped expressions
  • Forced users to learn a special-case parser escape hatch

At the same time, Slug increasingly benefits from expression-oriented semantics:

val result = {
  val x = compute()
  x * 2
}

This style aligns with Slug’s existing goals around:

  • expression-oriented design
  • immutable values
  • lexical scoping
  • recursion-first control flow
  • pipeline-friendly composition

The existing parser behavior prevented this from working naturally because brace forms were biased toward map parsing in many positions.

Decision

Slug will structurally disambiguate brace forms during parsing.

Map literals

A brace form is parsed as a map literal when its contents structurally match map entries:

{ a: 1 }
{ name: "knuckles", age: 42 }
{}

The empty brace form {} is always an empty map.

Blocks

A brace form is parsed as a block expression when its contents contain statements or expressions rather than map entries:

{
  val x = compute()
  x * 2
}

Blocks remain scoped expressions and create lexical scope boundaries.

Existing nested map behavior

The previous:


syntax was not a special language construct.

It was simply a block expression containing a nested map literal.

The underlying issue was that in some expression positions, particularly match arms, a form such as:

{ a: 1 }

would parse as a block rather than a map literal.

This ADR corrects that behavior through general structural brace disambiguation.

As a result, maps may now be returned directly from expression positions:

match value {
  :ok  => { result: true }
  :err => { error: "failed" }
}

Parser behavior

The parser determines brace meaning structurally:

{}                  -> empty map
{ key: value }      -> map literal
{ statements... }   -> block expression

No evaluator or runtime semantic changes are required.

Consequences

Positive

  • Removes the awkward `` syntax
  • Greatly improves readability of match arms and expression returns
  • Unlocks proper scoped block expressions
  • Makes Slug more expression-oriented
  • Improves AI code generation reliability
  • Aligns parser behavior with human visual intuition
  • Keeps lightweight map literal syntax
  • Requires only parser-level changes

Negative

  • Introduces structural parsing rules for brace forms
  • Some malformed brace forms may produce less obvious parser errors
  • Existing code using `` must be migrated

Neutral

  • Blocks continue to create lexical scopes
  • Maps remain immutable values
  • No evaluator or runtime changes are required
  • No changes to map semantics or block semantics
  • Empty brace forms now unambiguously represent empty maps