1use serde_json::{Map, Value};
2
3use super::{parse_error, unsupported_error, GrammarImportError};
4use crate::grammar::{CharClassItem, Grammar, GrammarExpr, GrammarFormat, GrammarRule, RuleKind};
5
6const FORMAT: GrammarFormat = GrammarFormat::TreeSitter;
7
8pub fn import_tree_sitter_json(text: &str) -> Result<Grammar, GrammarImportError> {
15 let value = serde_json::from_str::<Value>(text)
16 .map_err(|error| parse_error(FORMAT, error.to_string()))?;
17 let root = value
18 .as_object()
19 .ok_or_else(|| parse_error(FORMAT, "grammar.json root must be an object"))?;
20 let rules = required_object(root, "rules")?;
21 let rule_names = source_ordered_rule_names(text, rules)?;
22 if rule_names.is_empty() {
23 return Err(parse_error(FORMAT, "rules object must not be empty"));
24 }
25
26 let mut grammar = Grammar::new().with_source_format(FORMAT);
27 for name in rule_names {
28 let node = rules
29 .get(&name)
30 .ok_or_else(|| parse_error(FORMAT, format!("rule {name:?} is missing")))?;
31 grammar.add_rule(lower_rule(&name, node)?);
32 }
33
34 if let Some(start) = grammar.rules().first().map(|rule| rule.name.clone()) {
35 grammar.set_start(start);
36 }
37 if let Some(extras) = root.get("extras") {
38 if let Some(expr) = lower_extras(extras)? {
39 grammar.add_rule(GrammarRule::new("_extras", expr).with_kind(RuleKind::Silent));
40 }
41 }
42
43 Ok(grammar)
44}
45
46fn lower_rule(name: &str, node: &Value) -> Result<GrammarRule, GrammarImportError> {
47 match node_type(node)? {
48 "TOKEN" => Ok(GrammarRule::new(name, lower_content(node)?).with_kind(RuleKind::Token)),
49 "IMMEDIATE_TOKEN" => Ok(GrammarRule::new(
50 name,
51 GrammarExpr::capture("immediate_token", lower_content(node)?),
52 )
53 .with_kind(RuleKind::Token)),
54 _ => lower_node(node).map(|expr| GrammarRule::new(name, expr)),
55 }
56}
57
58fn lower_node(node: &Value) -> Result<GrammarExpr, GrammarImportError> {
59 match node_type(node)? {
60 "SYMBOL" => string_field(node, "name").map(GrammarExpr::NonTerminal),
61 "STRING" => string_field(node, "value").map(GrammarExpr::Terminal),
62 "PATTERN" => string_field(node, "value").map(|value| lower_pattern(&value)),
63 "BLANK" => Ok(GrammarExpr::Empty),
64 "SEQ" => lower_sequence(array_field(node, "members")?),
65 "CHOICE" => lower_choice(array_field(node, "members")?),
66 "REPEAT" => lower_content(node).map(GrammarExpr::zero_or_more),
67 "REPEAT1" => lower_content(node).map(GrammarExpr::one_or_more),
68 "PREC" => lower_precedence(node, "prec"),
69 "PREC_LEFT" => lower_precedence(node, "prec_left"),
70 "PREC_RIGHT" => lower_precedence(node, "prec_right"),
71 "PREC_DYNAMIC" => lower_precedence(node, "prec_dynamic"),
72 "TOKEN" => lower_content(node).map(|expr| GrammarExpr::capture("token", expr)),
73 "IMMEDIATE_TOKEN" => {
74 lower_content(node).map(|expr| GrammarExpr::capture("immediate_token", expr))
75 }
76 "FIELD" => {
77 let label = string_field(node, "name")?;
78 lower_content(node).map(|expr| GrammarExpr::capture(label, expr))
79 }
80 "ALIAS" => {
81 let value = string_field(node, "value")?;
82 lower_content(node).map(|expr| GrammarExpr::capture(format!("alias:{value}"), expr))
83 }
84 "RESERVED" => lower_reserved(node),
85 construct => Err(unsupported_error(FORMAT, construct)),
86 }
87}
88
89fn lower_sequence(members: &[Value]) -> Result<GrammarExpr, GrammarImportError> {
90 let mut lowered = Vec::new();
91 for member in members {
92 push_sequence_item(&mut lowered, lower_node(member)?);
93 }
94
95 Ok(match lowered.len() {
96 0 => GrammarExpr::Empty,
97 1 => lowered.remove(0),
98 _ => GrammarExpr::Sequence(lowered),
99 })
100}
101
102fn push_sequence_item(items: &mut Vec<GrammarExpr>, item: GrammarExpr) {
103 match item {
104 GrammarExpr::Empty => {}
105 GrammarExpr::Sequence(nested) => {
106 for item in nested {
107 push_sequence_item(items, item);
108 }
109 }
110 item => items.push(item),
111 }
112}
113
114fn lower_choice(members: &[Value]) -> Result<GrammarExpr, GrammarImportError> {
115 let mut alternatives = Vec::new();
116 for member in members {
117 alternatives.push(lower_node(member)?);
118 }
119
120 if alternatives.len() == 2 {
121 if alternatives[0] == GrammarExpr::Empty {
122 return Ok(GrammarExpr::optional(alternatives.remove(1)));
123 }
124 if alternatives[1] == GrammarExpr::Empty {
125 return Ok(GrammarExpr::optional(alternatives.remove(0)));
126 }
127 }
128
129 Ok(match alternatives.len() {
130 0 => GrammarExpr::Empty,
131 1 => alternatives.remove(0),
132 _ => GrammarExpr::Choice {
133 ordered: false,
134 alternatives,
135 },
136 })
137}
138
139fn lower_precedence(node: &Value, label: &str) -> Result<GrammarExpr, GrammarImportError> {
140 let value = precedence_value(node)?;
141 lower_content(node).map(|expr| GrammarExpr::capture(format!("{label}={value}"), expr))
142}
143
144fn lower_reserved(node: &Value) -> Result<GrammarExpr, GrammarImportError> {
145 let label = node
146 .get("context_name")
147 .and_then(Value::as_str)
148 .map_or_else(
149 || "reserved".to_string(),
150 |context| format!("reserved:{context}"),
151 );
152 lower_content(node).map(|expr| GrammarExpr::capture(label, expr))
153}
154
155fn lower_content(node: &Value) -> Result<GrammarExpr, GrammarImportError> {
156 lower_node(
157 node.as_object()
158 .and_then(|object| object.get("content"))
159 .ok_or_else(|| parse_error(FORMAT, "node is missing content"))?,
160 )
161}
162
163fn lower_extras(node: &Value) -> Result<Option<GrammarExpr>, GrammarImportError> {
164 let members = node
165 .as_array()
166 .ok_or_else(|| parse_error(FORMAT, "extras must be an array"))?;
167 if members.is_empty() {
168 return Ok(None);
169 }
170 lower_choice(members).map(Some)
171}
172
173fn lower_pattern(value: &str) -> GrammarExpr {
174 parse_char_class_pattern(value)
175 .unwrap_or_else(|| GrammarExpr::capture("regex", GrammarExpr::Terminal(value.to_string())))
176}
177
178fn parse_char_class_pattern(pattern: &str) -> Option<GrammarExpr> {
179 if !pattern.starts_with('[') || !pattern.ends_with(']') {
180 return None;
181 }
182 let content = &pattern[1..pattern.len() - 1];
183 let (negated, content) = content
184 .strip_prefix('^')
185 .map_or((false, content), |content| (true, content));
186 let chars = content.chars().collect::<Vec<_>>();
187 let mut items = Vec::new();
188 let mut index = 0;
189 while index < chars.len() {
190 let start = read_class_char(&chars, &mut index)?;
191 if index + 1 < chars.len() && chars[index] == '-' {
192 index += 1;
193 let end = read_class_char(&chars, &mut index)?;
194 if start > end {
195 return None;
196 }
197 items.push(CharClassItem::Range(start, end));
198 } else {
199 items.push(CharClassItem::Char(start));
200 }
201 }
202 if items.is_empty() {
203 return None;
204 }
205 Some(GrammarExpr::CharClass { negated, items })
206}
207
208fn read_class_char(chars: &[char], index: &mut usize) -> Option<char> {
209 let character = *chars.get(*index)?;
210 *index += 1;
211 if character != '\\' {
212 return Some(character);
213 }
214 let escaped = *chars.get(*index)?;
215 *index += 1;
216 match escaped {
217 'n' => Some('\n'),
218 'r' => Some('\r'),
219 't' => Some('\t'),
220 '\\' | '"' | '\'' | '[' | ']' | '-' | '^' => Some(escaped),
221 _ => None,
222 }
223}
224
225fn node_type(node: &Value) -> Result<&str, GrammarImportError> {
226 node.as_object()
227 .ok_or_else(|| parse_error(FORMAT, "grammar node must be an object"))?
228 .get("type")
229 .and_then(Value::as_str)
230 .ok_or_else(|| parse_error(FORMAT, "grammar node is missing string type"))
231}
232
233fn string_field(node: &Value, field: &str) -> Result<String, GrammarImportError> {
234 node.as_object()
235 .and_then(|object| object.get(field))
236 .and_then(Value::as_str)
237 .map(ToString::to_string)
238 .ok_or_else(|| parse_error(FORMAT, format!("node is missing string {field}")))
239}
240
241fn array_field<'node>(
242 node: &'node Value,
243 field: &str,
244) -> Result<&'node [Value], GrammarImportError> {
245 node.as_object()
246 .and_then(|object| object.get(field))
247 .and_then(Value::as_array)
248 .map(Vec::as_slice)
249 .ok_or_else(|| parse_error(FORMAT, format!("node is missing array {field}")))
250}
251
252fn precedence_value(node: &Value) -> Result<String, GrammarImportError> {
253 let value = node
254 .as_object()
255 .and_then(|object| object.get("value"))
256 .ok_or_else(|| parse_error(FORMAT, "precedence node is missing value"))?;
257 match value {
258 Value::Number(number) => Ok(number.to_string()),
259 Value::String(value) => Ok(value.clone()),
260 _ => Err(parse_error(
261 FORMAT,
262 "precedence value must be a number or string",
263 )),
264 }
265}
266
267fn required_object<'value>(
268 root: &'value Map<String, Value>,
269 field: &str,
270) -> Result<&'value Map<String, Value>, GrammarImportError> {
271 root.get(field)
272 .and_then(Value::as_object)
273 .ok_or_else(|| parse_error(FORMAT, format!("grammar.json must contain object {field}")))
274}
275
276fn source_ordered_rule_names(
277 text: &str,
278 rules: &Map<String, Value>,
279) -> Result<Vec<String>, GrammarImportError> {
280 let names = JsonScanner::new(text).top_level_object_keys("rules")?;
281 if names.len() != rules.len() || names.iter().any(|name| !rules.contains_key(name)) {
282 return Err(parse_error(
283 FORMAT,
284 "rules object in source text does not match parsed JSON object",
285 ));
286 }
287 Ok(names)
288}
289
290#[derive(Clone, Debug)]
291struct JsonScanner<'text> {
292 text: &'text str,
293 cursor: usize,
294}
295
296impl<'text> JsonScanner<'text> {
297 const fn new(text: &'text str) -> Self {
298 Self { text, cursor: 0 }
299 }
300
301 fn top_level_object_keys(mut self, property: &str) -> Result<Vec<String>, GrammarImportError> {
302 self.skip_whitespace();
303 self.consume_byte(b'{')?;
304 self.skip_whitespace();
305 if self.try_consume_byte(b'}') {
306 return Err(parse_error(FORMAT, format!("missing {property} object")));
307 }
308
309 loop {
310 let key = self.parse_string()?;
311 self.skip_whitespace();
312 self.consume_byte(b':')?;
313 self.skip_whitespace();
314 if key == property {
315 return self.object_keys();
316 }
317 self.skip_value()?;
318 self.skip_whitespace();
319 if self.try_consume_byte(b'}') {
320 return Err(parse_error(FORMAT, format!("missing {property} object")));
321 }
322 self.consume_byte(b',')?;
323 self.skip_whitespace();
324 }
325 }
326
327 fn object_keys(&mut self) -> Result<Vec<String>, GrammarImportError> {
328 self.consume_byte(b'{')?;
329 self.skip_whitespace();
330 let mut keys = Vec::new();
331 if self.try_consume_byte(b'}') {
332 return Ok(keys);
333 }
334
335 loop {
336 keys.push(self.parse_string()?);
337 self.skip_whitespace();
338 self.consume_byte(b':')?;
339 self.skip_whitespace();
340 self.skip_value()?;
341 self.skip_whitespace();
342 if self.try_consume_byte(b'}') {
343 return Ok(keys);
344 }
345 self.consume_byte(b',')?;
346 self.skip_whitespace();
347 }
348 }
349
350 fn skip_value(&mut self) -> Result<(), GrammarImportError> {
351 self.skip_whitespace();
352 match self.peek_byte() {
353 Some(b'"') => self.parse_string().map(|_| ()),
354 Some(b'{') => self.skip_object(),
355 Some(b'[') => self.skip_array(),
356 Some(_) => {
357 while let Some(byte) = self.peek_byte() {
358 if byte.is_ascii_whitespace() || matches!(byte, b',' | b'}' | b']') {
359 break;
360 }
361 self.cursor += 1;
362 }
363 Ok(())
364 }
365 None => Err(parse_error(FORMAT, "unexpected end of JSON value")),
366 }
367 }
368
369 fn skip_object(&mut self) -> Result<(), GrammarImportError> {
370 self.consume_byte(b'{')?;
371 self.skip_whitespace();
372 if self.try_consume_byte(b'}') {
373 return Ok(());
374 }
375 loop {
376 self.parse_string()?;
377 self.skip_whitespace();
378 self.consume_byte(b':')?;
379 self.skip_value()?;
380 self.skip_whitespace();
381 if self.try_consume_byte(b'}') {
382 return Ok(());
383 }
384 self.consume_byte(b',')?;
385 self.skip_whitespace();
386 }
387 }
388
389 fn skip_array(&mut self) -> Result<(), GrammarImportError> {
390 self.consume_byte(b'[')?;
391 self.skip_whitespace();
392 if self.try_consume_byte(b']') {
393 return Ok(());
394 }
395 loop {
396 self.skip_value()?;
397 self.skip_whitespace();
398 if self.try_consume_byte(b']') {
399 return Ok(());
400 }
401 self.consume_byte(b',')?;
402 self.skip_whitespace();
403 }
404 }
405
406 fn parse_string(&mut self) -> Result<String, GrammarImportError> {
407 self.skip_whitespace();
408 let start = self.cursor;
409 self.consume_byte(b'"')?;
410 let bytes = self.text.as_bytes();
411 while let Some(byte) = bytes.get(self.cursor).copied() {
412 self.cursor += 1;
413 match byte {
414 b'\\' => {
415 if self.cursor >= bytes.len() {
416 return Err(parse_error(FORMAT, "unterminated JSON string escape"));
417 }
418 self.cursor += 1;
419 }
420 b'"' => {
421 let text = &self.text[start..self.cursor];
422 return serde_json::from_str::<String>(text)
423 .map_err(|error| parse_error(FORMAT, error.to_string()));
424 }
425 _ => {}
426 }
427 }
428 Err(parse_error(FORMAT, "unterminated JSON string"))
429 }
430
431 fn skip_whitespace(&mut self) {
432 while self
433 .peek_byte()
434 .is_some_and(|byte| byte.is_ascii_whitespace())
435 {
436 self.cursor += 1;
437 }
438 }
439
440 fn consume_byte(&mut self, expected: u8) -> Result<(), GrammarImportError> {
441 self.skip_whitespace();
442 if self.try_consume_byte(expected) {
443 Ok(())
444 } else {
445 Err(parse_error(
446 FORMAT,
447 format!("expected JSON byte {:?}", char::from(expected)),
448 ))
449 }
450 }
451
452 fn try_consume_byte(&mut self, expected: u8) -> bool {
453 if self.peek_byte() == Some(expected) {
454 self.cursor += 1;
455 true
456 } else {
457 false
458 }
459 }
460
461 fn peek_byte(&self) -> Option<u8> {
462 self.text.as_bytes().get(self.cursor).copied()
463 }
464}