use crate::core::Span;
use crate::parser::kerml::Rule;
use crate::syntax::kerml::ast::enums::{ClassifierKind, FeatureDirection};
use crate::syntax::kerml::ast::parsers::ParseError;
use pest::iterators::Pair;
pub fn to_span(pest_span: pest::Span) -> Span {
let (sl, sc) = pest_span.start_pos().line_col();
let (el, ec) = pest_span.end_pos().line_col();
Span::from_coords(sl - 1, sc - 1, el - 1, ec - 1)
}
pub fn find_name<'a>(pairs: impl Iterator<Item = Pair<'a, Rule>>) -> Option<String> {
for pair in pairs {
if matches!(
pair.as_rule(),
Rule::feature_value | Rule::feature_specialization_part
) {
continue;
}
if matches!(
pair.as_rule(),
Rule::identification | Rule::name | Rule::identifier
) {
return Some(pair.as_str().to_string());
}
if let Some(name) = find_name(pair.into_inner()) {
return Some(name);
}
}
None
}
pub fn find_identifier_span<'a>(
pairs: impl Iterator<Item = Pair<'a, Rule>>,
) -> (Option<String>, Option<Span>) {
for pair in pairs {
if matches!(
pair.as_rule(),
Rule::feature_value | Rule::feature_specialization_part
) {
continue;
}
if matches!(
pair.as_rule(),
Rule::identification | Rule::name | Rule::identifier
) {
return (
Some(pair.as_str().to_string()),
Some(to_span(pair.as_span())),
);
}
if let (Some(name), Some(span)) = find_identifier_span(pair.into_inner()) {
return (Some(name), Some(span));
}
}
(None, None)
}
pub fn has_flag(pair: &Pair<Rule>, flag: Rule) -> bool {
if pair.as_rule() == flag {
return true;
}
if pair.as_rule() == Rule::feature_modifier || pair.as_rule() == Rule::feature_prefix_modifiers
{
return pair.clone().into_inner().any(|p| has_flag(&p, flag));
}
pair.clone()
.into_inner()
.any(|inner| inner.as_rule() == flag || has_flag(&inner, flag))
}
pub fn extract_flags(pairs: &[Pair<Rule>]) -> (bool, bool) {
let is_const = pairs.iter().any(|p| has_flag(p, Rule::const_modifier));
let derived = pairs.iter().any(|p| has_flag(p, Rule::derived));
(is_const, derived)
}
pub fn extract_direction(pairs: &[Pair<Rule>]) -> Option<FeatureDirection> {
pairs
.iter()
.find(|p| p.as_rule() == Rule::feature_direction_kind)
.and_then(|p| match p.as_str() {
"in" => Some(FeatureDirection::In),
"out" => Some(FeatureDirection::Out),
"inout" => Some(FeatureDirection::InOut),
_ => None,
})
}
pub fn is_classifier_rule(r: Rule) -> bool {
matches!(
r,
Rule::type_def
| Rule::classifier
| Rule::data_type
| Rule::class
| Rule::structure
| Rule::behavior
| Rule::function
| Rule::association
| Rule::association_structure
| Rule::metaclass
)
}
pub fn to_classifier_kind(rule: Rule) -> Result<ClassifierKind, ParseError> {
Ok(match rule {
Rule::type_def => ClassifierKind::Type,
Rule::classifier => ClassifierKind::Classifier,
Rule::data_type => ClassifierKind::DataType,
Rule::class => ClassifierKind::Class,
Rule::structure => ClassifierKind::Structure,
Rule::behavior => ClassifierKind::Behavior,
Rule::function => ClassifierKind::Function,
Rule::association => ClassifierKind::Association,
Rule::association_structure => ClassifierKind::AssociationStructure,
Rule::metaclass => ClassifierKind::Metaclass,
_ => return Err(ParseError::no_match()),
})
}