tree_sitter_generate/
node_types.rs

1use std::{
2    cmp::Ordering,
3    collections::{BTreeMap, HashMap, HashSet},
4};
5
6use anyhow::Result;
7use serde::Serialize;
8use thiserror::Error;
9
10use super::{
11    grammars::{LexicalGrammar, SyntaxGrammar, VariableType},
12    rules::{Alias, AliasMap, Symbol, SymbolType},
13};
14
15#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
16pub enum ChildType {
17    Normal(Symbol),
18    Aliased(Alias),
19}
20
21#[derive(Clone, Debug, Default, PartialEq, Eq)]
22pub struct FieldInfo {
23    pub quantity: ChildQuantity,
24    pub types: Vec<ChildType>,
25}
26
27#[derive(Clone, Debug, Default, PartialEq, Eq)]
28pub struct VariableInfo {
29    pub fields: HashMap<String, FieldInfo>,
30    pub children: FieldInfo,
31    pub children_without_fields: FieldInfo,
32    pub has_multi_step_production: bool,
33}
34
35#[derive(Debug, Serialize, PartialEq, Eq, Default, PartialOrd, Ord)]
36pub struct NodeInfoJSON {
37    #[serde(rename = "type")]
38    kind: String,
39    named: bool,
40    #[serde(skip_serializing_if = "std::ops::Not::not")]
41    root: bool,
42    #[serde(skip_serializing_if = "std::ops::Not::not")]
43    extra: bool,
44    #[serde(skip_serializing_if = "Option::is_none")]
45    fields: Option<BTreeMap<String, FieldInfoJSON>>,
46    #[serde(skip_serializing_if = "Option::is_none")]
47    children: Option<FieldInfoJSON>,
48    #[serde(skip_serializing_if = "Option::is_none")]
49    subtypes: Option<Vec<NodeTypeJSON>>,
50}
51
52#[derive(Clone, Debug, Serialize, PartialEq, Eq, PartialOrd, Ord, Hash)]
53pub struct NodeTypeJSON {
54    #[serde(rename = "type")]
55    kind: String,
56    named: bool,
57}
58
59#[derive(Debug, Serialize, PartialEq, Eq, PartialOrd, Ord)]
60pub struct FieldInfoJSON {
61    multiple: bool,
62    required: bool,
63    types: Vec<NodeTypeJSON>,
64}
65
66#[derive(Clone, Copy, Debug, PartialEq, Eq)]
67pub struct ChildQuantity {
68    exists: bool,
69    required: bool,
70    multiple: bool,
71}
72
73impl Default for FieldInfoJSON {
74    fn default() -> Self {
75        Self {
76            multiple: false,
77            required: true,
78            types: Vec::new(),
79        }
80    }
81}
82
83impl Default for ChildQuantity {
84    fn default() -> Self {
85        Self::one()
86    }
87}
88
89impl ChildQuantity {
90    #[must_use]
91    const fn zero() -> Self {
92        Self {
93            exists: false,
94            required: false,
95            multiple: false,
96        }
97    }
98
99    #[must_use]
100    const fn one() -> Self {
101        Self {
102            exists: true,
103            required: true,
104            multiple: false,
105        }
106    }
107
108    fn append(&mut self, other: Self) {
109        if other.exists {
110            if self.exists || other.multiple {
111                self.multiple = true;
112            }
113            if other.required {
114                self.required = true;
115            }
116            self.exists = true;
117        }
118    }
119
120    fn union(&mut self, other: Self) -> bool {
121        let mut result = false;
122        if !self.exists && other.exists {
123            result = true;
124            self.exists = true;
125        }
126        if self.required && !other.required {
127            result = true;
128            self.required = false;
129        }
130        if !self.multiple && other.multiple {
131            result = true;
132            self.multiple = true;
133        }
134        result
135    }
136}
137
138pub type VariableInfoResult<T> = Result<T, VariableInfoError>;
139
140#[derive(Debug, Error, Serialize)]
141pub enum VariableInfoError {
142    #[error("Grammar error: Supertype symbols must always have a single visible child, but `{0}` can have multiple")]
143    InvalidSupertype(String),
144}
145
146/// Compute a summary of the public-facing structure of each variable in the
147/// grammar. Each variable in the grammar corresponds to a distinct public-facing
148/// node type.
149///
150/// The information collected about each node type `N` is:
151/// 1. `child_types` - The types of visible children that can appear within `N`.
152/// 2. `fields` - The fields that `N` can have. Data regarding each field:
153///    * `types` - The types of visible children the field can contain.
154///    * `optional` - Do `N` nodes always have this field?
155///    * `multiple` - Can `N` nodes have multiple children for this field?
156/// 3. `children_without_fields` - The *other* named children of `N` that are not associated with
157///    fields. Data regarding these children:
158///    * `types` - The types of named children with no field.
159///    * `optional` - Do `N` nodes always have at least one named child with no field?
160///    * `multiple` - Can `N` nodes have multiple named children with no field?
161///
162/// Each summary must account for some indirect factors:
163/// 1. hidden nodes. When a parent node `N` has a hidden child `C`, the visible children of `C`
164///    *appear* to be direct children of `N`.
165/// 2. aliases. If a parent node type `M` is aliased as some other type `N`, then nodes which
166///    *appear* to have type `N` may have internal structure based on `M`.
167pub fn get_variable_info(
168    syntax_grammar: &SyntaxGrammar,
169    lexical_grammar: &LexicalGrammar,
170    default_aliases: &AliasMap,
171) -> VariableInfoResult<Vec<VariableInfo>> {
172    let child_type_is_visible = |t: &ChildType| {
173        variable_type_for_child_type(t, syntax_grammar, lexical_grammar) >= VariableType::Anonymous
174    };
175
176    let child_type_is_named = |t: &ChildType| {
177        variable_type_for_child_type(t, syntax_grammar, lexical_grammar) == VariableType::Named
178    };
179
180    // Each variable's summary can depend on the summaries of other hidden variables,
181    // and variables can have mutually recursive structure. So we compute the summaries
182    // iteratively, in a loop that terminates only when no more changes are possible.
183    let mut did_change = true;
184    let mut all_initialized = false;
185    let mut result = vec![VariableInfo::default(); syntax_grammar.variables.len()];
186    while did_change {
187        did_change = false;
188
189        for (i, variable) in syntax_grammar.variables.iter().enumerate() {
190            let mut variable_info = result[i].clone();
191
192            // Examine each of the variable's productions. The variable's child types can be
193            // immediately combined across all productions, but the child quantities must be
194            // recorded separately for each production.
195            for production in &variable.productions {
196                let mut production_field_quantities = HashMap::new();
197                let mut production_children_quantity = ChildQuantity::zero();
198                let mut production_children_without_fields_quantity = ChildQuantity::zero();
199                let mut production_has_uninitialized_invisible_children = false;
200
201                if production.steps.len() > 1 {
202                    variable_info.has_multi_step_production = true;
203                }
204
205                for step in &production.steps {
206                    let child_symbol = step.symbol;
207                    let child_type = if let Some(alias) = &step.alias {
208                        ChildType::Aliased(alias.clone())
209                    } else if let Some(alias) = default_aliases.get(&step.symbol) {
210                        ChildType::Aliased(alias.clone())
211                    } else {
212                        ChildType::Normal(child_symbol)
213                    };
214
215                    let child_is_hidden = !child_type_is_visible(&child_type)
216                        && !syntax_grammar.supertype_symbols.contains(&child_symbol);
217
218                    // Maintain the set of all child types for this variable, and the quantity of
219                    // visible children in this production.
220                    did_change |=
221                        extend_sorted(&mut variable_info.children.types, Some(&child_type));
222                    if !child_is_hidden {
223                        production_children_quantity.append(ChildQuantity::one());
224                    }
225
226                    // Maintain the set of child types associated with each field, and the quantity
227                    // of children associated with each field in this production.
228                    if let Some(field_name) = &step.field_name {
229                        let field_info = variable_info
230                            .fields
231                            .entry(field_name.clone())
232                            .or_insert_with(FieldInfo::default);
233                        did_change |= extend_sorted(&mut field_info.types, Some(&child_type));
234
235                        let production_field_quantity = production_field_quantities
236                            .entry(field_name)
237                            .or_insert_with(ChildQuantity::zero);
238
239                        // Inherit the types and quantities of hidden children associated with
240                        // fields.
241                        if child_is_hidden && child_symbol.is_non_terminal() {
242                            let child_variable_info = &result[child_symbol.index];
243                            did_change |= extend_sorted(
244                                &mut field_info.types,
245                                &child_variable_info.children.types,
246                            );
247                            production_field_quantity.append(child_variable_info.children.quantity);
248                        } else {
249                            production_field_quantity.append(ChildQuantity::one());
250                        }
251                    }
252                    // Maintain the set of named children without fields within this variable.
253                    else if child_type_is_named(&child_type) {
254                        production_children_without_fields_quantity.append(ChildQuantity::one());
255                        did_change |= extend_sorted(
256                            &mut variable_info.children_without_fields.types,
257                            Some(&child_type),
258                        );
259                    }
260
261                    // Inherit all child information from hidden children.
262                    if child_is_hidden && child_symbol.is_non_terminal() {
263                        let child_variable_info = &result[child_symbol.index];
264
265                        // If a hidden child can have multiple children, then its parent node can
266                        // appear to have multiple children.
267                        if child_variable_info.has_multi_step_production {
268                            variable_info.has_multi_step_production = true;
269                        }
270
271                        // If a hidden child has fields, then the parent node can appear to have
272                        // those same fields.
273                        for (field_name, child_field_info) in &child_variable_info.fields {
274                            production_field_quantities
275                                .entry(field_name)
276                                .or_insert_with(ChildQuantity::zero)
277                                .append(child_field_info.quantity);
278                            did_change |= extend_sorted(
279                                &mut variable_info
280                                    .fields
281                                    .entry(field_name.clone())
282                                    .or_insert_with(FieldInfo::default)
283                                    .types,
284                                &child_field_info.types,
285                            );
286                        }
287
288                        // If a hidden child has children, then the parent node can appear to have
289                        // those same children.
290                        production_children_quantity.append(child_variable_info.children.quantity);
291                        did_change |= extend_sorted(
292                            &mut variable_info.children.types,
293                            &child_variable_info.children.types,
294                        );
295
296                        // If a hidden child can have named children without fields, then the parent
297                        // node can appear to have those same children.
298                        if step.field_name.is_none() {
299                            let grandchildren_info = &child_variable_info.children_without_fields;
300                            if !grandchildren_info.types.is_empty() {
301                                production_children_without_fields_quantity
302                                    .append(child_variable_info.children_without_fields.quantity);
303                                did_change |= extend_sorted(
304                                    &mut variable_info.children_without_fields.types,
305                                    &child_variable_info.children_without_fields.types,
306                                );
307                            }
308                        }
309                    }
310
311                    // Note whether or not this production contains children whose summaries
312                    // have not yet been computed.
313                    if child_symbol.index >= i && !all_initialized {
314                        production_has_uninitialized_invisible_children = true;
315                    }
316                }
317
318                // If this production's children all have had their summaries initialized,
319                // then expand the quantity information with all of the possibilities introduced
320                // by this production.
321                if !production_has_uninitialized_invisible_children {
322                    did_change |= variable_info
323                        .children
324                        .quantity
325                        .union(production_children_quantity);
326
327                    did_change |= variable_info
328                        .children_without_fields
329                        .quantity
330                        .union(production_children_without_fields_quantity);
331
332                    for (field_name, info) in &mut variable_info.fields {
333                        did_change |= info.quantity.union(
334                            production_field_quantities
335                                .get(field_name)
336                                .copied()
337                                .unwrap_or_else(ChildQuantity::zero),
338                        );
339                    }
340                }
341            }
342
343            result[i] = variable_info;
344        }
345
346        all_initialized = true;
347    }
348
349    for supertype_symbol in &syntax_grammar.supertype_symbols {
350        if result[supertype_symbol.index].has_multi_step_production {
351            let variable = &syntax_grammar.variables[supertype_symbol.index];
352            Err(VariableInfoError::InvalidSupertype(variable.name.clone()))?;
353        }
354    }
355
356    // Update all of the node type lists to eliminate hidden nodes.
357    for supertype_symbol in &syntax_grammar.supertype_symbols {
358        result[supertype_symbol.index]
359            .children
360            .types
361            .retain(child_type_is_visible);
362    }
363    for variable_info in &mut result {
364        for field_info in variable_info.fields.values_mut() {
365            field_info.types.retain(child_type_is_visible);
366        }
367        variable_info.fields.retain(|_, v| !v.types.is_empty());
368        variable_info
369            .children_without_fields
370            .types
371            .retain(child_type_is_visible);
372    }
373
374    Ok(result)
375}
376
377fn get_aliases_by_symbol(
378    syntax_grammar: &SyntaxGrammar,
379    default_aliases: &AliasMap,
380) -> HashMap<Symbol, HashSet<Option<Alias>>> {
381    let mut aliases_by_symbol = HashMap::new();
382    for (symbol, alias) in default_aliases {
383        aliases_by_symbol.insert(*symbol, {
384            let mut aliases = HashSet::new();
385            aliases.insert(Some(alias.clone()));
386            aliases
387        });
388    }
389    for extra_symbol in &syntax_grammar.extra_symbols {
390        if !default_aliases.contains_key(extra_symbol) {
391            aliases_by_symbol
392                .entry(*extra_symbol)
393                .or_insert_with(HashSet::new)
394                .insert(None);
395        }
396    }
397    for variable in &syntax_grammar.variables {
398        for production in &variable.productions {
399            for step in &production.steps {
400                aliases_by_symbol
401                    .entry(step.symbol)
402                    .or_insert_with(HashSet::new)
403                    .insert(
404                        step.alias
405                            .as_ref()
406                            .or_else(|| default_aliases.get(&step.symbol))
407                            .cloned(),
408                    );
409            }
410        }
411    }
412    aliases_by_symbol.insert(
413        Symbol::non_terminal(0),
414        std::iter::once(&None).cloned().collect(),
415    );
416    aliases_by_symbol
417}
418
419pub fn get_supertype_symbol_map(
420    syntax_grammar: &SyntaxGrammar,
421    default_aliases: &AliasMap,
422    variable_info: &[VariableInfo],
423) -> BTreeMap<Symbol, Vec<ChildType>> {
424    let aliases_by_symbol = get_aliases_by_symbol(syntax_grammar, default_aliases);
425    let mut supertype_symbol_map = BTreeMap::new();
426
427    let mut symbols_by_alias = HashMap::new();
428    for (symbol, aliases) in &aliases_by_symbol {
429        for alias in aliases.iter().flatten() {
430            symbols_by_alias
431                .entry(alias)
432                .or_insert_with(Vec::new)
433                .push(*symbol);
434        }
435    }
436
437    for (i, info) in variable_info.iter().enumerate() {
438        let symbol = Symbol::non_terminal(i);
439        if syntax_grammar.supertype_symbols.contains(&symbol) {
440            let subtypes = info.children.types.clone();
441            supertype_symbol_map.insert(symbol, subtypes);
442        }
443    }
444    supertype_symbol_map
445}
446
447pub fn generate_node_types_json(
448    syntax_grammar: &SyntaxGrammar,
449    lexical_grammar: &LexicalGrammar,
450    default_aliases: &AliasMap,
451    variable_info: &[VariableInfo],
452) -> Vec<NodeInfoJSON> {
453    let mut node_types_json = BTreeMap::new();
454
455    let child_type_to_node_type = |child_type: &ChildType| match child_type {
456        ChildType::Aliased(alias) => NodeTypeJSON {
457            kind: alias.value.clone(),
458            named: alias.is_named,
459        },
460        ChildType::Normal(symbol) => {
461            if let Some(alias) = default_aliases.get(symbol) {
462                NodeTypeJSON {
463                    kind: alias.value.clone(),
464                    named: alias.is_named,
465                }
466            } else {
467                match symbol.kind {
468                    SymbolType::NonTerminal => {
469                        let variable = &syntax_grammar.variables[symbol.index];
470                        NodeTypeJSON {
471                            kind: variable.name.clone(),
472                            named: variable.kind != VariableType::Anonymous,
473                        }
474                    }
475                    SymbolType::Terminal => {
476                        let variable = &lexical_grammar.variables[symbol.index];
477                        NodeTypeJSON {
478                            kind: variable.name.clone(),
479                            named: variable.kind != VariableType::Anonymous,
480                        }
481                    }
482                    SymbolType::External => {
483                        let variable = &syntax_grammar.external_tokens[symbol.index];
484                        NodeTypeJSON {
485                            kind: variable.name.clone(),
486                            named: variable.kind != VariableType::Anonymous,
487                        }
488                    }
489                    _ => panic!("Unexpected symbol type"),
490                }
491            }
492        }
493    };
494
495    let populate_field_info_json = |json: &mut FieldInfoJSON, info: &FieldInfo| {
496        if info.types.is_empty() {
497            json.required = false;
498        } else {
499            json.multiple |= info.quantity.multiple;
500            json.required &= info.quantity.required;
501            json.types
502                .extend(info.types.iter().map(child_type_to_node_type));
503            json.types.sort_unstable();
504            json.types.dedup();
505        }
506    };
507
508    let aliases_by_symbol = get_aliases_by_symbol(syntax_grammar, default_aliases);
509
510    let mut subtype_map = Vec::new();
511    for (i, info) in variable_info.iter().enumerate() {
512        let symbol = Symbol::non_terminal(i);
513        let variable = &syntax_grammar.variables[i];
514        if syntax_grammar.supertype_symbols.contains(&symbol) {
515            let node_type_json =
516                node_types_json
517                    .entry(variable.name.clone())
518                    .or_insert_with(|| NodeInfoJSON {
519                        kind: variable.name.clone(),
520                        named: true,
521                        root: false,
522                        extra: false,
523                        fields: None,
524                        children: None,
525                        subtypes: None,
526                    });
527            let mut subtypes = info
528                .children
529                .types
530                .iter()
531                .map(child_type_to_node_type)
532                .collect::<Vec<_>>();
533            subtypes.sort_unstable();
534            subtypes.dedup();
535            let supertype = NodeTypeJSON {
536                kind: node_type_json.kind.clone(),
537                named: true,
538            };
539            subtype_map.push((supertype, subtypes.clone()));
540            node_type_json.subtypes = Some(subtypes);
541        } else if !syntax_grammar.variables_to_inline.contains(&symbol) {
542            // If a rule is aliased under multiple names, then its information
543            // contributes to multiple entries in the final JSON.
544            for alias in aliases_by_symbol.get(&symbol).unwrap_or(&HashSet::new()) {
545                let kind;
546                let is_named;
547                if let Some(alias) = alias {
548                    kind = &alias.value;
549                    is_named = alias.is_named;
550                } else if variable.kind.is_visible() {
551                    kind = &variable.name;
552                    is_named = variable.kind == VariableType::Named;
553                } else {
554                    continue;
555                }
556
557                // There may already be an entry with this name, because multiple
558                // rules may be aliased with the same name.
559                let mut node_type_existed = true;
560                let node_type_json = node_types_json.entry(kind.clone()).or_insert_with(|| {
561                    node_type_existed = false;
562                    NodeInfoJSON {
563                        kind: kind.clone(),
564                        named: is_named,
565                        root: i == 0,
566                        extra: false,
567                        fields: Some(BTreeMap::new()),
568                        children: None,
569                        subtypes: None,
570                    }
571                });
572
573                let fields_json = node_type_json.fields.as_mut().unwrap();
574                for (new_field, field_info) in &info.fields {
575                    let field_json = fields_json.entry(new_field.clone()).or_insert_with(|| {
576                        // If another rule is aliased with the same name, and does *not* have this
577                        // field, then this field cannot be required.
578                        let mut field_json = FieldInfoJSON::default();
579                        if node_type_existed {
580                            field_json.required = false;
581                        }
582                        field_json
583                    });
584                    populate_field_info_json(field_json, field_info);
585                }
586
587                // If another rule is aliased with the same name, any fields that aren't present in
588                // this cannot be required.
589                for (existing_field, field_json) in fields_json.iter_mut() {
590                    if !info.fields.contains_key(existing_field) {
591                        field_json.required = false;
592                    }
593                }
594
595                populate_field_info_json(
596                    node_type_json
597                        .children
598                        .get_or_insert(FieldInfoJSON::default()),
599                    &info.children_without_fields,
600                );
601            }
602        }
603    }
604
605    // Sort the subtype map so that subtypes are listed before their supertypes.
606    subtype_map.sort_by(|a, b| {
607        if b.1.contains(&a.0) {
608            Ordering::Less
609        } else if a.1.contains(&b.0) {
610            Ordering::Greater
611        } else {
612            Ordering::Equal
613        }
614    });
615
616    for node_type_json in node_types_json.values_mut() {
617        if node_type_json
618            .children
619            .as_ref()
620            .is_some_and(|c| c.types.is_empty())
621        {
622            node_type_json.children = None;
623        }
624
625        if let Some(children) = &mut node_type_json.children {
626            process_supertypes(children, &subtype_map);
627        }
628        if let Some(fields) = &mut node_type_json.fields {
629            for field_info in fields.values_mut() {
630                process_supertypes(field_info, &subtype_map);
631            }
632        }
633    }
634
635    let mut anonymous_node_types = Vec::new();
636
637    let empty = HashSet::new();
638    let regular_tokens = lexical_grammar
639        .variables
640        .iter()
641        .enumerate()
642        .flat_map(|(i, variable)| {
643            aliases_by_symbol
644                .get(&Symbol::terminal(i))
645                .unwrap_or(&empty)
646                .iter()
647                .map(move |alias| {
648                    alias
649                        .as_ref()
650                        .map_or((&variable.name, variable.kind), |alias| {
651                            (&alias.value, alias.kind())
652                        })
653                })
654        });
655    let external_tokens =
656        syntax_grammar
657            .external_tokens
658            .iter()
659            .enumerate()
660            .flat_map(|(i, token)| {
661                aliases_by_symbol
662                    .get(&Symbol::external(i))
663                    .unwrap_or(&empty)
664                    .iter()
665                    .map(move |alias| {
666                        alias.as_ref().map_or((&token.name, token.kind), |alias| {
667                            (&alias.value, alias.kind())
668                        })
669                    })
670            });
671    let extra_names = syntax_grammar
672        .extra_symbols
673        .iter()
674        .flat_map(|symbol| {
675            aliases_by_symbol
676                .get(symbol)
677                .unwrap_or(&empty)
678                .iter()
679                .map(|alias| {
680                    alias.as_ref().map_or(
681                        match symbol.kind {
682                            SymbolType::NonTerminal => &syntax_grammar.variables[symbol.index].name,
683                            SymbolType::Terminal => &lexical_grammar.variables[symbol.index].name,
684                            SymbolType::External => {
685                                &syntax_grammar.external_tokens[symbol.index].name
686                            }
687                            _ => unreachable!(),
688                        },
689                        |alias| &alias.value,
690                    )
691                })
692        })
693        .collect::<HashSet<_>>();
694
695    for (name, kind) in regular_tokens.chain(external_tokens) {
696        match kind {
697            VariableType::Named => {
698                let node_type_json =
699                    node_types_json
700                        .entry(name.clone())
701                        .or_insert_with(|| NodeInfoJSON {
702                            kind: name.clone(),
703                            named: true,
704                            root: false,
705                            extra: extra_names.contains(&name),
706                            fields: None,
707                            children: None,
708                            subtypes: None,
709                        });
710                if let Some(children) = &mut node_type_json.children {
711                    children.required = false;
712                }
713                if let Some(fields) = &mut node_type_json.fields {
714                    for field in fields.values_mut() {
715                        field.required = false;
716                    }
717                }
718            }
719            VariableType::Anonymous => anonymous_node_types.push(NodeInfoJSON {
720                kind: name.clone(),
721                named: false,
722                root: false,
723                extra: extra_names.contains(&name),
724                fields: None,
725                children: None,
726                subtypes: None,
727            }),
728            _ => {}
729        }
730    }
731
732    let mut result = node_types_json.into_iter().map(|e| e.1).collect::<Vec<_>>();
733    result.extend(anonymous_node_types);
734    result.sort_unstable_by(|a, b| {
735        b.subtypes
736            .is_some()
737            .cmp(&a.subtypes.is_some())
738            .then_with(|| {
739                let a_is_leaf = a.children.is_none() && a.fields.is_none();
740                let b_is_leaf = b.children.is_none() && b.fields.is_none();
741                a_is_leaf.cmp(&b_is_leaf)
742            })
743            .then_with(|| a.kind.cmp(&b.kind))
744    });
745    result.dedup();
746    result
747}
748
749fn process_supertypes(info: &mut FieldInfoJSON, subtype_map: &[(NodeTypeJSON, Vec<NodeTypeJSON>)]) {
750    for (supertype, subtypes) in subtype_map {
751        if info.types.contains(supertype) {
752            info.types.retain(|t| !subtypes.contains(t));
753        }
754    }
755}
756
757fn variable_type_for_child_type(
758    child_type: &ChildType,
759    syntax_grammar: &SyntaxGrammar,
760    lexical_grammar: &LexicalGrammar,
761) -> VariableType {
762    match child_type {
763        ChildType::Aliased(alias) => alias.kind(),
764        ChildType::Normal(symbol) => {
765            if syntax_grammar.supertype_symbols.contains(symbol) {
766                VariableType::Named
767            } else if syntax_grammar.variables_to_inline.contains(symbol) {
768                VariableType::Hidden
769            } else {
770                match symbol.kind {
771                    SymbolType::NonTerminal => syntax_grammar.variables[symbol.index].kind,
772                    SymbolType::Terminal => lexical_grammar.variables[symbol.index].kind,
773                    SymbolType::External => syntax_grammar.external_tokens[symbol.index].kind,
774                    _ => VariableType::Hidden,
775                }
776            }
777        }
778    }
779}
780
781fn extend_sorted<'a, T>(vec: &mut Vec<T>, values: impl IntoIterator<Item = &'a T>) -> bool
782where
783    T: 'a + Clone + Eq + Ord,
784{
785    values.into_iter().any(|value| {
786        if let Err(i) = vec.binary_search(value) {
787            vec.insert(i, value.clone());
788            true
789        } else {
790            false
791        }
792    })
793}
794
795#[cfg(test)]
796mod tests {
797    use super::*;
798    use crate::{
799        grammars::{
800            InputGrammar, LexicalVariable, Production, ProductionStep, SyntaxVariable, Variable,
801        },
802        prepare_grammar::prepare_grammar,
803        rules::Rule,
804    };
805
806    #[test]
807    fn test_node_types_simple() {
808        let node_types = get_node_types(&InputGrammar {
809            variables: vec![
810                Variable {
811                    name: "v1".to_string(),
812                    kind: VariableType::Named,
813                    rule: Rule::seq(vec![
814                        Rule::field("f1".to_string(), Rule::named("v2")),
815                        Rule::field("f2".to_string(), Rule::string(";")),
816                    ]),
817                },
818                Variable {
819                    name: "v2".to_string(),
820                    kind: VariableType::Named,
821                    rule: Rule::string("x"),
822                },
823                // This rule is not reachable from the start symbol
824                // so it won't be present in the node_types
825                Variable {
826                    name: "v3".to_string(),
827                    kind: VariableType::Named,
828                    rule: Rule::string("y"),
829                },
830            ],
831            ..Default::default()
832        });
833
834        assert_eq!(node_types.len(), 3);
835
836        assert_eq!(
837            node_types[0],
838            NodeInfoJSON {
839                kind: "v1".to_string(),
840                named: true,
841                root: true,
842                extra: false,
843                subtypes: None,
844                children: None,
845                fields: Some(
846                    vec![
847                        (
848                            "f1".to_string(),
849                            FieldInfoJSON {
850                                multiple: false,
851                                required: true,
852                                types: vec![NodeTypeJSON {
853                                    kind: "v2".to_string(),
854                                    named: true,
855                                }]
856                            }
857                        ),
858                        (
859                            "f2".to_string(),
860                            FieldInfoJSON {
861                                multiple: false,
862                                required: true,
863                                types: vec![NodeTypeJSON {
864                                    kind: ";".to_string(),
865                                    named: false,
866                                }]
867                            }
868                        ),
869                    ]
870                    .into_iter()
871                    .collect()
872                )
873            }
874        );
875        assert_eq!(
876            node_types[1],
877            NodeInfoJSON {
878                kind: ";".to_string(),
879                named: false,
880                root: false,
881                extra: false,
882                subtypes: None,
883                children: None,
884                fields: None
885            }
886        );
887        assert_eq!(
888            node_types[2],
889            NodeInfoJSON {
890                kind: "v2".to_string(),
891                named: true,
892                root: false,
893                extra: false,
894                subtypes: None,
895                children: None,
896                fields: None
897            }
898        );
899    }
900
901    #[test]
902    fn test_node_types_simple_extras() {
903        let node_types = get_node_types(&InputGrammar {
904            extra_symbols: vec![Rule::named("v3")],
905            variables: vec![
906                Variable {
907                    name: "v1".to_string(),
908                    kind: VariableType::Named,
909                    rule: Rule::seq(vec![
910                        Rule::field("f1".to_string(), Rule::named("v2")),
911                        Rule::field("f2".to_string(), Rule::string(";")),
912                    ]),
913                },
914                Variable {
915                    name: "v2".to_string(),
916                    kind: VariableType::Named,
917                    rule: Rule::string("x"),
918                },
919                // This rule is not reachable from the start symbol, but
920                // it is reachable from the 'extra_symbols' so it
921                // should be present in the node_types
922                Variable {
923                    name: "v3".to_string(),
924                    kind: VariableType::Named,
925                    rule: Rule::string("y"),
926                },
927            ],
928            ..Default::default()
929        });
930
931        assert_eq!(node_types.len(), 4);
932
933        assert_eq!(
934            node_types[0],
935            NodeInfoJSON {
936                kind: "v1".to_string(),
937                named: true,
938                root: true,
939                extra: false,
940                subtypes: None,
941                children: None,
942                fields: Some(
943                    vec![
944                        (
945                            "f1".to_string(),
946                            FieldInfoJSON {
947                                multiple: false,
948                                required: true,
949                                types: vec![NodeTypeJSON {
950                                    kind: "v2".to_string(),
951                                    named: true,
952                                }]
953                            }
954                        ),
955                        (
956                            "f2".to_string(),
957                            FieldInfoJSON {
958                                multiple: false,
959                                required: true,
960                                types: vec![NodeTypeJSON {
961                                    kind: ";".to_string(),
962                                    named: false,
963                                }]
964                            }
965                        ),
966                    ]
967                    .into_iter()
968                    .collect()
969                )
970            }
971        );
972        assert_eq!(
973            node_types[1],
974            NodeInfoJSON {
975                kind: ";".to_string(),
976                named: false,
977                root: false,
978                extra: false,
979                subtypes: None,
980                children: None,
981                fields: None
982            }
983        );
984        assert_eq!(
985            node_types[2],
986            NodeInfoJSON {
987                kind: "v2".to_string(),
988                named: true,
989                root: false,
990                extra: false,
991                subtypes: None,
992                children: None,
993                fields: None
994            }
995        );
996        assert_eq!(
997            node_types[3],
998            NodeInfoJSON {
999                kind: "v3".to_string(),
1000                named: true,
1001                root: false,
1002                extra: true,
1003                subtypes: None,
1004                children: None,
1005                fields: None
1006            }
1007        );
1008    }
1009
1010    #[test]
1011    fn test_node_types_with_supertypes() {
1012        let node_types = get_node_types(&InputGrammar {
1013            supertype_symbols: vec!["_v2".to_string()],
1014            variables: vec![
1015                Variable {
1016                    name: "v1".to_string(),
1017                    kind: VariableType::Named,
1018                    rule: Rule::field("f1".to_string(), Rule::named("_v2")),
1019                },
1020                Variable {
1021                    name: "_v2".to_string(),
1022                    kind: VariableType::Hidden,
1023                    rule: Rule::choice(vec![
1024                        Rule::named("v3"),
1025                        Rule::named("v4"),
1026                        Rule::string("*"),
1027                    ]),
1028                },
1029                Variable {
1030                    name: "v3".to_string(),
1031                    kind: VariableType::Named,
1032                    rule: Rule::string("x"),
1033                },
1034                Variable {
1035                    name: "v4".to_string(),
1036                    kind: VariableType::Named,
1037                    rule: Rule::string("y"),
1038                },
1039            ],
1040            ..Default::default()
1041        });
1042
1043        assert_eq!(
1044            node_types[0],
1045            NodeInfoJSON {
1046                kind: "_v2".to_string(),
1047                named: true,
1048                root: false,
1049                extra: false,
1050                fields: None,
1051                children: None,
1052                subtypes: Some(vec![
1053                    NodeTypeJSON {
1054                        kind: "*".to_string(),
1055                        named: false,
1056                    },
1057                    NodeTypeJSON {
1058                        kind: "v3".to_string(),
1059                        named: true,
1060                    },
1061                    NodeTypeJSON {
1062                        kind: "v4".to_string(),
1063                        named: true,
1064                    },
1065                ]),
1066            }
1067        );
1068        assert_eq!(
1069            node_types[1],
1070            NodeInfoJSON {
1071                kind: "v1".to_string(),
1072                named: true,
1073                root: true,
1074                extra: false,
1075                subtypes: None,
1076                children: None,
1077                fields: Some(
1078                    vec![(
1079                        "f1".to_string(),
1080                        FieldInfoJSON {
1081                            multiple: false,
1082                            required: true,
1083                            types: vec![NodeTypeJSON {
1084                                kind: "_v2".to_string(),
1085                                named: true,
1086                            }]
1087                        }
1088                    ),]
1089                    .into_iter()
1090                    .collect()
1091                )
1092            }
1093        );
1094    }
1095
1096    #[test]
1097    fn test_node_types_for_children_without_fields() {
1098        let node_types = get_node_types(&InputGrammar {
1099            variables: vec![
1100                Variable {
1101                    name: "v1".to_string(),
1102                    kind: VariableType::Named,
1103                    rule: Rule::seq(vec![
1104                        Rule::named("v2"),
1105                        Rule::field("f1".to_string(), Rule::named("v3")),
1106                        Rule::named("v4"),
1107                    ]),
1108                },
1109                Variable {
1110                    name: "v2".to_string(),
1111                    kind: VariableType::Named,
1112                    rule: Rule::seq(vec![
1113                        Rule::string("{"),
1114                        Rule::choice(vec![Rule::named("v3"), Rule::Blank]),
1115                        Rule::string("}"),
1116                    ]),
1117                },
1118                Variable {
1119                    name: "v3".to_string(),
1120                    kind: VariableType::Named,
1121                    rule: Rule::string("x"),
1122                },
1123                Variable {
1124                    name: "v4".to_string(),
1125                    kind: VariableType::Named,
1126                    rule: Rule::string("y"),
1127                },
1128            ],
1129            ..Default::default()
1130        });
1131
1132        assert_eq!(
1133            node_types[0],
1134            NodeInfoJSON {
1135                kind: "v1".to_string(),
1136                named: true,
1137                root: true,
1138                extra: false,
1139                subtypes: None,
1140                children: Some(FieldInfoJSON {
1141                    multiple: true,
1142                    required: true,
1143                    types: vec![
1144                        NodeTypeJSON {
1145                            kind: "v2".to_string(),
1146                            named: true,
1147                        },
1148                        NodeTypeJSON {
1149                            kind: "v4".to_string(),
1150                            named: true,
1151                        },
1152                    ]
1153                }),
1154                fields: Some(
1155                    vec![(
1156                        "f1".to_string(),
1157                        FieldInfoJSON {
1158                            multiple: false,
1159                            required: true,
1160                            types: vec![NodeTypeJSON {
1161                                kind: "v3".to_string(),
1162                                named: true,
1163                            }]
1164                        }
1165                    ),]
1166                    .into_iter()
1167                    .collect()
1168                )
1169            }
1170        );
1171        assert_eq!(
1172            node_types[1],
1173            NodeInfoJSON {
1174                kind: "v2".to_string(),
1175                named: true,
1176                root: false,
1177                extra: false,
1178                subtypes: None,
1179                children: Some(FieldInfoJSON {
1180                    multiple: false,
1181                    required: false,
1182                    types: vec![NodeTypeJSON {
1183                        kind: "v3".to_string(),
1184                        named: true,
1185                    },]
1186                }),
1187                fields: Some(BTreeMap::new()),
1188            }
1189        );
1190    }
1191
1192    #[test]
1193    fn test_node_types_with_inlined_rules() {
1194        let node_types = get_node_types(&InputGrammar {
1195            variables_to_inline: vec!["v2".to_string()],
1196            variables: vec![
1197                Variable {
1198                    name: "v1".to_string(),
1199                    kind: VariableType::Named,
1200                    rule: Rule::seq(vec![Rule::named("v2"), Rule::named("v3")]),
1201                },
1202                // v2 should not appear in the node types, since it is inlined
1203                Variable {
1204                    name: "v2".to_string(),
1205                    kind: VariableType::Named,
1206                    rule: Rule::alias(Rule::string("a"), "x".to_string(), true),
1207                },
1208                Variable {
1209                    name: "v3".to_string(),
1210                    kind: VariableType::Named,
1211                    rule: Rule::string("b"),
1212                },
1213            ],
1214            ..Default::default()
1215        });
1216
1217        assert_eq!(
1218            node_types[0],
1219            NodeInfoJSON {
1220                kind: "v1".to_string(),
1221                named: true,
1222                root: true,
1223                extra: false,
1224                subtypes: None,
1225                children: Some(FieldInfoJSON {
1226                    multiple: true,
1227                    required: true,
1228                    types: vec![
1229                        NodeTypeJSON {
1230                            kind: "v3".to_string(),
1231                            named: true,
1232                        },
1233                        NodeTypeJSON {
1234                            kind: "x".to_string(),
1235                            named: true,
1236                        },
1237                    ]
1238                }),
1239                fields: Some(BTreeMap::new()),
1240            }
1241        );
1242    }
1243
1244    #[test]
1245    fn test_node_types_for_aliased_nodes() {
1246        let node_types = get_node_types(&InputGrammar {
1247            variables: vec![
1248                Variable {
1249                    name: "thing".to_string(),
1250                    kind: VariableType::Named,
1251                    rule: Rule::choice(vec![Rule::named("type"), Rule::named("expression")]),
1252                },
1253                Variable {
1254                    name: "type".to_string(),
1255                    kind: VariableType::Named,
1256                    rule: Rule::choice(vec![
1257                        Rule::alias(
1258                            Rule::named("identifier"),
1259                            "type_identifier".to_string(),
1260                            true,
1261                        ),
1262                        Rule::string("void"),
1263                    ]),
1264                },
1265                Variable {
1266                    name: "expression".to_string(),
1267                    kind: VariableType::Named,
1268                    rule: Rule::choice(vec![
1269                        Rule::named("identifier"),
1270                        Rule::alias(
1271                            Rule::named("foo_identifier"),
1272                            "identifier".to_string(),
1273                            true,
1274                        ),
1275                    ]),
1276                },
1277                Variable {
1278                    name: "identifier".to_string(),
1279                    kind: VariableType::Named,
1280                    rule: Rule::pattern("\\w+", ""),
1281                },
1282                Variable {
1283                    name: "foo_identifier".to_string(),
1284                    kind: VariableType::Named,
1285                    rule: Rule::pattern("[\\w-]+", ""),
1286                },
1287            ],
1288            ..Default::default()
1289        });
1290
1291        assert_eq!(node_types.iter().find(|t| t.kind == "foo_identifier"), None);
1292        assert_eq!(
1293            node_types.iter().find(|t| t.kind == "identifier"),
1294            Some(&NodeInfoJSON {
1295                kind: "identifier".to_string(),
1296                named: true,
1297                root: false,
1298                extra: false,
1299                subtypes: None,
1300                children: None,
1301                fields: None,
1302            })
1303        );
1304        assert_eq!(
1305            node_types.iter().find(|t| t.kind == "type_identifier"),
1306            Some(&NodeInfoJSON {
1307                kind: "type_identifier".to_string(),
1308                named: true,
1309                root: false,
1310                extra: false,
1311                subtypes: None,
1312                children: None,
1313                fields: None,
1314            })
1315        );
1316    }
1317
1318    #[test]
1319    fn test_node_types_with_multiple_valued_fields() {
1320        let node_types = get_node_types(&InputGrammar {
1321            variables: vec![
1322                Variable {
1323                    name: "a".to_string(),
1324                    kind: VariableType::Named,
1325                    rule: Rule::seq(vec![
1326                        Rule::choice(vec![
1327                            Rule::Blank,
1328                            Rule::repeat(Rule::field("f1".to_string(), Rule::named("b"))),
1329                        ]),
1330                        Rule::repeat(Rule::named("c")),
1331                    ]),
1332                },
1333                Variable {
1334                    name: "b".to_string(),
1335                    kind: VariableType::Named,
1336                    rule: Rule::string("b"),
1337                },
1338                Variable {
1339                    name: "c".to_string(),
1340                    kind: VariableType::Named,
1341                    rule: Rule::string("c"),
1342                },
1343            ],
1344            ..Default::default()
1345        });
1346
1347        assert_eq!(
1348            node_types[0],
1349            NodeInfoJSON {
1350                kind: "a".to_string(),
1351                named: true,
1352                root: true,
1353                extra: false,
1354                subtypes: None,
1355                children: Some(FieldInfoJSON {
1356                    multiple: true,
1357                    required: true,
1358                    types: vec![NodeTypeJSON {
1359                        kind: "c".to_string(),
1360                        named: true,
1361                    },]
1362                }),
1363                fields: Some(
1364                    vec![(
1365                        "f1".to_string(),
1366                        FieldInfoJSON {
1367                            multiple: true,
1368                            required: false,
1369                            types: vec![NodeTypeJSON {
1370                                kind: "b".to_string(),
1371                                named: true,
1372                            }]
1373                        }
1374                    )]
1375                    .into_iter()
1376                    .collect()
1377                ),
1378            }
1379        );
1380    }
1381
1382    #[test]
1383    fn test_node_types_with_fields_on_hidden_tokens() {
1384        let node_types = get_node_types(&InputGrammar {
1385            variables: vec![Variable {
1386                name: "script".to_string(),
1387                kind: VariableType::Named,
1388                rule: Rule::seq(vec![
1389                    Rule::field("a".to_string(), Rule::pattern("hi", "")),
1390                    Rule::field("b".to_string(), Rule::pattern("bye", "")),
1391                ]),
1392            }],
1393            ..Default::default()
1394        });
1395
1396        assert_eq!(
1397            node_types,
1398            [NodeInfoJSON {
1399                kind: "script".to_string(),
1400                named: true,
1401                root: true,
1402                extra: false,
1403                fields: Some(BTreeMap::new()),
1404                children: None,
1405                subtypes: None
1406            }]
1407        );
1408    }
1409
1410    #[test]
1411    fn test_node_types_with_multiple_rules_same_alias_name() {
1412        let node_types = get_node_types(&InputGrammar {
1413            variables: vec![
1414                Variable {
1415                    name: "script".to_string(),
1416                    kind: VariableType::Named,
1417                    rule: Rule::choice(vec![
1418                        Rule::named("a"),
1419                        // Rule `b` is aliased as rule `a`
1420                        Rule::alias(Rule::named("b"), "a".to_string(), true),
1421                    ]),
1422                },
1423                Variable {
1424                    name: "a".to_string(),
1425                    kind: VariableType::Named,
1426                    rule: Rule::seq(vec![
1427                        Rule::field("f1".to_string(), Rule::string("1")),
1428                        Rule::field("f2".to_string(), Rule::string("2")),
1429                    ]),
1430                },
1431                Variable {
1432                    name: "b".to_string(),
1433                    kind: VariableType::Named,
1434                    rule: Rule::seq(vec![
1435                        Rule::field("f2".to_string(), Rule::string("22")),
1436                        Rule::field("f2".to_string(), Rule::string("222")),
1437                        Rule::field("f3".to_string(), Rule::string("3")),
1438                    ]),
1439                },
1440            ],
1441            ..Default::default()
1442        });
1443
1444        assert_eq!(
1445            &node_types
1446                .iter()
1447                .map(|t| t.kind.as_str())
1448                .collect::<Vec<_>>(),
1449            &["a", "script", "1", "2", "22", "222", "3"]
1450        );
1451
1452        assert_eq!(
1453            &node_types[0..2],
1454            &[
1455                // A combination of the types for `a` and `b`.
1456                NodeInfoJSON {
1457                    kind: "a".to_string(),
1458                    named: true,
1459                    root: false,
1460                    extra: false,
1461                    subtypes: None,
1462                    children: None,
1463                    fields: Some(
1464                        vec![
1465                            (
1466                                "f1".to_string(),
1467                                FieldInfoJSON {
1468                                    multiple: false,
1469                                    required: false,
1470                                    types: vec![NodeTypeJSON {
1471                                        kind: "1".to_string(),
1472                                        named: false,
1473                                    }]
1474                                }
1475                            ),
1476                            (
1477                                "f2".to_string(),
1478                                FieldInfoJSON {
1479                                    multiple: true,
1480                                    required: true,
1481                                    types: vec![
1482                                        NodeTypeJSON {
1483                                            kind: "2".to_string(),
1484                                            named: false,
1485                                        },
1486                                        NodeTypeJSON {
1487                                            kind: "22".to_string(),
1488                                            named: false,
1489                                        },
1490                                        NodeTypeJSON {
1491                                            kind: "222".to_string(),
1492                                            named: false,
1493                                        }
1494                                    ]
1495                                },
1496                            ),
1497                            (
1498                                "f3".to_string(),
1499                                FieldInfoJSON {
1500                                    multiple: false,
1501                                    required: false,
1502                                    types: vec![NodeTypeJSON {
1503                                        kind: "3".to_string(),
1504                                        named: false,
1505                                    }]
1506                                }
1507                            ),
1508                        ]
1509                        .into_iter()
1510                        .collect()
1511                    ),
1512                },
1513                NodeInfoJSON {
1514                    kind: "script".to_string(),
1515                    named: true,
1516                    root: true,
1517                    extra: false,
1518                    subtypes: None,
1519                    // Only one node
1520                    children: Some(FieldInfoJSON {
1521                        multiple: false,
1522                        required: true,
1523                        types: vec![NodeTypeJSON {
1524                            kind: "a".to_string(),
1525                            named: true,
1526                        }]
1527                    }),
1528                    fields: Some(BTreeMap::new()),
1529                }
1530            ]
1531        );
1532    }
1533
1534    #[test]
1535    fn test_node_types_with_tokens_aliased_to_match_rules() {
1536        let node_types = get_node_types(&InputGrammar {
1537            variables: vec![
1538                Variable {
1539                    name: "a".to_string(),
1540                    kind: VariableType::Named,
1541                    rule: Rule::seq(vec![Rule::named("b"), Rule::named("c")]),
1542                },
1543                // Ordinarily, `b` nodes have two named `c` children.
1544                Variable {
1545                    name: "b".to_string(),
1546                    kind: VariableType::Named,
1547                    rule: Rule::seq(vec![Rule::named("c"), Rule::string("B"), Rule::named("c")]),
1548                },
1549                Variable {
1550                    name: "c".to_string(),
1551                    kind: VariableType::Named,
1552                    rule: Rule::choice(vec![
1553                        Rule::string("C"),
1554                        // This token is aliased as a `b`, which will produce a `b` node
1555                        // with no children.
1556                        Rule::alias(Rule::string("D"), "b".to_string(), true),
1557                    ]),
1558                },
1559            ],
1560            ..Default::default()
1561        });
1562
1563        assert_eq!(
1564            node_types.iter().map(|n| &n.kind).collect::<Vec<_>>(),
1565            &["a", "b", "c", "B", "C"]
1566        );
1567        assert_eq!(
1568            node_types[1],
1569            NodeInfoJSON {
1570                kind: "b".to_string(),
1571                named: true,
1572                root: false,
1573                extra: false,
1574                subtypes: None,
1575                children: Some(FieldInfoJSON {
1576                    multiple: true,
1577                    required: false,
1578                    types: vec![NodeTypeJSON {
1579                        kind: "c".to_string(),
1580                        named: true,
1581                    }]
1582                }),
1583                fields: Some(BTreeMap::new()),
1584            }
1585        );
1586    }
1587
1588    #[test]
1589    fn test_get_variable_info() {
1590        let variable_info = get_variable_info(
1591            &build_syntax_grammar(
1592                vec![
1593                    // Required field `field1` has only one node type.
1594                    SyntaxVariable {
1595                        name: "rule0".to_string(),
1596                        kind: VariableType::Named,
1597                        productions: vec![Production {
1598                            dynamic_precedence: 0,
1599                            steps: vec![
1600                                ProductionStep::new(Symbol::terminal(0)),
1601                                ProductionStep::new(Symbol::non_terminal(1))
1602                                    .with_field_name("field1"),
1603                            ],
1604                        }],
1605                    },
1606                    // Hidden node
1607                    SyntaxVariable {
1608                        name: "_rule1".to_string(),
1609                        kind: VariableType::Hidden,
1610                        productions: vec![Production {
1611                            dynamic_precedence: 0,
1612                            steps: vec![ProductionStep::new(Symbol::terminal(1))],
1613                        }],
1614                    },
1615                    // Optional field `field2` can have two possible node types.
1616                    SyntaxVariable {
1617                        name: "rule2".to_string(),
1618                        kind: VariableType::Named,
1619                        productions: vec![
1620                            Production {
1621                                dynamic_precedence: 0,
1622                                steps: vec![ProductionStep::new(Symbol::terminal(0))],
1623                            },
1624                            Production {
1625                                dynamic_precedence: 0,
1626                                steps: vec![
1627                                    ProductionStep::new(Symbol::terminal(0)),
1628                                    ProductionStep::new(Symbol::terminal(2))
1629                                        .with_field_name("field2"),
1630                                ],
1631                            },
1632                            Production {
1633                                dynamic_precedence: 0,
1634                                steps: vec![
1635                                    ProductionStep::new(Symbol::terminal(0)),
1636                                    ProductionStep::new(Symbol::terminal(3))
1637                                        .with_field_name("field2"),
1638                                ],
1639                            },
1640                        ],
1641                    },
1642                ],
1643                vec![],
1644            ),
1645            &build_lexical_grammar(),
1646            &AliasMap::new(),
1647        )
1648        .unwrap();
1649
1650        assert_eq!(
1651            variable_info[0].fields,
1652            vec![(
1653                "field1".to_string(),
1654                FieldInfo {
1655                    quantity: ChildQuantity {
1656                        exists: true,
1657                        required: true,
1658                        multiple: false,
1659                    },
1660                    types: vec![ChildType::Normal(Symbol::terminal(1))],
1661                }
1662            )]
1663            .into_iter()
1664            .collect::<HashMap<_, _>>()
1665        );
1666
1667        assert_eq!(
1668            variable_info[2].fields,
1669            vec![(
1670                "field2".to_string(),
1671                FieldInfo {
1672                    quantity: ChildQuantity {
1673                        exists: true,
1674                        required: false,
1675                        multiple: false,
1676                    },
1677                    types: vec![
1678                        ChildType::Normal(Symbol::terminal(2)),
1679                        ChildType::Normal(Symbol::terminal(3)),
1680                    ],
1681                }
1682            )]
1683            .into_iter()
1684            .collect::<HashMap<_, _>>()
1685        );
1686    }
1687
1688    #[test]
1689    fn test_get_variable_info_with_repetitions_inside_fields() {
1690        let variable_info = get_variable_info(
1691            &build_syntax_grammar(
1692                vec![
1693                    // Field associated with a repetition.
1694                    SyntaxVariable {
1695                        name: "rule0".to_string(),
1696                        kind: VariableType::Named,
1697                        productions: vec![
1698                            Production {
1699                                dynamic_precedence: 0,
1700                                steps: vec![ProductionStep::new(Symbol::non_terminal(1))
1701                                    .with_field_name("field1")],
1702                            },
1703                            Production {
1704                                dynamic_precedence: 0,
1705                                steps: vec![],
1706                            },
1707                        ],
1708                    },
1709                    // Repetition node
1710                    SyntaxVariable {
1711                        name: "_rule0_repeat".to_string(),
1712                        kind: VariableType::Hidden,
1713                        productions: vec![
1714                            Production {
1715                                dynamic_precedence: 0,
1716                                steps: vec![ProductionStep::new(Symbol::terminal(1))],
1717                            },
1718                            Production {
1719                                dynamic_precedence: 0,
1720                                steps: vec![
1721                                    ProductionStep::new(Symbol::non_terminal(1)),
1722                                    ProductionStep::new(Symbol::non_terminal(1)),
1723                                ],
1724                            },
1725                        ],
1726                    },
1727                ],
1728                vec![],
1729            ),
1730            &build_lexical_grammar(),
1731            &AliasMap::new(),
1732        )
1733        .unwrap();
1734
1735        assert_eq!(
1736            variable_info[0].fields,
1737            vec![(
1738                "field1".to_string(),
1739                FieldInfo {
1740                    quantity: ChildQuantity {
1741                        exists: true,
1742                        required: false,
1743                        multiple: true,
1744                    },
1745                    types: vec![ChildType::Normal(Symbol::terminal(1))],
1746                }
1747            )]
1748            .into_iter()
1749            .collect::<HashMap<_, _>>()
1750        );
1751    }
1752
1753    #[test]
1754    fn test_get_variable_info_with_inherited_fields() {
1755        let variable_info = get_variable_info(
1756            &build_syntax_grammar(
1757                vec![
1758                    SyntaxVariable {
1759                        name: "rule0".to_string(),
1760                        kind: VariableType::Named,
1761                        productions: vec![
1762                            Production {
1763                                dynamic_precedence: 0,
1764                                steps: vec![
1765                                    ProductionStep::new(Symbol::terminal(0)),
1766                                    ProductionStep::new(Symbol::non_terminal(1)),
1767                                    ProductionStep::new(Symbol::terminal(1)),
1768                                ],
1769                            },
1770                            Production {
1771                                dynamic_precedence: 0,
1772                                steps: vec![ProductionStep::new(Symbol::non_terminal(1))],
1773                            },
1774                        ],
1775                    },
1776                    // Hidden node with fields
1777                    SyntaxVariable {
1778                        name: "_rule1".to_string(),
1779                        kind: VariableType::Hidden,
1780                        productions: vec![Production {
1781                            dynamic_precedence: 0,
1782                            steps: vec![
1783                                ProductionStep::new(Symbol::terminal(2)).with_alias(".", false),
1784                                ProductionStep::new(Symbol::terminal(3)).with_field_name("field1"),
1785                            ],
1786                        }],
1787                    },
1788                ],
1789                vec![],
1790            ),
1791            &build_lexical_grammar(),
1792            &AliasMap::new(),
1793        )
1794        .unwrap();
1795
1796        assert_eq!(
1797            variable_info[0].fields,
1798            vec![(
1799                "field1".to_string(),
1800                FieldInfo {
1801                    quantity: ChildQuantity {
1802                        exists: true,
1803                        required: true,
1804                        multiple: false,
1805                    },
1806                    types: vec![ChildType::Normal(Symbol::terminal(3))],
1807                }
1808            )]
1809            .into_iter()
1810            .collect::<HashMap<_, _>>()
1811        );
1812
1813        assert_eq!(
1814            variable_info[0].children_without_fields,
1815            FieldInfo {
1816                quantity: ChildQuantity {
1817                    exists: true,
1818                    required: false,
1819                    multiple: true,
1820                },
1821                types: vec![
1822                    ChildType::Normal(Symbol::terminal(0)),
1823                    ChildType::Normal(Symbol::terminal(1)),
1824                ],
1825            }
1826        );
1827    }
1828
1829    #[test]
1830    fn test_get_variable_info_with_supertypes() {
1831        let variable_info = get_variable_info(
1832            &build_syntax_grammar(
1833                vec![
1834                    SyntaxVariable {
1835                        name: "rule0".to_string(),
1836                        kind: VariableType::Named,
1837                        productions: vec![Production {
1838                            dynamic_precedence: 0,
1839                            steps: vec![
1840                                ProductionStep::new(Symbol::terminal(0)),
1841                                ProductionStep::new(Symbol::non_terminal(1))
1842                                    .with_field_name("field1"),
1843                                ProductionStep::new(Symbol::terminal(1)),
1844                            ],
1845                        }],
1846                    },
1847                    SyntaxVariable {
1848                        name: "_rule1".to_string(),
1849                        kind: VariableType::Hidden,
1850                        productions: vec![
1851                            Production {
1852                                dynamic_precedence: 0,
1853                                steps: vec![ProductionStep::new(Symbol::terminal(2))],
1854                            },
1855                            Production {
1856                                dynamic_precedence: 0,
1857                                steps: vec![ProductionStep::new(Symbol::terminal(3))],
1858                            },
1859                        ],
1860                    },
1861                ],
1862                // _rule1 is a supertype
1863                vec![Symbol::non_terminal(1)],
1864            ),
1865            &build_lexical_grammar(),
1866            &AliasMap::new(),
1867        )
1868        .unwrap();
1869
1870        assert_eq!(
1871            variable_info[0].fields,
1872            vec![(
1873                "field1".to_string(),
1874                FieldInfo {
1875                    quantity: ChildQuantity {
1876                        exists: true,
1877                        required: true,
1878                        multiple: false,
1879                    },
1880                    types: vec![ChildType::Normal(Symbol::non_terminal(1))],
1881                }
1882            )]
1883            .into_iter()
1884            .collect::<HashMap<_, _>>()
1885        );
1886    }
1887
1888    fn get_node_types(grammar: &InputGrammar) -> Vec<NodeInfoJSON> {
1889        let (syntax_grammar, lexical_grammar, _, default_aliases) =
1890            prepare_grammar(grammar).unwrap();
1891        let variable_info =
1892            get_variable_info(&syntax_grammar, &lexical_grammar, &default_aliases).unwrap();
1893        generate_node_types_json(
1894            &syntax_grammar,
1895            &lexical_grammar,
1896            &default_aliases,
1897            &variable_info,
1898        )
1899    }
1900
1901    fn build_syntax_grammar(
1902        variables: Vec<SyntaxVariable>,
1903        supertype_symbols: Vec<Symbol>,
1904    ) -> SyntaxGrammar {
1905        SyntaxGrammar {
1906            variables,
1907            supertype_symbols,
1908            ..SyntaxGrammar::default()
1909        }
1910    }
1911
1912    fn build_lexical_grammar() -> LexicalGrammar {
1913        let mut lexical_grammar = LexicalGrammar::default();
1914        for i in 0..10 {
1915            lexical_grammar.variables.push(LexicalVariable {
1916                name: format!("token_{i}"),
1917                kind: VariableType::Named,
1918                implicit_precedence: 0,
1919                start_state: 0,
1920            });
1921        }
1922        lexical_grammar
1923    }
1924}