diff --git a/cli/src/generate/mod.rs b/cli/src/generate/mod.rs index 9e640423..b5c4c0e4 100644 --- a/cli/src/generate/mod.rs +++ b/cli/src/generate/mod.rs @@ -1,15 +1,10 @@ use self::build_tables::build_tables; -use self::grammars::{LexicalGrammar, SyntaxGrammar, VariableType}; use self::parse_grammar::parse_grammar; use self::prepare_grammar::prepare_grammar; use self::render::render_c_code; -use self::rules::{AliasMap, Symbol, SymbolType}; -use self::tables::{ChildType, VariableInfo}; use crate::error::{Error, Result}; use lazy_static::lazy_static; use regex::{Regex, RegexBuilder}; -use serde_derive::Serialize; -use std::collections::BTreeMap; use std::fs; use std::io::Write; use std::path::{Path, PathBuf}; @@ -18,6 +13,7 @@ use std::process::{Command, Stdio}; mod build_tables; mod grammars; mod nfa; +mod node_types; mod npm_files; mod parse_grammar; mod prepare_grammar; @@ -112,7 +108,7 @@ fn generate_parser_for_grammar_with_opts( state_ids_to_log, )?; let name = input_grammar.name; - let node_types_json = generate_node_types_json( + let node_types_json = node_types::generate_node_types_json( &syntax_grammar, &lexical_grammar, &simple_aliases, @@ -131,7 +127,7 @@ fn generate_parser_for_grammar_with_opts( Ok(GeneratedParser { name, c_code, - node_types_json, + node_types_json: serde_json::to_string_pretty(&node_types_json).unwrap(), }) } @@ -185,133 +181,3 @@ fn ensure_file>(path: &PathBuf, f: impl Fn() -> T) -> Result<()> .map_err(|e| Error(format!("Failed to write file {:?}: {}", path, e))) } } - -#[derive(Debug, Serialize, PartialEq, Eq, Default)] -struct NodeInfoJSON { - #[serde(rename = "type")] - name: String, - #[serde(skip_serializing_if = "Option::is_none")] - fields: Option>, - #[serde(skip_serializing_if = "Option::is_none")] - subtypes: Option>, -} - -#[derive(Debug, Serialize, PartialEq, Eq, PartialOrd, Ord)] -struct NodeTypeJSON { - #[serde(rename = "type")] - kind: String, - named: bool, -} - -#[derive(Debug, Serialize, PartialEq, Eq)] -struct FieldInfoJSON { - multiple: bool, - required: bool, - types: Vec, -} - -fn generate_node_types_json( - syntax_grammar: &SyntaxGrammar, - lexical_grammar: &LexicalGrammar, - simple_aliases: &AliasMap, - variable_info: &Vec, -) -> String { - let mut node_types_json = BTreeMap::new(); - - let child_type_to_node_type = |child_type: &ChildType| match child_type { - ChildType::Aliased(alias) => NodeTypeJSON { - kind: alias.value.clone(), - named: alias.is_named, - }, - ChildType::Normal(symbol) => { - if let Some(alias) = simple_aliases.get(&symbol) { - NodeTypeJSON { - kind: alias.value.clone(), - named: alias.is_named, - } - } else { - match symbol.kind { - SymbolType::NonTerminal => { - let variable = &syntax_grammar.variables[symbol.index]; - NodeTypeJSON { - kind: variable.name.clone(), - named: variable.kind == VariableType::Named, - } - } - SymbolType::Terminal => { - let variable = &lexical_grammar.variables[symbol.index]; - NodeTypeJSON { - kind: variable.name.clone(), - named: variable.kind == VariableType::Named, - } - } - SymbolType::External => { - let variable = &syntax_grammar.external_tokens[symbol.index]; - NodeTypeJSON { - kind: variable.name.clone(), - named: variable.kind == VariableType::Named, - } - } - _ => panic!("Unexpected symbol type"), - } - } - } - }; - - for (i, info) in variable_info.iter().enumerate() { - let symbol = Symbol::non_terminal(i); - let variable = &syntax_grammar.variables[i]; - let name = simple_aliases - .get(&Symbol::non_terminal(i)) - .map_or(&variable.name, |alias| &alias.value); - - if syntax_grammar.supertype_symbols.contains(&symbol) { - let node_type_json = - node_types_json - .entry(name.clone()) - .or_insert_with(|| NodeInfoJSON { - name: name.clone(), - fields: None, - subtypes: None, - }); - let mut subtypes = info.child_types - .iter() - .map(child_type_to_node_type) - .collect::>(); - subtypes.sort_unstable(); - subtypes.dedup(); - node_type_json.subtypes = Some(subtypes); - - } else if variable.kind.is_visible() { - let node_type_json = - node_types_json - .entry(name.clone()) - .or_insert_with(|| NodeInfoJSON { - name: name.clone(), - fields: None, - subtypes: None, - }); - let mut fields_json = BTreeMap::new(); - for (field, field_info) in info.fields.iter() { - let field_info_json = fields_json.entry(field.clone()).or_insert(FieldInfoJSON { - multiple: false, - required: true, - types: Vec::new(), - }); - - field_info_json.multiple |= field_info.multiple; - field_info_json.required &= field_info.required; - field_info_json - .types - .extend(field_info.types.iter().map(child_type_to_node_type)); - field_info_json.types.sort_unstable(); - field_info_json.types.dedup(); - } - node_type_json.fields = Some(fields_json); - } - } - - let node_types_json = node_types_json.values().collect::>(); - - serde_json::to_string_pretty(&node_types_json).unwrap() -} diff --git a/cli/src/generate/node_types.rs b/cli/src/generate/node_types.rs new file mode 100644 index 00000000..35129189 --- /dev/null +++ b/cli/src/generate/node_types.rs @@ -0,0 +1,133 @@ +use super::grammars::{LexicalGrammar, SyntaxGrammar, VariableType}; +use super::rules::{AliasMap, Symbol, SymbolType}; +use super::tables::{ChildType, VariableInfo}; +use serde_derive::Serialize; +use std::collections::BTreeMap; + +#[derive(Debug, Serialize, PartialEq, Eq, Default)] +pub(crate) struct NodeInfoJSON { + #[serde(rename = "type")] + name: String, + #[serde(skip_serializing_if = "Option::is_none")] + fields: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + subtypes: Option>, +} + +#[derive(Debug, Serialize, PartialEq, Eq, PartialOrd, Ord)] +pub(crate) struct NodeTypeJSON { + #[serde(rename = "type")] + kind: String, + named: bool, +} + +#[derive(Debug, Serialize, PartialEq, Eq)] +pub(crate) struct FieldInfoJSON { + multiple: bool, + required: bool, + types: Vec, +} + +pub(crate) fn generate_node_types_json( + syntax_grammar: &SyntaxGrammar, + lexical_grammar: &LexicalGrammar, + simple_aliases: &AliasMap, + variable_info: &Vec, +) -> Vec { + let mut node_types_json = BTreeMap::new(); + + let child_type_to_node_type = |child_type: &ChildType| match child_type { + ChildType::Aliased(alias) => NodeTypeJSON { + kind: alias.value.clone(), + named: alias.is_named, + }, + ChildType::Normal(symbol) => { + if let Some(alias) = simple_aliases.get(&symbol) { + NodeTypeJSON { + kind: alias.value.clone(), + named: alias.is_named, + } + } else { + match symbol.kind { + SymbolType::NonTerminal => { + let variable = &syntax_grammar.variables[symbol.index]; + NodeTypeJSON { + kind: variable.name.clone(), + named: variable.kind == VariableType::Named, + } + } + SymbolType::Terminal => { + let variable = &lexical_grammar.variables[symbol.index]; + NodeTypeJSON { + kind: variable.name.clone(), + named: variable.kind == VariableType::Named, + } + } + SymbolType::External => { + let variable = &syntax_grammar.external_tokens[symbol.index]; + NodeTypeJSON { + kind: variable.name.clone(), + named: variable.kind == VariableType::Named, + } + } + _ => panic!("Unexpected symbol type"), + } + } + } + }; + + for (i, info) in variable_info.iter().enumerate() { + let symbol = Symbol::non_terminal(i); + let variable = &syntax_grammar.variables[i]; + let name = simple_aliases + .get(&Symbol::non_terminal(i)) + .map_or(&variable.name, |alias| &alias.value); + + if syntax_grammar.supertype_symbols.contains(&symbol) { + let node_type_json = + node_types_json + .entry(name.clone()) + .or_insert_with(|| NodeInfoJSON { + name: name.clone(), + fields: None, + subtypes: None, + }); + let mut subtypes = info + .child_types + .iter() + .map(child_type_to_node_type) + .collect::>(); + subtypes.sort_unstable(); + subtypes.dedup(); + node_type_json.subtypes = Some(subtypes); + } else if variable.kind.is_visible() { + let node_type_json = + node_types_json + .entry(name.clone()) + .or_insert_with(|| NodeInfoJSON { + name: name.clone(), + fields: None, + subtypes: None, + }); + let mut fields_json = BTreeMap::new(); + for (field, field_info) in info.fields.iter() { + let field_info_json = fields_json.entry(field.clone()).or_insert(FieldInfoJSON { + multiple: false, + required: true, + types: Vec::new(), + }); + + field_info_json.multiple |= field_info.multiple; + field_info_json.required &= field_info.required; + field_info_json + .types + .extend(field_info.types.iter().map(child_type_to_node_type)); + field_info_json.types.sort_unstable(); + field_info_json.types.dedup(); + } + node_type_json.fields = Some(fields_json); + } + } + + node_types_json.into_iter().map(|e| e.1).collect() +}