-
Notifications
You must be signed in to change notification settings - Fork 54
Expand file tree
/
Copy pathidentifier.rs
More file actions
109 lines (93 loc) · 3.03 KB
/
Copy pathidentifier.rs
File metadata and controls
109 lines (93 loc) · 3.03 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
use std::{fmt, sync::OnceLock};
use regex::{Regex, RegexBuilder};
#[cfg(feature = "quine")]
use {polyquine::Quine, proc_macro2::TokenStream};
use crate::{
common::{error::TypeQLError, Span, Spanned},
is_reserved_keyword,
pretty::Pretty,
};
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
#[cfg_attr(feature = "quine", derive(Quine))]
pub struct Identifier {
pub span: Option<Span>,
ident: String,
}
impl Identifier {
pub fn new(span: Option<Span>, ident: String) -> Self {
Self { span, ident }
}
pub fn as_str_unreserved(&self) -> Result<&str, TypeQLError> {
if !is_reserved_keyword(&self.ident) {
Ok(&self.ident)
} else {
Err(TypeQLError::ReservedKeywordAsIdentifier { identifier: self.clone() })
}
}
pub fn as_str_unchecked(&self) -> &str {
&self.ident
}
}
impl Pretty for Identifier {}
impl fmt::Display for Identifier {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&self.ident, f)
}
}
impl Spanned for Identifier {
fn span(&self) -> Option<Span> {
self.span
}
}
impl From<&str> for Identifier {
fn from(value: &str) -> Self {
Self::new(None, value.to_owned())
}
}
impl From<String> for Identifier {
fn from(value: String) -> Self {
Self::new(None, value)
}
}
const IDENTIFIER_CHAR: &str = "A-Za-z\
\\u00C0-\\u00D6\
\\u00D8-\\u00F6\
\\u00F8-\\u02FF\
\\u0370-\\u037D\
\\u037F-\\u1FFF\
\\u200C-\\u200D\
\\u2070-\\u218F\
\\u2C00-\\u2FEF\
\\u3001-\\uD7FF\
\\uF900-\\uFDCF\
\\uFDF0-\\uFFFD";
const IDENTIFIER_CONNECTOR: &str = "_\
\\-\
\\u00B7\
\\u0300-\\u036F\
\\u203F-\\u2040";
const IDENTIFIER_DIGIT: &str = "0-9";
pub fn is_valid_identifier(identifier: &str) -> bool {
static REGEX: OnceLock<Regex> = OnceLock::new();
let regex = REGEX.get_or_init(|| {
let identifier_tail = format!("{}{}{}", IDENTIFIER_CHAR, IDENTIFIER_CONNECTOR, IDENTIFIER_DIGIT);
let identifier_pattern = format!("^[{}][{}]*$", IDENTIFIER_CHAR, identifier_tail);
RegexBuilder::new(&identifier_pattern).build().unwrap()
});
regex.is_match(identifier)
}
pub fn is_valid_var_identifier(identifier: &str) -> bool {
static REGEX: OnceLock<Regex> = OnceLock::new();
let regex = REGEX.get_or_init(|| {
let identifier_head = format!("{}{}", IDENTIFIER_CHAR, IDENTIFIER_DIGIT);
let identifier_tail = format!("{}{}{}", IDENTIFIER_CHAR, IDENTIFIER_DIGIT, IDENTIFIER_CONNECTOR);
let identifier_pattern = format!("^[{}][{}]*$", identifier_head, identifier_tail);
RegexBuilder::new(&identifier_pattern).build().unwrap()
});
regex.is_match(identifier)
}