pub fn as_atom(&self) -> Option<SmolStr> {
let tt = self.value()?;
let (_bra, attr, _ket) = tt.syntax().children().collect_tuple()?;
- if attr.kind() == IDENT {
+ if attr.kind().is_ident() {
Some(attr.leaf_text().unwrap().clone())
} else {
None
let tt = self.value()?;
let (_bra, attr, args, _ket) = tt.syntax().children().collect_tuple()?;
let args = TokenTree::cast(args)?;
- if attr.kind() == IDENT {
+ if attr.kind().is_ident() {
Some((attr.leaf_text().unwrap().clone(), args))
} else {
None
tokens: [
"ERROR",
"IDENT",
+ "RAW_IDENT",
"UNDERSCORE",
"WHITESPACE",
"INT_NUMBER",
"COMMENT",
"SHEBANG",
],
+ ident_tokens: [
+ "IDENT",
+ "RAW_IDENT",
+ ],
nodes: [
"SOURCE_FILE",
}
fn name_r(p: &mut Parser, recovery: TokenSet) {
- if p.at(IDENT) {
+ if p.current().is_ident() {
let m = p.start();
p.bump();
m.complete(p, NAME);
}
fn name_ref(p: &mut Parser) {
- if p.at(IDENT) {
+ if p.current().is_ident() {
let m = p.start();
p.bump();
m.complete(p, NAME_REF);
// }
L_PAREN if allow_calls => call_expr(p, lhs),
L_BRACK if allow_calls => index_expr(p, lhs),
- DOT if p.nth(1) == IDENT && (p.nth(2) == L_PAREN || p.nth(2) == COLONCOLON) => {
+ DOT if p.nth(1).is_ident() && (p.nth(2) == L_PAREN || p.nth(2) == COLONCOLON) => {
method_call_expr(p, lhs)
}
DOT => field_expr(p, lhs),
// y.bar::<T>(1, 2,);
// }
fn method_call_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
- assert!(p.at(DOT) && p.nth(1) == IDENT && (p.nth(2) == L_PAREN || p.nth(2) == COLONCOLON));
+ assert!(p.at(DOT) && p.nth(1).is_ident() && (p.nth(2) == L_PAREN || p.nth(2) == COLONCOLON));
let m = lhs.precede(p);
p.bump();
name_ref(p);
assert!(p.at(DOT));
let m = lhs.precede(p);
p.bump();
- if p.at(IDENT) {
+ if p.current().is_ident() {
name_ref(p)
} else if p.at(INT_NUMBER) {
p.bump()
p.bump();
while !p.at(EOF) && !p.at(R_CURLY) {
match p.current() {
- IDENT => {
+ IDENT | RAW_IDENT => {
let m = p.start();
name_ref(p);
if p.eat(COLON) {
UNSAFE_KW,
RETURN_KW,
IDENT,
+ RAW_IDENT,
SELF_KW,
SUPER_KW,
CRATE_KW,
has_mods = true;
abi(p);
}
- if p.at(IDENT) && p.at_contextual_kw("auto") && p.nth(1) == TRAIT_KW {
+ if p.current().is_ident() && p.at_contextual_kw("auto") && p.nth(1) == TRAIT_KW {
p.bump_remap(AUTO_KW);
has_mods = true;
}
- if p.at(IDENT) && p.at_contextual_kw("default") && p.nth(1) == IMPL_KW {
+ if p.current().is_ident() && p.at_contextual_kw("default") && p.nth(1) == IMPL_KW {
p.bump_remap(DEFAULT_KW);
has_mods = true;
}
}
STRUCT_DEF
}
- IDENT if p.at_contextual_kw("union") && p.nth(1) == IDENT => {
+ IDENT | RAW_IDENT if p.at_contextual_kw("union") && p.nth(1).is_ident() => {
// test union_items
// union Foo {}
// union Foo {
use_item::use_item(p);
USE_ITEM
}
- CONST_KW if (la == IDENT || la == MUT_KW) => {
+ CONST_KW if (la.is_ident() || la == MUT_KW) => {
consts::const_def(p);
CONST_DEF
}
pub(super) fn macro_call_after_excl(p: &mut Parser) -> BlockLike {
p.expect(EXCL);
- p.eat(IDENT);
+ p.eat_one(&[IDENT, RAW_IDENT]);
match p.current() {
L_CURLY => {
token_tree(p);
}
let var = p.start();
attributes::outer_attributes(p);
- if p.at(IDENT) {
+ if p.current().is_ident() {
name(p);
match p.current() {
L_CURLY => named_field_def_list(p),
// }
attributes::outer_attributes(p);
opt_visibility(p);
- if p.at(IDENT) {
+ if p.current().is_ident() {
name(p);
p.expect(COLON);
types::type_(p);
if p.nth(1) == POUND || p.nth(1) == R_ANGLE {
return true;
}
- (p.nth(1) == LIFETIME || p.nth(1) == IDENT)
+ (p.nth(1) == LIFETIME || p.nth(1).is_ident())
&& (p.nth(2) == R_ANGLE || p.nth(2) == COMMA || p.nth(2) == COLON || p.nth(2) == EQ)
}
// trait Foo {
// fn bar(_: u64);
// }
- if (la0 == IDENT || la0 == UNDERSCORE) && la1 == COLON
- || la0 == AMP && la1 == IDENT && la2 == COLON
- || la0 == AMP && la1 == MUT_KW && la2 == IDENT && la3 == COLON
+ if (la0.is_ident() || la0 == UNDERSCORE) && la1 == COLON
+ || la0 == AMP && la1.is_ident() && la2 == COLON
+ || la0 == AMP && la1 == MUT_KW && la2.is_ident() && la3 == COLON
{
patterns::pattern(p);
types::ascription(p);
use super::*;
pub(super) const PATH_FIRST: TokenSet =
- token_set![IDENT, SELF_KW, SUPER_KW, CRATE_KW, COLONCOLON, L_ANGLE];
+ token_set![IDENT, RAW_IDENT, SELF_KW, SUPER_KW, CRATE_KW, COLONCOLON, L_ANGLE];
pub(super) fn is_path_start(p: &Parser) -> bool {
match p.current() {
- IDENT | SELF_KW | SUPER_KW | CRATE_KW | COLONCOLON => true,
+ IDENT | RAW_IDENT | SELF_KW | SUPER_KW | CRATE_KW | COLONCOLON => true,
_ => false,
}
}
p.eat(COLONCOLON);
}
match p.current() {
- IDENT => {
+ IDENT | RAW_IDENT => {
name_ref(p);
opt_path_type_args(p, mode);
}
let la1 = p.nth(1);
if la0 == REF_KW
|| la0 == MUT_KW
- || (la0 == IDENT && !(la1 == COLONCOLON || la1 == L_PAREN || la1 == L_CURLY))
+ || (la0.is_ident() && !(la1 == COLONCOLON || la1 == L_PAREN || la1 == L_CURLY))
{
return Some(bind_pat(p, true));
}
while !p.at(EOF) && !p.at(R_CURLY) {
match p.current() {
DOTDOT => p.bump(),
- IDENT if p.nth(1) == COLON => field_pat(p),
+ IDENT | RAW_IDENT if p.nth(1) == COLON => field_pat(p),
L_CURLY => error_block(p, "expected ident"),
_ => {
bind_pat(p, false);
}
fn field_pat(p: &mut Parser) {
- assert!(p.at(IDENT));
+ assert!(p.current().is_ident());
assert!(p.nth(1) == COLON);
let m = p.start();
p.bump();
m.complete(p, LIFETIME_ARG);
}
- IDENT if p.nth(1) == EQ => {
+ IDENT | RAW_IDENT if p.nth(1) == EQ => {
name_ref(p);
p.bump();
types::type_(p);
while !p.at(EOF) && !p.at(R_ANGLE) {
match p.current() {
LIFETIME => lifetime_param(p),
- IDENT => type_param(p),
+ IDENT | RAW_IDENT => type_param(p),
_ => p.err_and_bump("expected type parameter"),
}
if !p.at(R_ANGLE) && !p.expect(COMMA) {
}
fn type_param(p: &mut Parser) {
- assert!(p.at(IDENT));
+ assert!(p.current().is_ident());
let m = p.start();
name(p);
if p.at(COLON) {
}
fn scan_ident(c: char, ptr: &mut Ptr) -> SyntaxKind {
- let is_single_letter = match ptr.current() {
- None => true,
- Some(c) if !is_ident_continue(c) => true,
+ let is_raw = match (c, ptr.current()) {
+ ('r', Some('#')) => {
+ ptr.bump();
+ true
+ }
+ ('_', Some(c)) if !is_ident_continue(c) => return UNDERSCORE,
_ => false,
};
- if is_single_letter {
- return if c == '_' { UNDERSCORE } else { IDENT };
- }
+
ptr.bump_while(is_ident_continue);
- if let Some(kind) = SyntaxKind::from_keyword(ptr.current_token_text()) {
+
+ if is_raw {
+ RAW_IDENT
+ } else if let Some(kind) = SyntaxKind::from_keyword(ptr.current_token_text()) {
return kind;
+ } else {
+ IDENT
}
- IDENT
}
fn scan_literal_suffix(ptr: &mut Ptr) {
pub(crate) fn is_string_literal_start(c: char, c1: Option<char>, c2: Option<char>) -> bool {
match (c, c1, c2) {
('r', Some('"'), _)
- | ('r', Some('#'), _)
+ | ('r', Some('#'), Some('"'))
+ | ('r', Some('#'), Some('#'))
| ('b', Some('"'), _)
| ('b', Some('\''), _)
| ('b', Some('r'), Some('"'))
true
}
+ /// Consume the next token matching one of the `kinds`
+ pub(crate) fn eat_one<'k, K>(&mut self, kinds: K) -> bool
+ where
+ K: IntoIterator<Item = &'k SyntaxKind> + 'k,
+ {
+ kinds.into_iter().map(|k| self.eat(*k)).any(|eaten| eaten)
+ }
+
/// Consume the next token if it is `kind` or emit an error
/// otherwise.
pub(crate) fn expect(&mut self, kind: SyntaxKind) -> bool {
) -> Option<(&'node SyntaxNode, GreenNode, Vec<SyntaxError>)> {
let node = algo::find_covering_node(node, edit.delete);
match node.kind() {
- WHITESPACE | COMMENT | IDENT | STRING | RAW_STRING => {
+ WHITESPACE | COMMENT | IDENT | RAW_IDENT | STRING | RAW_STRING => {
let text = get_text_after_edit(node, &edit);
let tokens = tokenize(&text);
let token = match tokens[..] {
_ => return None,
};
- if token.kind == IDENT && is_contextual_kw(&text) {
+ if token.kind.is_ident() && is_contextual_kw(&text) {
return None;
}
UNION_KW,
ERROR,
IDENT,
+ RAW_IDENT,
UNDERSCORE,
WHITESPACE,
INT_NUMBER,
UNION_KW => &SyntaxInfo { name: "UNION_KW" },
ERROR => &SyntaxInfo { name: "ERROR" },
IDENT => &SyntaxInfo { name: "IDENT" },
+ RAW_IDENT => &SyntaxInfo { name: "RAW_IDENT" },
UNDERSCORE => &SyntaxInfo { name: "UNDERSCORE" },
WHITESPACE => &SyntaxInfo { name: "WHITESPACE" },
INT_NUMBER => &SyntaxInfo { name: "INT_NUMBER" },
};
Some(tok)
}
+
+ pub(crate) fn is_ident(&self) -> bool {
+ match self {
+ | IDENT
+ | RAW_IDENT => true,
+ _ => false,
+ }
+ }
}
};
Some(tok)
}
+
+ pub(crate) fn is_ident(&self) -> bool {
+ match self {
+{%- for kind in ident_tokens %}
+ | {{kind}}
+{%- endfor %} => true,
+ _ => false,
+ }
+ }
}
fn has_short_text(kind: SyntaxKind) -> bool {
use crate::SyntaxKind::*;
match kind {
- IDENT | LIFETIME | INT_NUMBER | FLOAT_NUMBER => true,
+ IDENT | RAW_IDENT | LIFETIME | INT_NUMBER | FLOAT_NUMBER => true,
_ => false,
}
}
--- /dev/null
+r#raw_ident
--- /dev/null
+RAW_IDENT 11 "r#raw_ident"
+WHITESPACE 1 "\n"
--- /dev/null
+fn r#foo() {
+}
--- /dev/null
+SOURCE_FILE@[0; 15)
+ FN_DEF@[0; 14)
+ FN_KW@[0; 2)
+ WHITESPACE@[2; 3)
+ NAME@[3; 8)
+ RAW_IDENT@[3; 8) "r#foo"
+ PARAM_LIST@[8; 10)
+ L_PAREN@[8; 9)
+ R_PAREN@[9; 10)
+ WHITESPACE@[10; 11)
+ BLOCK@[11; 14)
+ L_CURLY@[11; 12)
+ WHITESPACE@[12; 13)
+ R_CURLY@[13; 14)
+ WHITESPACE@[14; 15)
--- /dev/null
+struct S {
+ r#foo: u32
+}
\ No newline at end of file
--- /dev/null
+SOURCE_FILE@[0; 27)
+ STRUCT_DEF@[0; 27)
+ STRUCT_KW@[0; 6)
+ WHITESPACE@[6; 7)
+ NAME@[7; 8)
+ IDENT@[7; 8) "S"
+ WHITESPACE@[8; 9)
+ NAMED_FIELD_DEF_LIST@[9; 27)
+ L_CURLY@[9; 10)
+ WHITESPACE@[10; 15)
+ NAMED_FIELD_DEF@[15; 25)
+ NAME@[15; 20)
+ RAW_IDENT@[15; 20) "r#foo"
+ COLON@[20; 21)
+ WHITESPACE@[21; 22)
+ PATH_TYPE@[22; 25)
+ PATH@[22; 25)
+ PATH_SEGMENT@[22; 25)
+ NAME_REF@[22; 25)
+ IDENT@[22; 25) "u32"
+ WHITESPACE@[25; 26)
+ R_CURLY@[26; 27)