fix(generate): use topological sort for subtype map
This commit is contained in:
parent
3bd8f7df8e
commit
bcb30f7951
6 changed files with 87 additions and 27 deletions
|
|
@ -27,7 +27,7 @@ mod tables;
|
|||
use build_tables::build_tables;
|
||||
pub use build_tables::ParseTableBuilderError;
|
||||
use grammars::InputGrammar;
|
||||
pub use node_types::VariableInfoError;
|
||||
pub use node_types::{SuperTypeCycleError, VariableInfoError};
|
||||
use parse_grammar::parse_grammar;
|
||||
pub use parse_grammar::ParseGrammarError;
|
||||
use prepare_grammar::prepare_grammar;
|
||||
|
|
@ -70,6 +70,8 @@ pub enum GenerateError {
|
|||
BuildTables(#[from] ParseTableBuilderError),
|
||||
#[error(transparent)]
|
||||
ParseVersion(#[from] ParseVersionError),
|
||||
#[error(transparent)]
|
||||
SuperTypeCycle(#[from] SuperTypeCycleError),
|
||||
}
|
||||
|
||||
impl From<std::io::Error> for GenerateError {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,4 @@
|
|||
use std::{
|
||||
cmp::Ordering,
|
||||
collections::{BTreeMap, HashMap, HashSet},
|
||||
};
|
||||
use std::collections::{BTreeMap, HashMap, HashSet};
|
||||
|
||||
use anyhow::Result;
|
||||
use serde::Serialize;
|
||||
|
|
@ -444,12 +441,33 @@ pub fn get_supertype_symbol_map(
|
|||
supertype_symbol_map
|
||||
}
|
||||
|
||||
pub type SuperTypeCycleResult<T> = Result<T, SuperTypeCycleError>;
|
||||
|
||||
#[derive(Debug, Error, Serialize)]
|
||||
pub struct SuperTypeCycleError {
|
||||
items: Vec<String>,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for SuperTypeCycleError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "Dependency cycle detected in node types:")?;
|
||||
for (i, item) in self.items.iter().enumerate() {
|
||||
write!(f, " {item}")?;
|
||||
if i < self.items.len() - 1 {
|
||||
write!(f, ",")?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn generate_node_types_json(
|
||||
syntax_grammar: &SyntaxGrammar,
|
||||
lexical_grammar: &LexicalGrammar,
|
||||
default_aliases: &AliasMap,
|
||||
variable_info: &[VariableInfo],
|
||||
) -> Vec<NodeInfoJSON> {
|
||||
) -> SuperTypeCycleResult<Vec<NodeInfoJSON>> {
|
||||
let mut node_types_json = BTreeMap::new();
|
||||
|
||||
let child_type_to_node_type = |child_type: &ChildType| match child_type {
|
||||
|
|
@ -627,15 +645,33 @@ pub fn generate_node_types_json(
|
|||
}
|
||||
}
|
||||
|
||||
// Sort the subtype map so that subtypes are listed before their supertypes.
|
||||
subtype_map.sort_by(|a, b| {
|
||||
if b.1.contains(&a.0) {
|
||||
Ordering::Less
|
||||
} else if a.1.contains(&b.0) {
|
||||
Ordering::Greater
|
||||
} else {
|
||||
Ordering::Equal
|
||||
// Sort the subtype map topologically so that subtypes are listed before their supertypes.
|
||||
let mut sorted_kinds = Vec::with_capacity(subtype_map.len());
|
||||
let mut top_sort = topological_sort::TopologicalSort::<String>::new();
|
||||
for (supertype, subtypes) in &subtype_map {
|
||||
for subtype in subtypes {
|
||||
top_sort.add_dependency(subtype.kind.clone(), supertype.kind.clone());
|
||||
}
|
||||
}
|
||||
loop {
|
||||
let mut next_kinds = top_sort.pop_all();
|
||||
match (next_kinds.is_empty(), top_sort.is_empty()) {
|
||||
(true, true) => break,
|
||||
(true, false) => {
|
||||
let mut items = top_sort.collect::<Vec<String>>();
|
||||
items.sort();
|
||||
return Err(SuperTypeCycleError { items });
|
||||
}
|
||||
(false, _) => {
|
||||
next_kinds.sort();
|
||||
sorted_kinds.extend(next_kinds);
|
||||
}
|
||||
}
|
||||
}
|
||||
subtype_map.sort_by(|a, b| {
|
||||
let a_idx = sorted_kinds.iter().position(|n| n.eq(&a.0.kind)).unwrap();
|
||||
let b_idx = sorted_kinds.iter().position(|n| n.eq(&b.0.kind)).unwrap();
|
||||
a_idx.cmp(&b_idx)
|
||||
});
|
||||
|
||||
for node_type_json in node_types_json.values_mut() {
|
||||
|
|
@ -744,7 +780,7 @@ pub fn generate_node_types_json(
|
|||
.then_with(|| a.kind.cmp(&b.kind))
|
||||
});
|
||||
result.dedup();
|
||||
result
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
fn process_supertypes(info: &mut FieldInfoJSON, subtype_map: &[(NodeTypeJSON, Vec<NodeTypeJSON>)]) {
|
||||
|
|
@ -830,7 +866,8 @@ mod tests {
|
|||
},
|
||||
],
|
||||
..Default::default()
|
||||
});
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(node_types.len(), 3);
|
||||
|
||||
|
|
@ -929,7 +966,8 @@ mod tests {
|
|||
},
|
||||
],
|
||||
..Default::default()
|
||||
});
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(node_types.len(), 4);
|
||||
|
||||
|
|
@ -1040,7 +1078,8 @@ mod tests {
|
|||
},
|
||||
],
|
||||
..Default::default()
|
||||
});
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(node_types.len(), 6);
|
||||
|
||||
|
|
@ -1152,7 +1191,8 @@ mod tests {
|
|||
},
|
||||
],
|
||||
..Default::default()
|
||||
});
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
node_types[0],
|
||||
|
|
@ -1241,7 +1281,8 @@ mod tests {
|
|||
},
|
||||
],
|
||||
..Default::default()
|
||||
});
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
node_types[0],
|
||||
|
|
@ -1326,7 +1367,8 @@ mod tests {
|
|||
},
|
||||
],
|
||||
..Default::default()
|
||||
});
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
node_types[0],
|
||||
|
|
@ -1400,7 +1442,8 @@ mod tests {
|
|||
},
|
||||
],
|
||||
..Default::default()
|
||||
});
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(node_types.iter().find(|t| t.kind == "foo_identifier"), None);
|
||||
assert_eq!(
|
||||
|
|
@ -1456,7 +1499,8 @@ mod tests {
|
|||
},
|
||||
],
|
||||
..Default::default()
|
||||
});
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
node_types[0],
|
||||
|
|
@ -1505,7 +1549,8 @@ mod tests {
|
|||
]),
|
||||
}],
|
||||
..Default::default()
|
||||
});
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
node_types,
|
||||
|
|
@ -1553,7 +1598,8 @@ mod tests {
|
|||
},
|
||||
],
|
||||
..Default::default()
|
||||
});
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
&node_types
|
||||
|
|
@ -1672,7 +1718,8 @@ mod tests {
|
|||
},
|
||||
],
|
||||
..Default::default()
|
||||
});
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
node_types.iter().map(|n| &n.kind).collect::<Vec<_>>(),
|
||||
|
|
@ -1999,7 +2046,7 @@ mod tests {
|
|||
);
|
||||
}
|
||||
|
||||
fn get_node_types(grammar: &InputGrammar) -> Vec<NodeInfoJSON> {
|
||||
fn get_node_types(grammar: &InputGrammar) -> SuperTypeCycleResult<Vec<NodeInfoJSON>> {
|
||||
let (syntax_grammar, lexical_grammar, _, default_aliases) =
|
||||
prepare_grammar(grammar).unwrap();
|
||||
let variable_info =
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue