diff --git a/examples/json-schema-to-grammar.py b/examples/json-schema-to-grammar.py index 73baa0d4f..e66a948a5 100755 --- a/examples/json-schema-to-grammar.py +++ b/examples/json-schema-to-grammar.py @@ -299,6 +299,10 @@ class SchemaConverter: self._refs_being_resolved.remove(ref) return ref_name + def _generate_constant_rule(self, value): + assert isinstance(value, str), f'Only string constants are supported, got {value}' + return self._format_literal(value) + def visit(self, schema, name): schema_type = schema.get('type') schema_format = schema.get('format') @@ -314,10 +318,10 @@ class SchemaConverter: return self._add_rule(rule_name, self._generate_union_rule(name, [{'type': t} for t in schema_type])) elif 'const' in schema: - return self._add_rule(rule_name, self._format_literal(schema['const'])) + return self._add_rule(rule_name, self._generate_constant_rule(schema['const'])) elif 'enum' in schema: - rule = ' | '.join((self._format_literal(v) for v in schema['enum'])) + rule = ' | '.join((self._generate_constant_rule(v) for v in schema['enum'])) return self._add_rule(rule_name, rule) elif schema_type in (None, 'object') and ('properties' in schema or 'additionalProperties' in schema): diff --git a/examples/server/json-schema-to-grammar.cpp b/examples/server/json-schema-to-grammar.cpp index e74712cc5..79046ffa7 100644 --- a/examples/server/json-schema-to-grammar.cpp +++ b/examples/server/json-schema-to-grammar.cpp @@ -547,6 +547,14 @@ public: visit_refs(schema); } + string _generate_constant_rule(const json& value) { + if (!value.is_string()) { + _errors.push_back("Only string constants are supported, got " + value.dump()); + return ""; + } + return _format_literal(value.get()); + } + string visit(const json& schema, const string& name) { json schema_type = schema.contains("type") ? schema["type"] : json(); string schema_format = schema.contains("format") ? schema["format"].get() : ""; @@ -564,11 +572,11 @@ public: } return _add_rule(rule_name, _generate_union_rule(name, schema_types)); } else if (schema.contains("const")) { - return _add_rule(rule_name, _format_literal(schema["const"].dump())); + return _add_rule(rule_name, _generate_constant_rule(schema["const"])); } else if (schema.contains("enum")) { vector enum_values; for (const auto& v : schema["enum"]) { - enum_values.push_back(_format_literal(v.dump())); + enum_values.push_back(_generate_constant_rule(v)); } return _add_rule(rule_name, join(enum_values.begin(), enum_values.end(), " | ")); } else if ((schema_type.is_null() || schema_type == "object") diff --git a/examples/server/public/json-schema-to-grammar.mjs b/examples/server/public/json-schema-to-grammar.mjs index 952c38647..1db99de6c 100644 --- a/examples/server/public/json-schema-to-grammar.mjs +++ b/examples/server/public/json-schema-to-grammar.mjs @@ -325,6 +325,13 @@ export class SchemaConverter { return refName; } + _generateConstantRule(value) { + if (typeof value !== 'string') { + throw new Error('Only string constants are supported, got ' + JSON.stringify(value)); + } + return this._formatLiteral(value); + } + visit(schema, name) { const schemaType = schema.type; const schemaFormat = schema.format; @@ -338,9 +345,12 @@ export class SchemaConverter { } else if (Array.isArray(schemaType)) { return this._addRule(ruleName, this._generateUnionRule(name, schemaType.map(t => ({ type: t })))); } else if ('const' in schema) { - return this._addRule(ruleName, this._formatLiteral(schema.const)); + if (typeof schema.const !== 'string') { + throw new Error('Only string constants are supported, got ' + JSON.stringify(schema.const)); + } + return this._addRule(ruleName, this._generateConstantRule(schema.const)); } else if ('enum' in schema) { - const rule = schema.enum.map(v => this._formatLiteral(v)).join(' | '); + const rule = schema.enum.map(v => this._generateConstantRule(v)).join(' | '); return this._addRule(ruleName, rule); } else if ((schemaType === undefined || schemaType === 'object') && ('properties' in schema || 'additionalProperties' in schema)) { const required = new Set(schema.required || []); diff --git a/tests/test-json-schema-to-grammar.cpp b/tests/test-json-schema-to-grammar.cpp index 63a637add..450d0233b 100755 --- a/tests/test-json-schema-to-grammar.cpp +++ b/tests/test-json-schema-to-grammar.cpp @@ -155,6 +155,36 @@ static void test_all(const string& lang, std::function ru )""" }); + test({ + SUCCESS, + "string const", + R"""({ + "const": "foo" + })""", + R"""( + root ::= "\"foo\"" + space ::= " "? + )""" + }); + + test({ + FAILURE, + "non-string const", + R"""({ + "const": 123 + })""", + "" + }); + + test({ + FAILURE, + "non-string enum", + R"""({ + "enum": [123] + })""", + "" + }); + test({ SUCCESS, "tuple1",