parent
cb87b7b76e
commit
754cfd42bf
1 changed files with 179 additions and 69 deletions
|
|
@ -5,7 +5,7 @@ use super::grammars::{
|
|||
use super::rules::{Alias, AliasMap, Symbol, SymbolType};
|
||||
use crate::error::{Error, Result};
|
||||
use serde_derive::Serialize;
|
||||
use std::collections::{BTreeMap, HashMap};
|
||||
use std::collections::{BTreeMap, HashMap, HashSet};
|
||||
use std::mem;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
|
|
@ -29,7 +29,7 @@ pub(crate) struct VariableInfo {
|
|||
pub has_multi_step_production: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, PartialEq, Eq, Default)]
|
||||
#[derive(Debug, Serialize, PartialEq, Eq, Default, PartialOrd, Ord)]
|
||||
pub(crate) struct NodeInfoJSON {
|
||||
#[serde(rename = "type")]
|
||||
kind: String,
|
||||
|
|
@ -49,7 +49,7 @@ pub(crate) struct NodeTypeJSON {
|
|||
named: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, PartialEq, Eq)]
|
||||
#[derive(Debug, Serialize, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub(crate) struct FieldInfoJSON {
|
||||
multiple: bool,
|
||||
required: bool,
|
||||
|
|
@ -309,8 +309,8 @@ pub(crate) fn get_variable_info(
|
|||
let mut variable_info = VariableInfo::default();
|
||||
mem::swap(&mut variable_info, &mut result[i]);
|
||||
|
||||
// For each field, make the `types` list more concise by replacing sets of
|
||||
// subtypes with a single supertype.
|
||||
// For each named field, make the `types` list more concise by replacing sets of
|
||||
// subtypes with a single supertype. Also remove any hidden node types.
|
||||
for (_, field_info) in variable_info.fields.iter_mut() {
|
||||
for supertype_symbol in &syntax_grammar.supertype_symbols {
|
||||
sorted_vec_replace(
|
||||
|
|
@ -319,10 +319,10 @@ pub(crate) fn get_variable_info(
|
|||
ChildType::Normal(*supertype_symbol),
|
||||
);
|
||||
}
|
||||
|
||||
field_info.types.retain(child_type_is_visible);
|
||||
}
|
||||
|
||||
// Do the same thing for the children without fields.
|
||||
for supertype_symbol in &syntax_grammar.supertype_symbols {
|
||||
sorted_vec_replace(
|
||||
&mut variable_info.children_without_fields.types,
|
||||
|
|
@ -330,7 +330,6 @@ pub(crate) fn get_variable_info(
|
|||
ChildType::Normal(*supertype_symbol),
|
||||
);
|
||||
}
|
||||
|
||||
variable_info
|
||||
.children_without_fields
|
||||
.types
|
||||
|
|
@ -511,19 +510,32 @@ pub(crate) fn generate_node_types_json(
|
|||
}
|
||||
};
|
||||
|
||||
let mut aliases_by_symbol = HashMap::new();
|
||||
for (symbol, alias) in simple_aliases {
|
||||
aliases_by_symbol.insert(*symbol, {
|
||||
let mut aliases = HashSet::new();
|
||||
aliases.insert(Some(alias.clone()));
|
||||
aliases
|
||||
});
|
||||
}
|
||||
for variable in &syntax_grammar.variables {
|
||||
for production in &variable.productions {
|
||||
for step in &production.steps {
|
||||
aliases_by_symbol.entry(step.symbol).or_insert(HashSet::new()).insert(step.alias.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
aliases_by_symbol.insert(Symbol::non_terminal(0), [None].into_iter().cloned().collect());
|
||||
|
||||
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())
|
||||
.entry(variable.name.clone())
|
||||
.or_insert_with(|| NodeInfoJSON {
|
||||
kind: name.clone(),
|
||||
kind: variable.name.clone(),
|
||||
named: true,
|
||||
fields: None,
|
||||
children: None,
|
||||
|
|
@ -540,73 +552,107 @@ pub(crate) fn generate_node_types_json(
|
|||
} else if variable.kind.is_visible()
|
||||
&& !syntax_grammar.variables_to_inline.contains(&symbol)
|
||||
{
|
||||
let node_type_json =
|
||||
node_types_json
|
||||
.entry(name.clone())
|
||||
.or_insert_with(|| NodeInfoJSON {
|
||||
kind: name.clone(),
|
||||
named: true,
|
||||
fields: None,
|
||||
children: 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(),
|
||||
});
|
||||
for alias in aliases_by_symbol.get(&Symbol::non_terminal(i)).unwrap_or(&HashSet::new()) {
|
||||
let kind;
|
||||
let is_named;
|
||||
if let Some(alias) = alias {
|
||||
kind = &alias.value;
|
||||
is_named = alias.is_named;
|
||||
} else {
|
||||
kind = &variable.name;
|
||||
is_named = variable.kind == VariableType::Named;
|
||||
}
|
||||
|
||||
field_info_json.multiple |= field_info.multiple;
|
||||
field_info_json.required &= field_info.required;
|
||||
field_info_json
|
||||
let node_type_json =
|
||||
node_types_json
|
||||
.entry(kind.clone())
|
||||
.or_insert_with(|| NodeInfoJSON {
|
||||
kind: kind.clone(),
|
||||
named: is_named,
|
||||
fields: None,
|
||||
children: 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 mut children_types = info
|
||||
.children_without_fields
|
||||
.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 mut children_types = info
|
||||
.children_without_fields
|
||||
.types
|
||||
.iter()
|
||||
.map(child_type_to_node_type)
|
||||
.collect::<Vec<_>>();
|
||||
if children_types.len() > 0 {
|
||||
children_types.sort_unstable();
|
||||
children_types.dedup();
|
||||
node_type_json.children = Some(FieldInfoJSON {
|
||||
multiple: info.children_without_fields.multiple,
|
||||
required: info.children_without_fields.required,
|
||||
types: children_types,
|
||||
});
|
||||
.iter()
|
||||
.map(child_type_to_node_type)
|
||||
.collect::<Vec<_>>();
|
||||
if children_types.len() > 0 {
|
||||
children_types.sort_unstable();
|
||||
children_types.dedup();
|
||||
node_type_json.children = Some(FieldInfoJSON {
|
||||
multiple: info.children_without_fields.multiple,
|
||||
required: info.children_without_fields.required,
|
||||
types: children_types,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut result = node_types_json.into_iter().map(|e| e.1).collect::<Vec<_>>();
|
||||
|
||||
for variable in &lexical_grammar.variables {
|
||||
if variable.kind == VariableType::Named {
|
||||
result.push(NodeInfoJSON {
|
||||
kind: variable.name.clone(),
|
||||
named: true,
|
||||
fields: None,
|
||||
children: None,
|
||||
subtypes: None,
|
||||
});
|
||||
} else if variable.kind == VariableType::Anonymous {
|
||||
result.push(NodeInfoJSON {
|
||||
kind: variable.name.clone(),
|
||||
named: false,
|
||||
fields: None,
|
||||
children: None,
|
||||
subtypes: None,
|
||||
});
|
||||
for (i, variable) in lexical_grammar.variables.iter().enumerate() {
|
||||
for alias in aliases_by_symbol.get(&Symbol::terminal(i)).unwrap_or(&HashSet::new()) {
|
||||
let kind;
|
||||
let is_named;
|
||||
if let Some(alias) = alias {
|
||||
kind = &alias.value;
|
||||
is_named = alias.is_named;
|
||||
} else {
|
||||
kind = &variable.name;
|
||||
is_named = variable.kind == VariableType::Named;
|
||||
}
|
||||
|
||||
if variable.kind == VariableType::Named {
|
||||
result.push(NodeInfoJSON {
|
||||
kind: kind.clone(),
|
||||
named: is_named,
|
||||
fields: None,
|
||||
children: None,
|
||||
subtypes: None,
|
||||
});
|
||||
} else if variable.kind == VariableType::Anonymous {
|
||||
result.push(NodeInfoJSON {
|
||||
kind: kind.clone(),
|
||||
named: is_named,
|
||||
fields: None,
|
||||
children: None,
|
||||
subtypes: None,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result.sort_unstable_by(|a, b| {
|
||||
b.subtypes.is_some().cmp(&a.subtypes.is_some())
|
||||
.then_with(|| {
|
||||
let a_is_leaf = a.children.is_none() && a.fields.is_none();
|
||||
let b_is_leaf = b.children.is_none() && b.fields.is_none();
|
||||
a_is_leaf.cmp(&b_is_leaf)
|
||||
})
|
||||
.then_with(|| a.kind.cmp(&b.kind))
|
||||
});
|
||||
result.dedup();
|
||||
result
|
||||
}
|
||||
|
||||
|
|
@ -890,6 +936,70 @@ mod tests {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_node_types_for_aliased_nodes() {
|
||||
let node_types = get_node_types(InputGrammar {
|
||||
name: String::new(),
|
||||
extra_tokens: Vec::new(),
|
||||
external_tokens: Vec::new(),
|
||||
expected_conflicts: Vec::new(),
|
||||
variables_to_inline: Vec::new(),
|
||||
word_token: None,
|
||||
supertype_symbols: vec![],
|
||||
variables: vec![
|
||||
Variable {
|
||||
name: "thing".to_string(),
|
||||
kind: VariableType::Named,
|
||||
rule: Rule::choice(vec![
|
||||
Rule::named("type"),
|
||||
Rule::named("expression"),
|
||||
]),
|
||||
},
|
||||
Variable {
|
||||
name: "type".to_string(),
|
||||
kind: VariableType::Named,
|
||||
rule: Rule::choice(vec![
|
||||
Rule::alias(Rule::named("identifier"), "type_identifier".to_string(), true),
|
||||
Rule::string("void"),
|
||||
]),
|
||||
},
|
||||
Variable {
|
||||
name: "expression".to_string(),
|
||||
kind: VariableType::Named,
|
||||
rule: Rule::choice(vec![
|
||||
Rule::named("identifier"),
|
||||
]),
|
||||
},
|
||||
Variable {
|
||||
name: "identifier".to_string(),
|
||||
kind: VariableType::Named,
|
||||
rule: Rule::pattern("\\w+"),
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
assert_eq!(
|
||||
node_types.iter().find(|t| t.kind == "identifier"),
|
||||
Some(&NodeInfoJSON {
|
||||
kind: "identifier".to_string(),
|
||||
named: true,
|
||||
subtypes: None,
|
||||
children: None,
|
||||
fields: None,
|
||||
})
|
||||
);
|
||||
assert_eq!(
|
||||
node_types.iter().find(|t| t.kind == "type_identifier"),
|
||||
Some(&NodeInfoJSON {
|
||||
kind: "type_identifier".to_string(),
|
||||
named: true,
|
||||
subtypes: None,
|
||||
children: None,
|
||||
fields: None,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_variable_info() {
|
||||
let variable_info = get_variable_info(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue