blob: dec783a673d157959aa53c1e89a7c7dc2c0b3b3c [file] [log] [blame]
David Tolnay42f50292016-09-04 13:54:21 -07001use std::fmt::{self, Display};
David Tolnay42f50292016-09-04 13:54:21 -07002
David Tolnay55337722016-09-11 12:58:56 -07003#[derive(Debug, Clone, Eq, Hash)]
David Tolnay42f50292016-09-04 13:54:21 -07004pub struct Ident(String);
5
6impl Ident {
7 pub fn new<T: Into<Ident>>(t: T) -> Self {
8 t.into()
9 }
10}
11
12impl<'a> From<&'a str> for Ident {
13 fn from(s: &str) -> Self {
14 Ident(s.to_owned())
15 }
16}
17
18impl From<String> for Ident {
19 fn from(s: String) -> Self {
20 Ident(s)
21 }
22}
23
David Tolnayc1683102016-09-27 08:17:58 -070024impl From<usize> for Ident {
25 fn from(u: usize) -> Self {
26 Ident(u.to_string())
27 }
28}
29
David Tolnay26469072016-09-04 13:59:48 -070030impl AsRef<str> for Ident {
31 fn as_ref(&self) -> &str {
David Tolnay42f50292016-09-04 13:54:21 -070032 &self.0
33 }
34}
35
36impl Display for Ident {
37 fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
38 self.0.fmt(formatter)
39 }
40}
David Tolnayb79ee962016-09-04 09:39:20 -070041
David Tolnaydaaf7742016-10-03 11:11:43 -070042impl<T: ?Sized> PartialEq<T> for Ident
43 where T: AsRef<str>
44{
David Tolnay55337722016-09-11 12:58:56 -070045 fn eq(&self, other: &T) -> bool {
46 self.0 == other.as_ref()
47 }
David Tolnayb79ee962016-09-04 09:39:20 -070048}
49
David Tolnay86eca752016-09-04 11:26:41 -070050#[cfg(feature = "parsing")]
David Tolnay9d8f1972016-09-04 11:58:48 -070051pub mod parsing {
52 use super::*;
David Tolnaye26baba2016-10-24 22:05:57 -070053 use nom::IResult;
54 use space::skip_whitespace;
55 use unicode_xid::UnicodeXID;
David Tolnay9d8f1972016-09-04 11:58:48 -070056
David Tolnay05f462f2016-10-24 22:19:42 -070057 pub fn ident(input: &str) -> IResult<&str, Ident> {
58 let (rest, id) = match word(input) {
59 IResult::Done(rest, id) => (rest, id),
60 IResult::Error => return IResult::Error,
61 };
62
63 match id.as_ref() {
64 // From https://doc.rust-lang.org/grammar.html#keywords
65 "abstract" | "alignof" | "as" | "become" | "box" | "break" | "const" | "continue" |
66 "crate" | "do" | "else" | "enum" | "extern" | "false" | "final" | "fn" | "for" |
67 "if" | "impl" | "in" | "let" | "loop" | "macro" | "match" | "mod" | "move" |
68 "mut" | "offsetof" | "override" | "priv" | "proc" | "pub" | "pure" | "ref" |
69 "return" | "Self" | "self" | "sizeof" | "static" | "struct" | "super" | "trait" |
70 "true" | "type" | "typeof" | "unsafe" | "unsized" | "use" | "virtual" | "where" |
71 "while" | "yield" => IResult::Error,
72 _ => IResult::Done(rest, id),
73 }
74 }
75
76 pub fn word(mut input: &str) -> IResult<&str, Ident> {
David Tolnaye26baba2016-10-24 22:05:57 -070077 input = skip_whitespace(input);
78
79 let mut chars = input.char_indices();
80 match chars.next() {
81 Some((_, ch)) if UnicodeXID::is_xid_start(ch) || ch == '_' => {}
82 _ => return IResult::Error,
83 }
84
85 while let Some((i, ch)) = chars.next() {
86 if !UnicodeXID::is_xid_continue(ch) {
87 return IResult::Done(&input[i..], input[..i].into());
88 }
89 }
90
91 IResult::Done("", input.into())
David Tolnay9d8f1972016-09-04 11:58:48 -070092 }
David Tolnay39039442016-10-30 11:25:21 -070093
94 pub fn wordlike(mut input: &str) -> IResult<&str, Ident> {
95 input = skip_whitespace(input);
96
97 for (i, ch) in input.char_indices() {
98 if !UnicodeXID::is_xid_start(ch) && !UnicodeXID::is_xid_continue(ch) {
99 return if i == 0 {
100 IResult::Error
101 } else {
102 IResult::Done(&input[i..], input[..i].into())
103 };
104 }
105 }
106
107 IResult::Done("", input.into())
108 }
David Tolnayb79ee962016-09-04 09:39:20 -0700109}
David Tolnay26469072016-09-04 13:59:48 -0700110
111#[cfg(feature = "printing")]
112mod printing {
113 use super::*;
114 use quote::{Tokens, ToTokens};
115
116 impl ToTokens for Ident {
117 fn to_tokens(&self, tokens: &mut Tokens) {
118 tokens.append(self.as_ref())
119 }
120 }
121}