summaryrefslogtreecommitdiff
path: root/src/chomp/name.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/chomp/name.rs')
-rw-r--r--src/chomp/name.rs217
1 files changed, 217 insertions, 0 deletions
diff --git a/src/chomp/name.rs b/src/chomp/name.rs
new file mode 100644
index 0000000..450b6e9
--- /dev/null
+++ b/src/chomp/name.rs
@@ -0,0 +1,217 @@
+use std::{
+ array::IntoIter,
+ cmp::{self, Ordering},
+ fmt, hash,
+};
+
+use heck::{CamelCase, SnakeCase};
+use proc_macro2::{Ident, Span};
+use syn::{ext::IdentExt, spanned::Spanned};
+
+#[derive(Clone, Debug)]
+pub enum Content {
+ Spanned(Ident),
+ Spanless(String),
+}
+
+impl Spanned for Content {
+ fn span(&self) -> Span {
+ match self {
+ Content::Spanned(i) => i.span(),
+ Content::Spanless(_) => Span::call_site(),
+ }
+ }
+}
+
+impl From<Content> for Ident {
+ fn from(content: Content) -> Self {
+ match content {
+ Content::Spanned(i) => i,
+ Content::Spanless(s) => Ident::new(&s, Span::call_site()),
+ }
+ }
+}
+
+impl CamelCase for Content {
+ fn to_camel_case(&self) -> Self::Owned {
+ match self {
+ Self::Spanned(ident) => {
+ let span = ident.span();
+ let name = ident.unraw().to_string();
+ Ident::new(&name.to_camel_case(), span).into()
+ }
+ Self::Spanless(name) => name.to_camel_case().into(),
+ }
+ }
+}
+
+impl SnakeCase for Content {
+ fn to_snake_case(&self) -> Self::Owned {
+ match self {
+ Self::Spanned(ident) => {
+ let span = ident.span();
+ let name = ident.unraw().to_string();
+ Ident::new(&name.to_snake_case(), span).into()
+ }
+ Self::Spanless(name) => name.to_snake_case().into(),
+ }
+ }
+}
+
+impl PartialEq for Content {
+ fn eq(&self, other: &Self) -> bool {
+ match (self, other) {
+ (Self::Spanned(me), Self::Spanned(them)) => me == them,
+ (Self::Spanned(me), Self::Spanless(them)) => me.unraw() == them,
+ (Self::Spanless(me), Self::Spanned(them)) => them.unraw() == me,
+ (Self::Spanless(me), Self::Spanless(them)) => me == them,
+ }
+ }
+}
+
+impl<T: AsRef<str>> PartialEq<T> for Content {
+ fn eq(&self, other: &T) -> bool {
+ match self {
+ Self::Spanned(me) => me.unraw() == other,
+ Self::Spanless(me) => me == other.as_ref(),
+ }
+ }
+}
+
+impl Eq for Content {}
+
+impl hash::Hash for Content {
+ fn hash<H: hash::Hasher>(&self, state: &mut H) {
+ match self {
+ Self::Spanned(i) => i.unraw().to_string().hash(state),
+ Self::Spanless(s) => s.hash(state),
+ }
+ }
+}
+
+impl fmt::Display for Content {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self {
+ Self::Spanned(i) => i.fmt(f),
+ Self::Spanless(s) => s.fmt(f),
+ }
+ }
+}
+
+impl From<Ident> for Content {
+ fn from(ident: Ident) -> Self {
+ Self::Spanned(ident)
+ }
+}
+
+impl From<String> for Content {
+ fn from(string: String) -> Self {
+ Self::Spanless(string)
+ }
+}
+
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
+pub enum Kind {
+ Label,
+ Let,
+ Variable,
+}
+
+impl PartialOrd for Kind {
+ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+ Some(match (self, other) {
+ (Kind::Label, Kind::Label)
+ | (Kind::Let, Kind::Let)
+ | (Kind::Variable, Kind::Variable) => Ordering::Equal,
+ (Kind::Label, Kind::Let)
+ | (Kind::Label, Kind::Variable)
+ | (Kind::Let, Kind::Variable) => Ordering::Greater,
+ (Kind::Let, Kind::Label)
+ | (Kind::Variable, Kind::Label)
+ | (Kind::Variable, Kind::Let) => Ordering::Less,
+ })
+ }
+}
+
+#[derive(Clone, Debug, PartialEq, Eq, Hash)]
+pub struct Name {
+ pub content: Content,
+ kind: Kind,
+}
+
+impl Name {
+ pub fn new_variable<T: Into<Content>>(content: T) -> Self {
+ Self {
+ content: content.into(),
+ kind: Kind::Variable,
+ }
+ }
+
+ pub fn new_let<T: Into<Content>>(content: T) -> Self {
+ Self {
+ content: content.into(),
+ kind: Kind::Let,
+ }
+ }
+
+ pub fn new_label<T: Into<Content>>(content: T) -> Self {
+ Self {
+ content: content.into(),
+ kind: Kind::Label,
+ }
+ }
+
+ pub fn merge(this: Option<Self>, that: Option<Self>) -> Option<Self> {
+ match (this, that) {
+ (None, that) => that,
+ (Some(this), None) => Some(this),
+ (Some(this), Some(that)) => {
+ if this.kind >= that.kind {
+ Some(this)
+ } else {
+ Some(that)
+ }
+ }
+ }
+ }
+
+ pub fn merge_all<I: IntoIterator<Item = Option<Self>>>(iter: I) -> Option<Self> {
+ iter.into_iter().fold(None, Self::merge)
+ }
+}
+
+impl Spanned for Name {
+ fn span(&self) -> Span {
+ self.content.span()
+ }
+}
+
+impl From<Name> for Ident {
+ fn from(name: Name) -> Self {
+ name.content.into()
+ }
+}
+
+impl CamelCase for Name {
+ fn to_camel_case(&self) -> Self::Owned {
+ Self {
+ content: self.content.to_camel_case(),
+ kind: self.kind,
+ }
+ }
+}
+
+impl SnakeCase for Name {
+ fn to_snake_case(&self) -> Self::Owned {
+ Self {
+ content: self.content.to_snake_case(),
+ kind: self.kind,
+ }
+ }
+}
+
+impl fmt::Display for Name {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ self.content.fmt(f)
+ }
+}