Skip to content

fix: std.format %c rejects multi-character strings#1015

Open
He-Pin wants to merge 2 commits into
databricks:masterfrom
He-Pin:fix/format-c-single-char
Open

fix: std.format %c rejects multi-character strings#1015
He-Pin wants to merge 2 commits into
databricks:masterfrom
He-Pin:fix/format-c-single-char

Conversation

@He-Pin

@He-Pin He-Pin commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

fix: std.format %c rejects multi-character strings

Motivation

The %c format specifier should only accept a single-character string or a numeric codepoint. sjsonnet silently accepted multi-character strings (e.g. "%c" % "AB""AB"), while C++ jsonnet, go-jsonnet, and jrsonnet all correctly reject them.

Modification

  • Format.scala: When %c receives a Val.Str, validate codepoint count is exactly 1 using codePointCount. Multi-char or empty strings raise "%c expected 1-sized string got: N", matching C++ jsonnet's error format.
  • Added regression tests: error.format_c_multi_char_string.jsonnet, error.format_c_empty_string.jsonnet

Result

"%c" % "AB" and "%c" % "" now correctly error, matching all reference implementations.

Expression cpp-jsonnet go-jsonnet jrsonnet sjsonnet (before) sjsonnet (after)
"%c" % "A" "A" "A" "A" "A" "A"
"%c" % "AB" ERROR ERROR ERROR "AB" ERROR ✅
"%c" % "" ERROR ERROR ERROR "" ERROR ✅
"%c" % 65 "A" "A" "A" "A" "A"

He-Pin added 2 commits June 24, 2026 11:16
Motivation:
The %c format specifier should only accept a single-character string
or a numeric codepoint. sjsonnet silently accepted multi-character
strings (e.g. "%c" % "AB" → "AB"), while C++ jsonnet, go-jsonnet,
and jrsonnet all correctly reject them with an error.

Modification:
- Format.scala: When %c receives a Val.Str, validate it contains
  exactly 1 codepoint. Raise "%c expected 1-sized string got: N"
  if the codepoint count is != 1, matching C++ jsonnet's error
  format.

Result:
"%c" % "AB" now correctly errors instead of silently returning "AB".

Cross-implementation comparison:
| Expression        | C++ jsonnet           | go-jsonnet | jrsonnet                     | sjsonnet (before) | sjsonnet (after)            |
|-------------------|-----------------------|------------|------------------------------|-------------------|-----------------------------|
| "%c" % "A"        | "A"                   | "A"        | "A"                          | "A"               | "A"                         |
| "%c" % "AB"       | ERROR: 1-sized string | ERROR      | ERROR: 1 char string got 2   | "AB" ❌           | ERROR: 1-sized string ✅    |
| "%c" % ""         | ERROR                 | ERROR      | ERROR: 1 char string got 0   | "" ❌             | ERROR: 1-sized string ✅    |
| "%c" % 65         | "A"                   | "A"        | "A"                          | "A"               | "A"                         |
| "%c" % "世"       | "世"                  | "世"       | "世"                         | "世"              | "世"                        |
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