Skip to content

feat(sprintf): support full %q format specifications - #810

Open
Vitalii Tverdokhlib (vitaliytv) wants to merge 3 commits into
microsoft:mainfrom
vitaliytv:codex/sprintf-format-spec
Open

feat(sprintf): support full %q format specifications#810
Vitalii Tverdokhlib (vitaliytv) wants to merge 3 commits into
microsoft:mainfrom
vitaliytv:codex/sprintf-format-spec

Conversation

@vitaliytv

Copy link
Copy Markdown
Contributor

Depends on #809.

This follow-up completes %q support with a dedicated sprintf format-spec parser instead of extending the original PR's single-verb parsing incrementally.

What this adds

  • Parses Go-style flags, width, precision, dynamic * operands, and explicit argument indexes such as %[3]*.[2]*[1]q.
  • Supports %+q (QuoteToASCII behavior), %#q (backquoted strings when valid), left/right alignment, zero padding, and combined width/precision.
  • Applies width and precision in Unicode code points, matching Go/OPA rather than UTF-8 byte length.
  • Handles %q operands using OPA-compatible value conversion for strings, booleans, null, collections, integral runes, invalid runes, fractional numbers, and out-of-range integers.
  • Preserves the existing behavior of non-q verbs. Newly parsed flags that those verbs do not support are rejected explicitly.
  • Keeps width and precision bounded by the existing memory limit strategy.

Compatibility boundary

Regorus currently normalizes numbers into its internal Number variants and does not retain the original Rego numeric token spelling. OPA's %q behavior can depend on that spelling: for example, OPA distinguishes 65.0, 65e0, and 65, while Regorus may normalize them to different shared numeric variants. Exact parity for those lexical-number edge cases requires a separate change to the number representation; this PR does not disguise or broaden that architectural change.

The common %q matrix and parser edge cases were compared directly with OPA, including ASCII quoting, raw quoting and fallback, width/precision combinations, dynamic and indexed operands, runes, invalid runes, collections, and diagnostics.

Validation

  • Full repository pre-push suite passed.
  • cargo test: 298 passed, 2 ignored.
  • OPA compatibility suite: 2875 passed, 0 failed.
  • cargo test --locked --no-default-features --lib: 220 passed, 2 ignored.
  • cargo xtask test-no-std passed.
  • cargo clippy --locked --all-targets --all-features -- -D warnings passed.

This is intentionally stacked on #809. Until #809 is merged, GitHub's diff against main includes that prerequisite commit as well; afterward this PR reduces to the format-spec extension.

Go's `%q` verb (strconv.Quote) is used by OPA's sprintf, but regorus
currently bails on it unconditionally. Add support for `Value::String`
arguments only: wrap in double quotes, escape `"` and `\`, use the
short escapes for the common control characters (\a \b \f \n \r \t \v),
fall back to \xNN/\uNNNN/\UNNNNNNNN for other non-printable characters,
and leave printable (including non-ASCII) characters untouched. Unlike
json.marshal, %q does not HTML-escape < > &.

%q on non-string values (numbers, bools, etc.) still bails as before -
Go's %q on those produces different, single-quoted output that is out
of scope for this change.

Verified byte-for-byte against real OPA output (strconv.Quote
semantics) for quotes, backslashes, control characters, DEL, non-ASCII
printable text, and the < > & non-escaping case.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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.

1 participant