aboutsummaryrefslogtreecommitdiff
path: root/crates/syntax/src/ast/token_ext.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/syntax/src/ast/token_ext.rs')
-rw-r--r--crates/syntax/src/ast/token_ext.rs97
1 files changed, 86 insertions, 11 deletions
diff --git a/crates/syntax/src/ast/token_ext.rs b/crates/syntax/src/ast/token_ext.rs
index c5ef92733..8d3fad5a6 100644
--- a/crates/syntax/src/ast/token_ext.rs
+++ b/crates/syntax/src/ast/token_ext.rs
@@ -8,11 +8,11 @@ use std::{
8use rustc_lexer::unescape::{unescape_literal, Mode}; 8use rustc_lexer::unescape::{unescape_literal, Mode};
9 9
10use crate::{ 10use crate::{
11 ast::{AstToken, Comment, RawString, String, Whitespace}, 11 ast::{self, AstToken},
12 TextRange, TextSize, 12 TextRange, TextSize,
13}; 13};
14 14
15impl Comment { 15impl ast::Comment {
16 pub fn kind(&self) -> CommentKind { 16 pub fn kind(&self) -> CommentKind {
17 kind_by_prefix(self.text()) 17 kind_by_prefix(self.text())
18 } 18 }
@@ -80,7 +80,7 @@ fn kind_by_prefix(text: &str) -> CommentKind {
80 panic!("bad comment text: {:?}", text) 80 panic!("bad comment text: {:?}", text)
81} 81}
82 82
83impl Whitespace { 83impl ast::Whitespace {
84 pub fn spans_multiple_lines(&self) -> bool { 84 pub fn spans_multiple_lines(&self) -> bool {
85 let text = self.text(); 85 let text = self.text();
86 text.find('\n').map_or(false, |idx| text[idx + 1..].contains('\n')) 86 text.find('\n').map_or(false, |idx| text[idx + 1..].contains('\n'))
@@ -138,19 +138,19 @@ pub trait HasQuotes: AstToken {
138 } 138 }
139} 139}
140 140
141impl HasQuotes for String {} 141impl HasQuotes for ast::String {}
142impl HasQuotes for RawString {} 142impl HasQuotes for ast::RawString {}
143 143
144pub trait HasStringValue: HasQuotes { 144pub trait HasStringValue: HasQuotes {
145 fn value(&self) -> Option<Cow<'_, str>>; 145 fn value(&self) -> Option<Cow<'_, str>>;
146} 146}
147 147
148impl HasStringValue for String { 148impl HasStringValue for ast::String {
149 fn value(&self) -> Option<Cow<'_, str>> { 149 fn value(&self) -> Option<Cow<'_, str>> {
150 let text = self.text().as_str(); 150 let text = self.text().as_str();
151 let text = &text[self.text_range_between_quotes()? - self.syntax().text_range().start()]; 151 let text = &text[self.text_range_between_quotes()? - self.syntax().text_range().start()];
152 152
153 let mut buf = std::string::String::with_capacity(text.len()); 153 let mut buf = String::with_capacity(text.len());
154 let mut has_error = false; 154 let mut has_error = false;
155 unescape_literal(text, Mode::Str, &mut |_, unescaped_char| match unescaped_char { 155 unescape_literal(text, Mode::Str, &mut |_, unescaped_char| match unescaped_char {
156 Ok(c) => buf.push(c), 156 Ok(c) => buf.push(c),
@@ -166,7 +166,8 @@ impl HasStringValue for String {
166 } 166 }
167} 167}
168 168
169impl HasStringValue for RawString { 169// FIXME: merge `ast::RawString` and `ast::String`.
170impl HasStringValue for ast::RawString {
170 fn value(&self) -> Option<Cow<'_, str>> { 171 fn value(&self) -> Option<Cow<'_, str>> {
171 let text = self.text().as_str(); 172 let text = self.text().as_str();
172 let text = &text[self.text_range_between_quotes()? - self.syntax().text_range().start()]; 173 let text = &text[self.text_range_between_quotes()? - self.syntax().text_range().start()];
@@ -174,7 +175,7 @@ impl HasStringValue for RawString {
174 } 175 }
175} 176}
176 177
177impl RawString { 178impl ast::RawString {
178 pub fn map_range_up(&self, range: TextRange) -> Option<TextRange> { 179 pub fn map_range_up(&self, range: TextRange) -> Option<TextRange> {
179 let contents_range = self.text_range_between_quotes()?; 180 let contents_range = self.text_range_between_quotes()?;
180 assert!(TextRange::up_to(contents_range.len()).contains_range(range)); 181 assert!(TextRange::up_to(contents_range.len()).contains_range(range));
@@ -500,7 +501,7 @@ pub trait HasFormatSpecifier: AstToken {
500 } 501 }
501} 502}
502 503
503impl HasFormatSpecifier for String { 504impl HasFormatSpecifier for ast::String {
504 fn char_ranges( 505 fn char_ranges(
505 &self, 506 &self,
506 ) -> Option<Vec<(TextRange, Result<char, rustc_lexer::unescape::EscapeError>)>> { 507 ) -> Option<Vec<(TextRange, Result<char, rustc_lexer::unescape::EscapeError>)>> {
@@ -521,7 +522,7 @@ impl HasFormatSpecifier for String {
521 } 522 }
522} 523}
523 524
524impl HasFormatSpecifier for RawString { 525impl HasFormatSpecifier for ast::RawString {
525 fn char_ranges( 526 fn char_ranges(
526 &self, 527 &self,
527 ) -> Option<Vec<(TextRange, Result<char, rustc_lexer::unescape::EscapeError>)>> { 528 ) -> Option<Vec<(TextRange, Result<char, rustc_lexer::unescape::EscapeError>)>> {
@@ -536,3 +537,77 @@ impl HasFormatSpecifier for RawString {
536 Some(res) 537 Some(res)
537 } 538 }
538} 539}
540
541impl ast::IntNumber {
542 #[rustfmt::skip]
543 pub(crate) const SUFFIXES: &'static [&'static str] = &[
544 "u8", "u16", "u32", "u64", "u128", "usize",
545 "i8", "i16", "i32", "i64", "i128", "isize",
546 ];
547
548 pub fn radix(&self) -> Radix {
549 match self.text().get(..2).unwrap_or_default() {
550 "0b" => Radix::Binary,
551 "0o" => Radix::Octal,
552 "0x" => Radix::Hexadecimal,
553 _ => Radix::Decimal,
554 }
555 }
556
557 pub fn value(&self) -> Option<u128> {
558 let token = self.syntax();
559
560 let mut text = token.text().as_str();
561 if let Some(suffix) = self.suffix() {
562 text = &text[..text.len() - suffix.len()]
563 }
564
565 let radix = self.radix();
566 text = &text[radix.prefix_len()..];
567
568 let buf;
569 if text.contains("_") {
570 buf = text.replace('_', "");
571 text = buf.as_str();
572 };
573
574 let value = u128::from_str_radix(text, radix as u32).ok()?;
575 Some(value)
576 }
577
578 pub fn suffix(&self) -> Option<&str> {
579 let text = self.text();
580 // FIXME: don't check a fixed set of suffixes, `1_0_1___lol` is valid
581 // syntax, suffix is `lol`.
582 ast::IntNumber::SUFFIXES.iter().find_map(|suffix| {
583 if text.ends_with(suffix) {
584 return Some(&text[text.len() - suffix.len()..]);
585 }
586 None
587 })
588 }
589}
590
591impl ast::FloatNumber {
592 pub(crate) const SUFFIXES: &'static [&'static str] = &["f32", "f64"];
593}
594
595#[derive(Debug, PartialEq, Eq, Copy, Clone)]
596pub enum Radix {
597 Binary = 2,
598 Octal = 8,
599 Decimal = 10,
600 Hexadecimal = 16,
601}
602
603impl Radix {
604 pub const ALL: &'static [Radix] =
605 &[Radix::Binary, Radix::Octal, Radix::Decimal, Radix::Hexadecimal];
606
607 const fn prefix_len(&self) -> usize {
608 match self {
609 Self::Decimal => 0,
610 _ => 2,
611 }
612 }
613}