diff --git a/crates/codegen/runtime/cargo/src/runtime/kinds.rs.jinja2 b/crates/codegen/runtime/cargo/src/runtime/kinds.rs.jinja2 index 30e59186fb..850d2499ce 100644 --- a/crates/codegen/runtime/cargo/src/runtime/kinds.rs.jinja2 +++ b/crates/codegen/runtime/cargo/src/runtime/kinds.rs.jinja2 @@ -22,7 +22,7 @@ pub enum NonterminalKind { Stub2, Stub3, {%- else -%} - {%- for variant in model.parser.nonterminal_kinds -%} + {%- for variant in model.kinds.nonterminal_kinds -%} {# variant.documentation | indent(prefix = "/// ", first = true, blank = true) #} {{ variant }}, {%- endfor -%} @@ -65,7 +65,7 @@ pub enum EdgeLabel { Stub2, Stub3, {%- else -%} - {% for variant in model.parser.labels -%} + {% for variant in model.kinds.labels -%} {{ variant | pascal_case }}, {%- endfor -%} {%- endif -%} @@ -98,7 +98,7 @@ pub enum TerminalKind { Stub2, Stub3, {%- else -%} - {%- for variant in model.parser.terminal_kinds -%} + {%- for variant in model.kinds.terminal_kinds -%} {# variant.documentation | indent(prefix = "/// ", first = true, blank = true) #} {{ variant }}, {%- endfor -%} @@ -112,7 +112,7 @@ impl metaslang_cst::TerminalKind for TerminalKind { {%- else -%} matches!( self, - {%- for variant in model.parser.trivia_scanner_names -%} + {%- for variant in model.kinds.trivia_scanner_names -%} | Self::{{ variant }} {%- endfor -%} ) @@ -128,7 +128,7 @@ pub(crate) enum LexicalContext { Stub2, Stub3, {%- else -%} - {%- for context_name, _ in model.parser.scanner_contexts %} + {%- for context_name in model.kinds.lexical_contexts %} {{ context_name }}, {%- endfor %} {%- endif -%} @@ -143,7 +143,7 @@ pub(crate) trait IsLexicalContext { #[allow(non_snake_case)] pub(crate) mod LexicalContextType { {%- if not rendering_in_stubs -%} - {%- for context_name, _ in model.parser.scanner_contexts %} + {%- for context_name in model.kinds.lexical_contexts %} pub struct {{ context_name }}; impl super::IsLexicalContext for {{ context_name }} { diff --git a/crates/codegen/runtime/generator/src/kinds.rs b/crates/codegen/runtime/generator/src/kinds.rs new file mode 100644 index 0000000000..3d157ba90f --- /dev/null +++ b/crates/codegen/runtime/generator/src/kinds.rs @@ -0,0 +1,98 @@ +use std::collections::BTreeSet; + +use codegen_language_definition::model::{self, Identifier, Item}; +use serde::Serialize; + +#[derive(Default, Serialize)] +pub struct KindsModel { + /// Defines the `NonterminalKind` enum variants. + nonterminal_kinds: BTreeSet, + /// Defines the `TerminalKind` enum variants. + terminal_kinds: BTreeSet, + /// Defines `TerminalKind::is_trivia` method. + trivia_scanner_names: BTreeSet, + /// Defines `EdgeLabel` enum variants. + labels: BTreeSet, + // Defines the `LexicalContext(Type)` enum and type-level variants. + lexical_contexts: BTreeSet, +} + +impl KindsModel { + pub fn create(language: &model::Language) -> Self { + let terminal_kinds = language + .items() + .filter(|item| item.is_terminal() && !matches!(item, Item::Fragment { .. })) + .map(|item| item.name().clone()) + .collect(); + + let mut nonterminal_kinds = BTreeSet::default(); + for item in language.items() { + match item { + Item::Struct { item } => { + nonterminal_kinds.insert(item.name.clone()); + } + Item::Enum { item } => { + nonterminal_kinds.insert(item.name.clone()); + } + Item::Repeated { item } => { + nonterminal_kinds.insert(item.name.clone()); + } + Item::Separated { item } => { + nonterminal_kinds.insert(item.name.clone()); + } + Item::Precedence { item } => { + nonterminal_kinds.insert(item.name.clone()); + for op in &item.precedence_expressions { + nonterminal_kinds.insert(op.name.clone()); + } + } + // Terminals + _ => {} + } + } + + let trivia_scanner_names = language + .items() + .filter_map(|item| match item { + Item::Trivia { item } => Some(item.name.clone()), + _ => None, + }) + .collect(); + + let mut labels = BTreeSet::default(); + for item in language.items() { + match item { + Item::Struct { item } => { + for field_name in item.fields.keys() { + labels.insert(field_name.clone()); + } + } + Item::Precedence { item } => { + for item in &item.precedence_expressions { + for item in &item.operators { + for field_name in item.fields.keys() { + labels.insert(field_name.clone()); + } + } + } + } + _ => {} + } + } + + let lexical_contexts: BTreeSet<_> = language + .topics() + .filter_map(|t| t.lexical_context.as_ref()) + .cloned() + .chain(std::iter::once(Identifier::from("Default"))) + .collect(); + + KindsModel { + nonterminal_kinds, + terminal_kinds, + trivia_scanner_names, + labels, + lexical_contexts, + } + } +} diff --git a/crates/codegen/runtime/generator/src/lib.rs b/crates/codegen/runtime/generator/src/lib.rs index 24d3e5e046..b74b1c8d9f 100644 --- a/crates/codegen/runtime/generator/src/lib.rs +++ b/crates/codegen/runtime/generator/src/lib.rs @@ -10,6 +10,7 @@ use serde::Serialize; use crate::model::RuntimeModel; mod ast; +mod kinds; mod model; mod parser; diff --git a/crates/codegen/runtime/generator/src/model.rs b/crates/codegen/runtime/generator/src/model.rs index a241ff48a7..308d8e8845 100644 --- a/crates/codegen/runtime/generator/src/model.rs +++ b/crates/codegen/runtime/generator/src/model.rs @@ -6,6 +6,7 @@ use semver::Version; use serde::Serialize; use crate::ast::AstModel; +use crate::kinds::KindsModel; use crate::parser::ParserModel; #[derive(Default, Serialize)] @@ -14,6 +15,7 @@ pub struct RuntimeModel { all_versions: BTreeSet, parser: ParserModel, ast: AstModel, + kinds: KindsModel, } impl RuntimeModel { @@ -22,6 +24,7 @@ impl RuntimeModel { all_versions: language.versions.iter().cloned().collect(), ast: AstModel::create(language), parser: ParserModel::from_language(language), + kinds: KindsModel::create(language), } } } diff --git a/crates/codegen/runtime/generator/src/parser.rs b/crates/codegen/runtime/generator/src/parser.rs index f4aa5ee8c1..4f86a2401c 100644 --- a/crates/codegen/runtime/generator/src/parser.rs +++ b/crates/codegen/runtime/generator/src/parser.rs @@ -3,7 +3,7 @@ use std::collections::{BTreeMap, BTreeSet}; use std::rc::Rc; -use codegen_language_definition::model::{Identifier, Item, Language}; +use codegen_language_definition::model::{Identifier, Language}; use semver::Version; use serde::Serialize; @@ -29,15 +29,6 @@ pub struct ParserModel { /// Constructs inner `Language` the state to evaluate the version-dependent branches. referenced_versions: BTreeSet, - /// Defines the `NonterminalKind` enum variants. - nonterminal_kinds: BTreeSet, - /// Defines the `TerminalKind` enum variants. - terminal_kinds: BTreeSet, - /// Defines `TerminalKind::is_trivia` method. - trivia_scanner_names: BTreeSet, - /// Defines `EdgeLabel` enum variants. - labels: BTreeSet, - /// Defines the top-level scanner functions in `Language`. scanner_functions: BTreeMap, // (name of scanner, code) // Defines the `LexicalContext(Type)` enum and type-level variants. @@ -98,14 +89,6 @@ struct ScannerContextAccumulatorState { struct DslV2CollectorState { /// Constructs inner `Language` the state to evaluate the version-dependent branches. referenced_versions: BTreeSet, - /// Defines the `TerminalKind` enum variants. - terminal_kinds: BTreeSet, - /// Defines the `NonterminalKind` enum variants. - nonterminal_kinds: BTreeSet, - /// Defines `TerminalKind::is_trivia` method. - trivia_scanner_names: BTreeSet, - /// Defines `EdgeLabel` enum variants. - labels: BTreeSet, } impl ParserModel { @@ -117,73 +100,8 @@ impl ParserModel { grammar.accept_visitor(&mut acc); // WIP(#638): Gradually migrate off `GrammarVisitor` - let terminal_kinds = language - .items() - .filter(|item| item.is_terminal() && !matches!(item, Item::Fragment { .. })) - .map(|item| item.name().clone()) - .collect(); - - let mut nonterminal_kinds = BTreeSet::default(); - for item in language.items() { - match item { - Item::Struct { item } => { - nonterminal_kinds.insert(item.name.clone()); - } - Item::Enum { item } => { - nonterminal_kinds.insert(item.name.clone()); - } - Item::Repeated { item } => { - nonterminal_kinds.insert(item.name.clone()); - } - Item::Separated { item } => { - nonterminal_kinds.insert(item.name.clone()); - } - Item::Precedence { item } => { - nonterminal_kinds.insert(item.name.clone()); - for op in &item.precedence_expressions { - nonterminal_kinds.insert(op.name.clone()); - } - } - // Terminals - _ => {} - } - } - - let trivia_scanner_names = language - .items() - .filter_map(|item| match item { - Item::Trivia { item } => Some(item.name.clone()), - _ => None, - }) - .collect(); - - let mut labels = BTreeSet::default(); - for item in language.items() { - match item { - Item::Struct { item } => { - for field_name in item.fields.keys() { - labels.insert(field_name.to_string()); - } - } - Item::Precedence { item } => { - for item in &item.precedence_expressions { - for item in &item.operators { - for field_name in item.fields.keys() { - labels.insert(field_name.to_string()); - } - } - } - } - _ => {} - } - } - acc.into_model(DslV2CollectorState { referenced_versions: language.collect_breaking_versions(), - terminal_kinds, - nonterminal_kinds, - trivia_scanner_names, - labels, }) } } @@ -288,10 +206,6 @@ impl ParserAccumulatorState { keyword_compound_scanners, // These are derived from the DSLv2 model directly referenced_versions: collected.referenced_versions, - terminal_kinds: collected.terminal_kinds, - nonterminal_kinds: collected.nonterminal_kinds, - trivia_scanner_names: collected.trivia_scanner_names, - labels: collected.labels, } } }