Skip to main content

meta_language/grammar/interchange/
json.rs

1//! The serialized JSON form of a grammar: `{schemaVersion: 1, start,
2//! sourceFormat, rules, declarations?}` written with two-space indentation and
3//! the key order of `Grammar.normalized()` in `js/src/grammar.js`, so both
4//! runtimes write the same bytes for the same grammar and read each other's
5//! documents.
6
7use serde_json::Value;
8
9use super::super::feature::{class_expression, feature_expression_fields, operation_form};
10use super::super::{
11    ByteClassItem, CharClassItem, FeatureExpr, FeatureForm, FieldType, FieldValue, Grammar,
12    GrammarDeclarations, GrammarExpr, GrammarFormat, GrammarImportError, GrammarMacro, GrammarRule,
13    GrammarScanner, Operation, OperationCategory, PrecedenceEntry, RuleAttributes, RuleKind,
14    UnicodeClassItem,
15};
16
17/// A JSON value whose objects keep their key order.
18enum Json {
19    Null,
20    Bool(bool),
21    Int(i64),
22    Str(String),
23    Array(Vec<Self>),
24    Object(Vec<(&'static str, Self)>),
25}
26
27impl Json {
28    fn str(value: &str) -> Self {
29        Self::Str(value.to_owned())
30    }
31
32    fn strings(values: &[String]) -> Self {
33        Self::Array(values.iter().map(|value| Self::str(value)).collect())
34    }
35
36    fn render(&self, indent: usize, out: &mut String) {
37        match self {
38            Self::Null => out.push_str("null"),
39            Self::Bool(value) => out.push_str(if *value { "true" } else { "false" }),
40            Self::Int(value) => out.push_str(&value.to_string()),
41            Self::Str(value) => {
42                out.push_str(&serde_json::to_string(value).unwrap_or_default());
43            }
44            Self::Array(items) if items.is_empty() => out.push_str("[]"),
45            Self::Object(entries) if entries.is_empty() => out.push_str("{}"),
46            Self::Array(items) => {
47                out.push('[');
48                for (index, item) in items.iter().enumerate() {
49                    out.push_str(if index == 0 { "\n" } else { ",\n" });
50                    push_indent(indent + 1, out);
51                    item.render(indent + 1, out);
52                }
53                out.push('\n');
54                push_indent(indent, out);
55                out.push(']');
56            }
57            Self::Object(entries) => {
58                out.push('{');
59                for (index, (key, value)) in entries.iter().enumerate() {
60                    out.push_str(if index == 0 { "\n" } else { ",\n" });
61                    push_indent(indent + 1, out);
62                    out.push('"');
63                    out.push_str(key);
64                    out.push_str("\": ");
65                    value.render(indent + 1, out);
66                }
67                out.push('\n');
68                push_indent(indent, out);
69                out.push('}');
70            }
71        }
72    }
73}
74
75fn push_indent(indent: usize, out: &mut String) {
76    for _ in 0..indent {
77        out.push_str("  ");
78    }
79}
80
81fn int(value: usize) -> Json {
82    Json::Int(i64::try_from(value).unwrap_or(i64::MAX))
83}
84
85fn char_json(value: char) -> Json {
86    Json::Str(value.to_string())
87}
88
89fn unary(kind: &'static str, item: &GrammarExpr) -> Json {
90    Json::Object(vec![
91        ("kind", Json::str(kind)),
92        ("item", expression_json(item)),
93    ])
94}
95
96fn class_json(kind: &'static str, negated: bool, items: Vec<Json>) -> Json {
97    Json::Object(vec![
98        ("kind", Json::str(kind)),
99        ("negated", Json::Bool(negated)),
100        ("items", Json::Array(items)),
101    ])
102}
103
104fn char_item_json(item: &CharClassItem) -> Json {
105    match item {
106        CharClassItem::Char(value) => Json::Object(vec![
107            ("kind", Json::str("char")),
108            ("value", char_json(*value)),
109        ]),
110        CharClassItem::Range(start, end) => Json::Object(vec![
111            ("kind", Json::str("range")),
112            ("start", char_json(*start)),
113            ("end", char_json(*end)),
114        ]),
115    }
116}
117
118fn expressions_json(items: &[GrammarExpr]) -> Json {
119    Json::Array(items.iter().map(expression_json).collect())
120}
121
122fn expression_json(expr: &GrammarExpr) -> Json {
123    let kind = |kind: &str| ("kind", Json::str(kind));
124    match expr {
125        GrammarExpr::Empty => Json::Object(vec![kind("empty")]),
126        GrammarExpr::AnyChar => Json::Object(vec![kind("any")]),
127        GrammarExpr::Terminal(value) => {
128            Json::Object(vec![kind("literal"), ("value", Json::str(value))])
129        }
130        GrammarExpr::TerminalInsensitive(value) => Json::Object(vec![
131            kind("literalInsensitive"),
132            ("value", Json::str(value)),
133        ]),
134        GrammarExpr::CharRange(start, end) => Json::Object(vec![
135            kind("charRange"),
136            ("start", char_json(*start)),
137            ("end", char_json(*end)),
138        ]),
139        GrammarExpr::CharClass { negated, items } => class_json(
140            "charClass",
141            *negated,
142            items.iter().map(char_item_json).collect(),
143        ),
144        GrammarExpr::NonTerminal(name) => {
145            Json::Object(vec![kind("ref"), ("name", Json::str(name))])
146        }
147        GrammarExpr::Choice {
148            ordered,
149            alternatives,
150        } => Json::Object(vec![
151            kind("choice"),
152            ("items", expressions_json(alternatives)),
153            ("ordered", Json::Bool(*ordered)),
154        ]),
155        GrammarExpr::Sequence(items) => {
156            Json::Object(vec![kind("seq"), ("items", expressions_json(items))])
157        }
158        GrammarExpr::Optional(item) => unary("optional", item),
159        GrammarExpr::ZeroOrMore(item) => unary("repeat0", item),
160        GrammarExpr::OneOrMore(item) => unary("repeat1", item),
161        GrammarExpr::And(item) => unary("and", item),
162        GrammarExpr::Not(item) => unary("not", item),
163        GrammarExpr::Repeat { expr, min, max } => Json::Object(vec![
164            kind("repeat"),
165            ("item", expression_json(expr)),
166            ("min", int(*min)),
167            ("max", max.map_or(Json::Null, int)),
168        ]),
169        GrammarExpr::Capture { label, expr } => Json::Object(vec![
170            kind("capture"),
171            ("label", label.as_deref().map_or(Json::Null, Json::str)),
172            ("item", expression_json(expr)),
173        ]),
174        GrammarExpr::Feature(feature) => feature_json(feature),
175    }
176}
177
178fn feature_json(feature: &FeatureExpr) -> Json {
179    match feature {
180        FeatureExpr::UnicodeClass { negated, items } => class_json(
181            "charClass",
182            *negated,
183            items
184                .iter()
185                .map(|item| match item {
186                    UnicodeClassItem::Char(value) => char_item_json(&CharClassItem::Char(*value)),
187                    UnicodeClassItem::Range(start, end) => {
188                        char_item_json(&CharClassItem::Range(*start, *end))
189                    }
190                    UnicodeClassItem::Category(value) => Json::Object(vec![
191                        ("kind", Json::str("category")),
192                        ("value", Json::str(value)),
193                    ]),
194                    UnicodeClassItem::Script(value) => Json::Object(vec![
195                        ("kind", Json::str("script")),
196                        ("value", Json::str(value)),
197                    ]),
198                })
199                .collect(),
200        ),
201        FeatureExpr::ByteClass { negated, items } => class_json(
202            "byteClass",
203            *negated,
204            items
205                .iter()
206                .map(|item| match item {
207                    ByteClassItem::Byte(value) => Json::Object(vec![
208                        ("kind", Json::str("byte")),
209                        ("value", Json::Int(i64::from(*value))),
210                    ]),
211                    ByteClassItem::Range(start, end) => Json::Object(vec![
212                        ("kind", Json::str("byteRange")),
213                        ("start", Json::Int(i64::from(*start))),
214                        ("end", Json::Int(i64::from(*end))),
215                    ]),
216                })
217                .collect(),
218        ),
219        FeatureExpr::Call { name, arguments } => Json::Object(vec![
220            ("kind", Json::str("ref")),
221            ("name", Json::str(name)),
222            ("arguments", expressions_json(arguments)),
223        ]),
224        FeatureExpr::Form(form) => form_json("kind", form),
225    }
226}
227
228/// A feature form or an operation: its head under `head_key`, then its fields.
229fn form_json(head_key: &'static str, form: &FeatureForm) -> Json {
230    let mut entries = vec![(head_key, Json::str(&form.head))];
231    for ((key, _), value) in form.spec().iter().zip(&form.fields) {
232        let value = match value {
233            FieldValue::Word(text) | FieldValue::Name(text) | FieldValue::Text(text) => {
234                Json::str(text)
235            }
236            FieldValue::Integer(value) => Json::Int(*value),
237            FieldValue::Expression(expr) => expression_json(expr),
238            FieldValue::Expressions(items) => expressions_json(items),
239            FieldValue::Operation(operation) => operation_json(operation),
240            FieldValue::Operations(items) | FieldValue::Block(Some(items)) => {
241                operations_json(items)
242            }
243            FieldValue::Block(None) => continue,
244        };
245        entries.push((key, value));
246    }
247    Json::Object(entries)
248}
249
250fn operation_json(operation: &Operation) -> Json {
251    form_json("operation", operation)
252}
253
254fn operations_json(operations: &[Operation]) -> Json {
255    Json::Array(operations.iter().map(operation_json).collect())
256}
257
258fn rule_json(rule: &GrammarRule) -> Json {
259    let mut entries = vec![
260        ("name", Json::str(&rule.name)),
261        ("kind", Json::str(rule.kind.as_str())),
262        ("expression", expression_json(&rule.expr)),
263    ];
264    let attributes = &rule.attributes;
265    if !attributes.parameters.is_empty() {
266        entries.push(("parameters", Json::strings(&attributes.parameters)));
267    }
268    if let Some(channel) = &attributes.channel {
269        entries.push(("channel", Json::str(channel)));
270    }
271    if let Some(modes) = &attributes.modes {
272        entries.push(("modes", Json::strings(modes)));
273    }
274    if let Some(action) = &attributes.action {
275        entries.push(("action", operations_json(action)));
276    }
277    Json::Object(entries)
278}
279
280fn declarations_json(declarations: &GrammarDeclarations) -> Json {
281    let mut entries = Vec::new();
282    if let Some(matching) = &declarations.matching {
283        entries.push(("matching", Json::str(matching)));
284    }
285    if let Some(settling) = &declarations.settling {
286        entries.push(("settling", Json::strings(settling)));
287    }
288    if !declarations.imports.is_empty() {
289        entries.push(("imports", Json::strings(&declarations.imports)));
290    }
291    if !declarations.modes.is_empty() {
292        entries.push(("modes", Json::strings(&declarations.modes)));
293    }
294    if !declarations.extras.is_empty() {
295        entries.push(("extras", expressions_json(&declarations.extras)));
296    }
297    if !declarations.conflicts.is_empty() {
298        let groups = declarations
299            .conflicts
300            .iter()
301            .map(|group| Json::strings(group));
302        entries.push(("conflicts", Json::Array(groups.collect())));
303    }
304    if !declarations.precedences.is_empty() {
305        let orders = declarations.precedences.iter().map(|order| {
306            Json::Array(
307                order
308                    .iter()
309                    .map(|entry| {
310                        Json::Object(vec![
311                            ("kind", Json::str(entry.kind())),
312                            ("value", Json::str(entry.value())),
313                        ])
314                    })
315                    .collect(),
316            )
317        });
318        entries.push(("precedences", Json::Array(orders.collect())));
319    }
320    if !declarations.macros.is_empty() {
321        let macros = declarations.macros.iter().map(|declared| {
322            Json::Object(vec![
323                ("name", Json::str(&declared.name)),
324                ("parameters", Json::strings(&declared.parameters)),
325                ("expression", expression_json(&declared.expression)),
326            ])
327        });
328        entries.push(("macros", Json::Array(macros.collect())));
329    }
330    if !declarations.scanners.is_empty() {
331        let scanners = declarations.scanners.iter().map(|scanner| {
332            Json::Object(vec![
333                ("name", Json::str(&scanner.name)),
334                ("tokens", Json::strings(&scanner.tokens)),
335                ("operations", operations_json(&scanner.operations)),
336            ])
337        });
338        entries.push(("scanners", Json::Array(scanners.collect())));
339    }
340    Json::Object(entries)
341}
342
343/// Serializes `grammar` as `JSON.stringify(grammar.normalized(), null, 2)`
344/// followed by a newline, as `serializeGrammar` of `js/src/grammar.js` does.
345#[must_use]
346pub fn serialize_grammar(grammar: &Grammar) -> String {
347    let mut entries = vec![
348        ("schemaVersion", Json::Int(1)),
349        ("start", grammar.start().map_or(Json::Null, Json::str)),
350        (
351            "sourceFormat",
352            grammar
353                .source_format()
354                .map_or(Json::Null, |format| Json::str(format.as_str())),
355        ),
356        (
357            "rules",
358            Json::Array(grammar.rules().iter().map(rule_json).collect()),
359        ),
360    ];
361    if !grammar.declarations().is_empty() {
362        entries.push(("declarations", declarations_json(grammar.declarations())));
363    }
364    let mut out = String::new();
365    Json::Object(entries).render(0, &mut out);
366    out.push('\n');
367    out
368}
369
370fn json_error(detail: impl Into<String>) -> GrammarImportError {
371    GrammarImportError::Parse {
372        format: GrammarFormat::MetaLanguage,
373        message: detail.into(),
374    }
375}
376
377fn invalid(what: &str) -> GrammarImportError {
378    json_error(format!("invalid serialized grammar {what}"))
379}
380
381fn field<'a>(value: &'a Value, key: &str, what: &str) -> Result<&'a Value, GrammarImportError> {
382    value.get(key).ok_or_else(|| invalid(what))
383}
384
385fn string(value: &Value, key: &str, what: &str) -> Result<String, GrammarImportError> {
386    field(value, key, what)?
387        .as_str()
388        .map(str::to_owned)
389        .ok_or_else(|| invalid(what))
390}
391
392fn optional_string(
393    value: &Value,
394    key: &str,
395    what: &str,
396) -> Result<Option<String>, GrammarImportError> {
397    match value.get(key) {
398        None | Some(Value::Null) => Ok(None),
399        Some(Value::String(text)) => Ok(Some(text.clone())),
400        Some(_) => Err(invalid(what)),
401    }
402}
403
404fn strings(value: Option<&Value>, what: &str) -> Result<Vec<String>, GrammarImportError> {
405    match value {
406        None | Some(Value::Null) => Ok(Vec::new()),
407        Some(Value::Array(items)) => items
408            .iter()
409            .map(|item| {
410                item.as_str()
411                    .map(str::to_owned)
412                    .ok_or_else(|| invalid(what))
413            })
414            .collect(),
415        Some(_) => Err(invalid(what)),
416    }
417}
418
419fn array<'a>(value: &'a Value, key: &str, what: &str) -> Result<&'a [Value], GrammarImportError> {
420    field(value, key, what)?
421        .as_array()
422        .map(Vec::as_slice)
423        .ok_or_else(|| invalid(what))
424}
425
426fn character(value: &Value, key: &str) -> Result<char, GrammarImportError> {
427    let text = string(value, key, "expression")?;
428    let mut chars = text.chars();
429    match (chars.next(), chars.next()) {
430        (Some(value), None) => Ok(value),
431        _ => Err(invalid("expression")),
432    }
433}
434
435fn integer(value: &Value, key: &str, what: &str) -> Result<i64, GrammarImportError> {
436    field(value, key, what)?
437        .as_i64()
438        .ok_or_else(|| invalid(what))
439}
440
441fn count(value: &Value, key: &str) -> Result<usize, GrammarImportError> {
442    usize::try_from(integer(value, key, "expression")?).map_err(|_| invalid("expression"))
443}
444
445fn byte(value: &Value, key: &str) -> Result<u8, GrammarImportError> {
446    u8::try_from(integer(value, key, "expression")?).map_err(|_| invalid("expression"))
447}
448
449fn read_expressions(value: &Value, key: &str) -> Result<Vec<GrammarExpr>, GrammarImportError> {
450    array(value, key, "expression")?
451        .iter()
452        .map(read_expression)
453        .collect()
454}
455
456fn read_item(value: &Value) -> Result<Box<GrammarExpr>, GrammarImportError> {
457    Ok(Box::new(read_expression(field(
458        value,
459        "item",
460        "expression",
461    )?)?))
462}
463
464fn read_expression(value: &Value) -> Result<GrammarExpr, GrammarImportError> {
465    let kind = string(value, "kind", "expression")?;
466    Ok(match kind.as_str() {
467        "empty" => GrammarExpr::Empty,
468        "any" => GrammarExpr::AnyChar,
469        "literal" => GrammarExpr::Terminal(string(value, "value", "expression")?),
470        "literalInsensitive" => {
471            GrammarExpr::TerminalInsensitive(string(value, "value", "expression")?)
472        }
473        "charRange" => GrammarExpr::CharRange(character(value, "start")?, character(value, "end")?),
474        "charClass" => {
475            let negated = value
476                .get("negated")
477                .and_then(Value::as_bool)
478                .unwrap_or(false);
479            let items = array(value, "items", "expression")?
480                .iter()
481                .map(read_class_item)
482                .collect::<Result<_, _>>()?;
483            class_expression(negated, items)
484        }
485        "byteClass" => {
486            let negated = value
487                .get("negated")
488                .and_then(Value::as_bool)
489                .unwrap_or(false);
490            let items = array(value, "items", "expression")?
491                .iter()
492                .map(|item| match string(item, "kind", "expression")?.as_str() {
493                    "byte" => Ok(ByteClassItem::Byte(byte(item, "value")?)),
494                    "byteRange" => Ok(ByteClassItem::Range(
495                        byte(item, "start")?,
496                        byte(item, "end")?,
497                    )),
498                    _ => Err(invalid("expression")),
499                })
500                .collect::<Result<_, _>>()?;
501            GrammarExpr::feature(FeatureExpr::ByteClass { negated, items })
502        }
503        "ref" => {
504            let name = string(value, "name", "expression")?;
505            match value.get("arguments") {
506                None | Some(Value::Null) => GrammarExpr::NonTerminal(name),
507                Some(_) => GrammarExpr::feature(FeatureExpr::Call {
508                    name,
509                    arguments: read_expressions(value, "arguments")?,
510                }),
511            }
512        }
513        "choice" => GrammarExpr::Choice {
514            ordered: value
515                .get("ordered")
516                .and_then(Value::as_bool)
517                .unwrap_or(false),
518            alternatives: read_expressions(value, "items")?,
519        },
520        "seq" => GrammarExpr::Sequence(read_expressions(value, "items")?),
521        "optional" => GrammarExpr::Optional(read_item(value)?),
522        "repeat0" => GrammarExpr::ZeroOrMore(read_item(value)?),
523        "repeat1" => GrammarExpr::OneOrMore(read_item(value)?),
524        "and" => GrammarExpr::And(read_item(value)?),
525        "not" => GrammarExpr::Not(read_item(value)?),
526        "repeat" => GrammarExpr::Repeat {
527            expr: read_item(value)?,
528            min: count(value, "min")?,
529            max: match value.get("max") {
530                None | Some(Value::Null) => None,
531                Some(_) => Some(count(value, "max")?),
532            },
533        },
534        "capture" => GrammarExpr::Capture {
535            label: optional_string(value, "label", "expression")?,
536            expr: read_item(value)?,
537        },
538        other => {
539            let fields = feature_expression_fields(other).ok_or_else(|| {
540                json_error(format!(
541                    "unsupported serialized grammar expression kind {other}"
542                ))
543            })?;
544            GrammarExpr::feature(FeatureExpr::Form(read_form(other, fields, value)?))
545        }
546    })
547}
548
549fn read_class_item(item: &Value) -> Result<UnicodeClassItem, GrammarImportError> {
550    Ok(match string(item, "kind", "expression")?.as_str() {
551        "char" => UnicodeClassItem::Char(character(item, "value")?),
552        "range" => UnicodeClassItem::Range(character(item, "start")?, character(item, "end")?),
553        "category" => UnicodeClassItem::Category(string(item, "value", "expression")?),
554        "script" => UnicodeClassItem::Script(string(item, "value", "expression")?),
555        _ => return Err(invalid("expression")),
556    })
557}
558
559fn read_form(
560    head: &str,
561    fields: &[(&'static str, FieldType)],
562    value: &Value,
563) -> Result<FeatureForm, GrammarImportError> {
564    let mut values = Vec::with_capacity(fields.len());
565    for (key, kind) in fields {
566        let what = "expression";
567        values.push(match kind {
568            FieldType::Choice(words) => {
569                let word = string(value, key, what)?;
570                if !words.contains(&word.as_str()) {
571                    return Err(invalid(what));
572                }
573                FieldValue::Word(word)
574            }
575            FieldType::Integer => FieldValue::Integer(integer(value, key, what)?),
576            FieldType::Name => FieldValue::Name(string(value, key, what)?),
577            FieldType::Text => FieldValue::Text(string(value, key, what)?),
578            FieldType::Expression => {
579                FieldValue::Expression(read_expression(field(value, key, what)?)?)
580            }
581            FieldType::Expressions => FieldValue::Expressions(read_expressions(value, key)?),
582            FieldType::Condition => FieldValue::Operation(read_operation(
583                field(value, key, what)?,
584                OperationCategory::Condition,
585            )?),
586            FieldType::Value => FieldValue::Operation(read_operation(
587                field(value, key, what)?,
588                OperationCategory::Value,
589            )?),
590            FieldType::Conditions => FieldValue::Operations(read_operations(
591                array(value, key, what)?,
592                OperationCategory::Condition,
593            )?),
594            FieldType::Block(_, optional) => match value.get(*key) {
595                None | Some(Value::Null) if *optional => FieldValue::Block(None),
596                _ => FieldValue::Block(Some(read_operations(
597                    array(value, key, what)?,
598                    OperationCategory::Statement,
599                )?)),
600            },
601        });
602    }
603    Ok(FeatureForm::new(head, values))
604}
605
606fn read_operation(
607    value: &Value,
608    category: OperationCategory,
609) -> Result<Operation, GrammarImportError> {
610    let head = string(value, "operation", "operation")?;
611    let (found, fields) = operation_form(&head)
612        .ok_or_else(|| json_error(format!("unsupported serialized grammar operation {head}")))?;
613    if found != category {
614        return Err(json_error(format!(
615            "serialized grammar operation {head} is not a {}",
616            category.as_str()
617        )));
618    }
619    read_form(&head, fields, value)
620}
621
622fn read_operations(
623    values: &[Value],
624    category: OperationCategory,
625) -> Result<Vec<Operation>, GrammarImportError> {
626    values
627        .iter()
628        .map(|value| read_operation(value, category))
629        .collect()
630}
631
632fn read_declarations(value: &Value) -> Result<GrammarDeclarations, GrammarImportError> {
633    let what = "declarations";
634    let mut declarations = GrammarDeclarations {
635        matching: optional_string(value, "matching", what)?,
636        settling: value
637            .get("settling")
638            .map(|steps| strings(Some(steps), what))
639            .transpose()?,
640        imports: strings(value.get("imports"), what)?,
641        modes: strings(value.get("modes"), what)?,
642        ..GrammarDeclarations::default()
643    };
644    if let Some(Value::Array(extras)) = value.get("extras") {
645        declarations.extras = extras
646            .iter()
647            .map(read_expression)
648            .collect::<Result<_, _>>()?;
649    }
650    if let Some(Value::Array(groups)) = value.get("conflicts") {
651        declarations.conflicts = groups
652            .iter()
653            .map(|group| strings(Some(group), what))
654            .collect::<Result<_, _>>()?;
655    }
656    if let Some(Value::Array(orders)) = value.get("precedences") {
657        for order in orders {
658            let Value::Array(entries) = order else {
659                return Err(invalid(what));
660            };
661            let mut read = Vec::new();
662            for entry in entries {
663                let kind = string(entry, "kind", what)?;
664                let value = string(entry, "value", what)?;
665                let Some(entry) = PrecedenceEntry::from_kind(&kind, value) else {
666                    return Err(invalid(what));
667                };
668                read.push(entry);
669            }
670            declarations.precedences.push(read);
671        }
672    }
673    if let Some(Value::Array(macros)) = value.get("macros") {
674        for declared in macros {
675            declarations.macros.push(GrammarMacro {
676                name: string(declared, "name", what)?,
677                parameters: strings(declared.get("parameters"), what)?,
678                expression: read_expression(field(declared, "expression", what)?)?,
679            });
680        }
681    }
682    if let Some(Value::Array(scanners)) = value.get("scanners") {
683        for scanner in scanners {
684            declarations.scanners.push(GrammarScanner {
685                name: string(scanner, "name", what)?,
686                tokens: strings(scanner.get("tokens"), what)?,
687                operations: read_operations(
688                    array(scanner, "operations", what)?,
689                    OperationCategory::Statement,
690                )?,
691            });
692        }
693    }
694    Ok(declarations)
695}
696
697fn read_rule(value: &Value) -> Result<GrammarRule, GrammarImportError> {
698    let name = value.get("name").and_then(Value::as_str);
699    let expression = value
700        .get("expression")
701        .filter(|expr| expr.get("kind").is_some());
702    let (Some(name), Some(expression)) = (name, expression) else {
703        return Err(invalid("rule"));
704    };
705    let kind = match value.get("kind") {
706        None | Some(Value::Null) => RuleKind::Normal,
707        Some(kind) => kind
708            .as_str()
709            .and_then(RuleKind::from_tag)
710            .ok_or_else(|| invalid("rule"))?,
711    };
712    let attributes = RuleAttributes {
713        parameters: strings(value.get("parameters"), "rule")?,
714        channel: optional_string(value, "channel", "rule")?,
715        modes: match value.get("modes") {
716            None | Some(Value::Null) => None,
717            modes => Some(strings(modes, "rule")?),
718        },
719        action: match value.get("action") {
720            None | Some(Value::Null) => None,
721            Some(_) => Some(read_operations(
722                array(value, "action", "rule")?,
723                OperationCategory::Statement,
724            )?),
725        },
726    };
727    Ok(GrammarRule::new(name, read_expression(expression)?)
728        .with_kind(kind)
729        .with_attributes(attributes))
730}
731
732/// Reads a document [`serialize_grammar`] (or `serializeGrammar` of
733/// `js/src/grammar.js`) wrote.
734///
735/// # Errors
736///
737/// Returns a [`GrammarImportError`] when the text is not JSON, is not a
738/// schema version 1 grammar document, names a rule twice, holds an
739/// expression or operation this runtime does not know, or has no start rule.
740pub fn deserialize_grammar(source: &str) -> Result<Grammar, GrammarImportError> {
741    let value: Value = serde_json::from_str(source)
742        .map_err(|error| json_error(format!("invalid serialized grammar JSON: {error}")))?;
743    let (Some(1), Some(Value::Array(rules))) = (
744        value.get("schemaVersion").and_then(Value::as_i64),
745        value.get("rules"),
746    ) else {
747        return Err(invalid("document"));
748    };
749    let mut grammar = Grammar::new();
750    for rule in rules {
751        let rule = read_rule(rule)?;
752        if grammar.rule(&rule.name).is_some() {
753            return Err(json_error(format!(
754                "duplicate serialized grammar rule {}",
755                rule.name
756            )));
757        }
758        grammar.add_rule(rule);
759    }
760    if let Some(start) = value.get("start").and_then(Value::as_str) {
761        grammar.set_start(start);
762    }
763    if let Some(format) = value.get("sourceFormat").and_then(Value::as_str) {
764        let format = GrammarFormat::from_tag(format)
765            .ok_or_else(|| json_error(format!("unknown serialized grammar format {format}")))?;
766        grammar.set_source_format(format);
767    }
768    if let Some(declarations) = value.get("declarations").filter(|value| !value.is_null()) {
769        grammar.set_declarations(read_declarations(declarations)?);
770    }
771    if grammar.start_rule().is_none() {
772        return Err(json_error("serialized grammar has no start rule"));
773    }
774    Ok(grammar)
775}