- 
          
- 
                Notifications
    You must be signed in to change notification settings 
- Fork 11
Codify and Resolve modifiers #46
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 2 commits
a3a16a7
              536dc49
              4895855
              1fdbb1e
              a5cbb19
              34edb09
              ff6b56a
              039f401
              b99817a
              17d2dff
              65e5b01
              7157b82
              120d424
              d7d2c96
              6ef866a
              477a343
              1e8e94b
              02ea0fb
              File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,148 @@ | ||
| use std::ops::{AddAssign, Deref}; | ||
|         
                  T0mstone marked this conversation as resolved.
              Outdated
          
            Show resolved
            Hide resolved | ||
|  | ||
| macro_rules! declare_types { | ||
| ($(<$lt:lifetime>)? | ||
| $(derive($($Der:ident),*),)? | ||
| str = $s:ty, | ||
| List = $List:ident<_> | ||
|         
                  MDLC01 marked this conversation as resolved.
              Outdated
          
            Show resolved
            Hide resolved | ||
| ) => { | ||
| /// A module of definitions. | ||
| $(#[derive($($Der),*)])? | ||
| pub struct Module<$($lt)?>($List<($s, Binding<$($lt)?>)>); | ||
|  | ||
| /// A definition bound in a module, with metadata. | ||
| $(#[derive($($Der),*)])? | ||
| pub struct Binding<$($lt)?> { | ||
| /// The bound definition. | ||
| pub def: Def<$($lt)?>, | ||
| /// A deprecation message for the definition, if it is deprecated. | ||
| pub deprecation: Option<$s>, | ||
| } | ||
|  | ||
| impl<$($lt)?> Binding<$($lt)?> { | ||
| /// Create a new bound definition. | ||
| pub const fn new(definition: Def<$($lt)?>) -> Self { | ||
| Self { def: definition, deprecation: None } | ||
| } | ||
| } | ||
|  | ||
| /// A definition in a module. | ||
| $(#[derive($($Der),*)])? | ||
| pub enum Def<$($lt)?> { | ||
| /// A symbol, potentially with modifiers. | ||
| Symbol(Symbol<$($lt)?>), | ||
| /// A nested module. | ||
| Module(Module<$($lt)?>), | ||
| } | ||
|  | ||
| /// A symbol, either a leaf or with modifiers. | ||
| $(#[derive($($Der),*)])? | ||
| pub enum Symbol<$($lt)?> { | ||
| /// A symbol without modifiers. | ||
| Single(char), | ||
| /// A symbol with named modifiers. | ||
| /// The symbol defaults to its first variant. | ||
| Multi($List<(ModifierSet<$s>, char)>), | ||
| } | ||
| }; | ||
| } | ||
|  | ||
| /// A set of modifiers. | ||
| #[derive(Debug, Copy, Clone)] | ||
| pub struct ModifierSet<S>(S); | ||
|  | ||
| impl<S: Deref<Target = str>> ModifierSet<S> { | ||
| /// Convert the underlying string to a slice. | ||
| pub fn as_deref(&self) -> ModifierSet<&str> { | ||
| ModifierSet(&self.0) | ||
| } | ||
|  | ||
| /// Construct a modifier set from a string, | ||
| /// where modifiers are separated by the character `.`. | ||
| /// | ||
| /// It is not unsafe to use this function wrongly, but it can produce | ||
| /// unexpected results down the line. Correct usage should ensure that | ||
| /// `s` does not contain any empty modifiers (i.e. the sequence `..`) | ||
| /// and that no modifier occurs twice. | ||
| pub fn new_unchecked(s: S) -> Self { | ||
|         
                  MDLC01 marked this conversation as resolved.
              Outdated
          
            Show resolved
            Hide resolved          | ||
| Self(s) | ||
| } | ||
|  | ||
| /// Construct an empty modifier set. | ||
| pub fn empty() -> Self | ||
| where | ||
| S: Default, | ||
| { | ||
| Self(S::default()) | ||
| } | ||
|         
                  T0mstone marked this conversation as resolved.
              Outdated
          
            Show resolved
            Hide resolved | ||
|  | ||
| /// Whether `self` is empty. | ||
| pub fn is_empty(&self) -> bool { | ||
| self.0.is_empty() | ||
| } | ||
|  | ||
| /// Add a modifier to the set, without checking that it is a valid modifier. | ||
| /// | ||
| /// It is not unsafe to use this method wrongly, but that can produce | ||
| /// unexpected results down the line. Correct usage should ensure that | ||
| /// `modifier` is not empty and doesn't contain the character `.`. | ||
| pub fn add_unchecked(&mut self, m: &str) | ||
|         
                  T0mstone marked this conversation as resolved.
              Outdated
          
            Show resolved
            Hide resolved | ||
| where | ||
| S: for<'a> AddAssign<&'a str>, | ||
| { | ||
| if !self.0.is_empty() { | ||
| self.0 += "."; | ||
| } | ||
| self.0 += m; | ||
| } | ||
|  | ||
| /// Iterate over the list of modifiers in an arbitrary order. | ||
| pub fn iter(&self) -> impl Iterator<Item = &str> { | ||
| self.0.split('.').filter(|s| !s.is_empty()) | ||
| } | ||
|         
                  T0mstone marked this conversation as resolved.
              Outdated
          
            Show resolved
            Hide resolved | ||
|  | ||
| /// Whether the set contains the modifier `m`. | ||
| pub fn contains(&self, m: &str) -> bool { | ||
| self.iter().any(|lhs| lhs == m) | ||
| } | ||
|  | ||
| /// Whether all modifiers in `self` are also present in `other`. | ||
| pub fn is_subset(&self, other: ModifierSet<&str>) -> bool { | ||
| self.iter().all(|m| other.contains(m)) | ||
| } | ||
|  | ||
| /// Find the best match from the list. | ||
| /// | ||
| /// To be considered a match, the modifier set must be a superset of | ||
| /// (or equal to) `self`. Among different matches, the best one is selected | ||
| /// by the following two criteria (in order): | ||
| /// 1. Number of modifiers in common with `self` (more is better). | ||
| /// 2. Total number of modifiers (fewer is better). | ||
| pub fn best_match_in<'a, T>( | ||
| &self, | ||
| variants: impl Iterator<Item = (ModifierSet<&'a str>, T)>, | ||
| ) -> Option<T> { | ||
| let mut best = None; | ||
| let mut best_score = None; | ||
|  | ||
| // Find the best table entry with this name. | ||
| for candidate in variants.filter(|(set, _)| self.is_subset(*set)) { | ||
| let mut matching = 0; | ||
| let mut total = 0; | ||
| for modifier in candidate.0.iter() { | ||
| if self.contains(modifier) { | ||
| matching += 1; | ||
| } | ||
| total += 1; | ||
| } | ||
|  | ||
| let score = (matching, core::cmp::Reverse(total)); | ||
|         
                  T0mstone marked this conversation as resolved.
              Outdated
          
            Show resolved
            Hide resolved | ||
| if best_score.map_or(true, |b| score > b) { | ||
|         
                  T0mstone marked this conversation as resolved.
              Outdated
          
            Show resolved
            Hide resolved | ||
| best = Some(candidate.1); | ||
| best_score = Some(score); | ||
| } | ||
| } | ||
|  | ||
| best | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.