Skip to content

Commit 0874693

Browse files
authored
common : fix json schema with '\' in literals (#17307)
* Fix json schema with '\' in literals * Add "literal string with escapes" test
1 parent 7d2add5 commit 0874693

File tree

4 files changed

+32
-6
lines changed

4 files changed

+32
-6
lines changed

common/json-schema-to-grammar.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -268,10 +268,10 @@ static bool is_reserved_name(const std::string & name) {
268268
}
269269

270270
std::regex INVALID_RULE_CHARS_RE("[^a-zA-Z0-9-]+");
271-
std::regex GRAMMAR_LITERAL_ESCAPE_RE("[\r\n\"]");
271+
std::regex GRAMMAR_LITERAL_ESCAPE_RE("[\r\n\"\\\\]");
272272
std::regex GRAMMAR_RANGE_LITERAL_ESCAPE_RE("[\r\n\"\\]\\-\\\\]");
273273
std::unordered_map<char, std::string> GRAMMAR_LITERAL_ESCAPES = {
274-
{'\r', "\\r"}, {'\n', "\\n"}, {'"', "\\\""}, {'-', "\\-"}, {']', "\\]"}
274+
{'\r', "\\r"}, {'\n', "\\n"}, {'"', "\\\""}, {'-', "\\-"}, {']', "\\]"}, {'\\', "\\\\"}
275275
};
276276

277277
std::unordered_set<char> NON_LITERAL_SET = {'|', '.', '(', ')', '[', ']', '{', '}', '*', '+', '?'};

examples/json_schema_to_grammar.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -231,9 +231,9 @@ def __init__(self, content: str, deps: list | None = None):
231231
RESERVED_NAMES = set(["root", "dot", *PRIMITIVE_RULES.keys(), *STRING_FORMAT_RULES.keys()])
232232

233233
INVALID_RULE_CHARS_RE = re.compile(r'[^a-zA-Z0-9-]+')
234-
GRAMMAR_LITERAL_ESCAPE_RE = re.compile(r'[\r\n"]')
234+
GRAMMAR_LITERAL_ESCAPE_RE = re.compile(r'[\r\n"\\]')
235235
GRAMMAR_RANGE_LITERAL_ESCAPE_RE = re.compile(r'[\r\n"\]\-\\]')
236-
GRAMMAR_LITERAL_ESCAPES = {'\r': '\\r', '\n': '\\n', '"': '\\"', '-': '\\-', ']': '\\]'}
236+
GRAMMAR_LITERAL_ESCAPES = {'\r': '\\r', '\n': '\\n', '"': '\\"', '-': '\\-', ']': '\\]', '\\': '\\\\'}
237237

238238
NON_LITERAL_SET = set('|.()[]{}*+?')
239239
ESCAPED_IN_REGEXPS_BUT_NOT_IN_LITERALS = set('^$.[]()|{}*+?')

tests/test-json-schema-to-grammar.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1339,6 +1339,32 @@ static void test_all(const std::string & lang, std::function<void(const TestCase
13391339
space ::= | " " | "\n"{1,2} [ \t]{0,20}
13401340
)"""
13411341
});
1342+
1343+
test({
1344+
SUCCESS,
1345+
"literal string with escapes",
1346+
R"""({
1347+
"properties": {
1348+
"code": {
1349+
"const": " \r \n \" \\ ",
1350+
"description": "Generated code",
1351+
"title": "Code",
1352+
"type": "string"
1353+
}
1354+
},
1355+
"required": [
1356+
"code"
1357+
],
1358+
"title": "DecoderResponse",
1359+
"type": "object"
1360+
})""",
1361+
R"""(
1362+
code ::= "\" \\r \\n \\\" \\\\ \"" space
1363+
code-kv ::= "\"code\"" space ":" space code
1364+
root ::= "{" space code-kv "}" space
1365+
space ::= | " " | "\n"{1,2} [ \t]{0,20}
1366+
)"""
1367+
});
13421368
}
13431369

13441370
int main() {

tools/server/public_legacy/json-schema-to-grammar.mjs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -257,9 +257,9 @@ const STRING_FORMAT_RULES = {
257257
const RESERVED_NAMES = {'root': true, ...PRIMITIVE_RULES, ...STRING_FORMAT_RULES};
258258

259259
const INVALID_RULE_CHARS_RE = /[^\dA-Za-z-]+/g;
260-
const GRAMMAR_LITERAL_ESCAPE_RE = /[\n\r"]/g;
260+
const GRAMMAR_LITERAL_ESCAPE_RE = /[\n\r"\\]/g;
261261
const GRAMMAR_RANGE_LITERAL_ESCAPE_RE = /[\n\r"\]\-\\]/g;
262-
const GRAMMAR_LITERAL_ESCAPES = { '\r': '\\r', '\n': '\\n', '"': '\\"', '-': '\\-', ']': '\\]' };
262+
const GRAMMAR_LITERAL_ESCAPES = { '\r': '\\r', '\n': '\\n', '"': '\\"', '-': '\\-', ']': '\\]', '\\': '\\\\' };
263263

264264
const NON_LITERAL_SET = new Set('|.()[]{}*+?');
265265
const ESCAPED_IN_REGEXPS_BUT_NOT_IN_LITERALS = new Set('^$.[]()|{}*+?');

0 commit comments

Comments
 (0)