Skip to content

Accept bare IDENT in kind-qualified brackets (#119)#143

Merged
iskandr merged 1 commit intomasterfrom
bare-ident-brackets
Apr 24, 2026
Merged

Accept bare IDENT in kind-qualified brackets (#119)#143
iskandr merged 1 commit intomasterfrom
bare-ident-brackets

Conversation

@iskandr
Copy link
Copy Markdown
Contributor

@iskandr iskandr commented Apr 24, 2026

Summary

Closes #119 (step 1 only — step 2 labels deferred until there's real demand).

The string DSL now accepts bare identifiers inside kind-qualified brackets in addition to the quoted form:

```
affinity[netmhcpan] <= 500 # new
affinity[netmhcpan, "4.1b"] <= 500 # version keeps quotes (not an IDENT)
affinity['netmhcpan'] <= 500 # still parses
affinity['netmhcpan', '4.1b'].rank <= 2.0 # still parses
```

Motivated by YAML-embedded configs (e.g. vaxrank scoring YAML), where `"affinity[netmhcpan] <= 500"` is much easier to read than `"affinity['netmhcpan'] <= 500"` with nested quote escaping.

Changes

  • `_Tokenizer.expect_string_or_ident()` — bracket-arg primitive that accepts either a STRING or IDENT token and returns it. Wraps the exact shape of `expect()`.
  • `_postfix` (the chained `[...]` path) and `_kind_accessor` (the first-bracket path) now call the new helper at all four bracket-arg sites.
  • Grammar comment updated: `BRACKET_ARG := STRING | IDENT`.
  • `to_expr_string()` is unchanged — it still emits single-quoted canonical form, so round-trips and serialization are deterministic. The bare form is a read-only input sugar.

Back-compat

Fully additive. Every previously-valid expression still parses. Error surface for genuinely invalid bracket args is clearer: `parse("affinity[netmhcpan, 4]")` → `ValueError("Expected STRING or IDENT ...")` instead of the old `Expected STRING ...`.

Deferred (Step 2 of the issue)

Prometheus-style labels (`affinity[predictor=netmhcpan, version="4.1b"]`) are left out of this PR. They're the right escape hatch if positional order starts tripping users up, but Step 1 solves the immediate YAML ergonomics pain.

Test plan

  • `affinity[netmhcpan].score` parses to `Field(method="netmhcpan")`; AST-equal to the quoted form
  • `affinity[netmhcpan] <= 500` parses as a Comparison with qualified LHS
  • `affinity[netmhcpan, "4.1b"]` carries method + version through
  • Mixed forms in one bracket (`['netmhcpan', v4]`) work
  • Bare form composes with `.norm(...)` transforms
  • `to_expr_string()` → re-parse round-trip is AST-equal
  • `affinity[netmhcpan, 4]` (number inside bracket) raises `STRING or IDENT`
  • Full suite: `pytest tests/` → 1187 passed, 3 skipped

- Parser accepts affinity[netmhcpan] in addition to
  affinity['netmhcpan']; both forms produce the same AST. Non-IDENT
  values (e.g. "4.1b") still require quotes.
- New Tokenizer.expect_string_or_ident helper drives the four
  bracket-arg sites in _postfix and _kind_accessor.
- to_expr_string keeps emitting the canonical single-quoted form so
  round-trips stay deterministic.
- Grammar comment updated.
@iskandr iskandr force-pushed the bare-ident-brackets branch from 2e9716e to 0166dc4 Compare April 24, 2026 18:55
@coveralls
Copy link
Copy Markdown

Coverage Status

coverage: 88.837% (+0.2%) from 88.589% — bare-ident-brackets into master

@iskandr iskandr merged commit e047ad8 into master Apr 24, 2026
8 checks passed
@iskandr iskandr deleted the bare-ident-brackets branch April 24, 2026 19:10
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.

Accept bare IDENT in kind-qualified brackets (two-step: bare idents now, Prometheus labels later)

2 participants