Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit e8c9ca2

Browse files
committed
Refactor shared literal_from_str code
1 parent adf7adf commit e8c9ca2

File tree

3 files changed

+76
-122
lines changed

3 files changed

+76
-122
lines changed

crates/proc-macro-srv/src/server.rs

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ pub mod rust_analyzer_span;
1717
mod symbol;
1818
pub mod token_id;
1919
pub use symbol::*;
20+
use syntax::ast::{self, HasModuleItem, IsString};
2021
use tt::Spacing;
2122

2223
fn delim_to_internal<S>(d: proc_macro::Delimiter, span: bridge::DelimSpan<S>) -> tt::Delimiter<S> {
@@ -54,6 +55,60 @@ fn spacing_to_external(spacing: Spacing) -> proc_macro::Spacing {
5455
}
5556
}
5657

58+
fn literal_to_external(literal: ast::LiteralKind) -> Option<proc_macro::bridge::LitKind> {
59+
Some(match lit.kind() {
60+
ast::LiteralKind::String(data) => {
61+
if data.is_raw() {
62+
bridge::LitKind::StrRaw(raw_delimiter_count(data)?)
63+
} else {
64+
bridge::LitKind::Str
65+
}
66+
}
67+
ast::LiteralKind::ByteString(data) => {
68+
if data.is_raw() {
69+
bridge::LitKind::ByteStrRaw(raw_delimiter_count(data)?)
70+
} else {
71+
bridge::LitKind::ByteStr
72+
}
73+
}
74+
ast::LiteralKind::CString(data) => {
75+
if data.is_raw() {
76+
bridge::LitKind::CStrRaw(raw_delimiter_count(data)?)
77+
} else {
78+
bridge::LitKind::CStr
79+
}
80+
}
81+
ast::LiteralKind::IntNumber(num) => bridge::LitKind::Integer,
82+
ast::LiteralKind::FloatNumber(num) => bridge::LitKind::Float,
83+
ast::LiteralKind::Char(_) => bridge::LitKind::Char,
84+
ast::LiteralKind::Byte(_) => bridge::LitKind::Byte,
85+
ast::LiteralKind::Bool(_) => unreachable!(),
86+
})
87+
}
88+
89+
fn raw_delimiter_count<S: IsString>(s: S) -> Option<u8> {
90+
let text = s.text();
91+
let quote_range = s.text_range_between_quotes()?;
92+
let range_start = s.syntax().text_range().start();
93+
text[TextRange::up_to((quote_range - range_start).start())].matches('#').count().try_into().ok()
94+
}
95+
96+
fn str_to_lit_node(input: &str) -> Option<ast::Literal> {
97+
let input = input.trim();
98+
let source_code = format!("fn f() {{ let _ = {input}; }}");
99+
100+
let parse = ast::SourceFile::parse(&source_code);
101+
let file = parse.tree();
102+
103+
let ast::Item::Fn(func) = file.items().next()? else { return None };
104+
let ast::Stmt::LetStmt(stmt) = func.body()?.stmt_list()?.statements().next()? else {
105+
return None;
106+
};
107+
let ast::Expr::Literal(lit) = stmt.initializer()? else { return None };
108+
109+
Some(lit)
110+
}
111+
57112
struct LiteralFormatter<S>(bridge::Literal<S, Symbol>);
58113

59114
impl<S> LiteralFormatter<S> {

crates/proc-macro-srv/src/server/rust_analyzer_span.rs

Lines changed: 12 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
//! It is an unfortunate result of how the proc-macro API works that we need to look into the
55
//! concrete representation of the spans, and as such, RustRover cannot make use of this unless they
66
//! change their representation to be compatible with rust-analyzer's.
7+
use core::num;
78
use std::{
89
collections::{HashMap, HashSet},
910
iter,
@@ -13,11 +14,11 @@ use std::{
1314
use ::tt::{TextRange, TextSize};
1415
use proc_macro::bridge::{self, server};
1516
use span::{Span, FIXUP_ERASED_FILE_AST_ID_MARKER};
16-
use syntax::ast::{self, HasModuleItem, IsString};
17+
use syntax::ast;
1718

1819
use crate::server::{
19-
delim_to_external, delim_to_internal, token_stream::TokenStreamBuilder, LiteralFormatter,
20-
Symbol, SymbolInternerRef, SYMBOL_INTERNER,
20+
delim_to_external, delim_to_internal, literal_to_external, str_to_lit_node,
21+
token_stream::TokenStreamBuilder, LiteralFormatter, Symbol, SymbolInternerRef, SYMBOL_INTERNER,
2122
};
2223
mod tt {
2324
pub use ::tt::*;
@@ -71,66 +72,15 @@ impl server::FreeFunctions for RaSpanServer {
7172
&mut self,
7273
s: &str,
7374
) -> Result<bridge::Literal<Self::Span, Self::Symbol>, ()> {
74-
let input = s.trim();
75-
let source_code = format!("fn f() {{ let _ = {input}; }}");
76-
77-
let parse = ast::SourceFile::parse(&source_code);
78-
let file = parse.tree();
79-
80-
let Some(ast::Item::Fn(func)) = file.items().next() else { return Err(()) };
81-
let Some(ast::Stmt::LetStmt(stmt)) =
82-
func.body().ok_or(Err(()))?.stmt_list().ok_or(Err(()))?.statements().next()
83-
else {
84-
return Err(());
85-
};
86-
let Some(ast::Expr::Literal(lit)) = stmt.initializer() else { return Err(()) };
87-
88-
fn raw_delimiter_count<S: IsString>(s: S) -> Option<u8> {
89-
let text = s.text();
90-
let quote_range = s.text_range_between_quotes()?;
91-
let range_start = s.syntax().text_range().start();
92-
text[TextRange::up_to((quote_range - range_start).start())]
93-
.matches('#')
94-
.count()
95-
.try_into()
96-
.ok()
97-
}
75+
let literal = str_to_lit_node(s).ok_or(Err(()))?;
9876

99-
let mut suffix = None;
100-
let kind = match lit.kind() {
101-
ast::LiteralKind::String(data) => {
102-
if data.is_raw() {
103-
bridge::LitKind::StrRaw(raw_delimiter_count(data).ok_or(Err(()))?)
104-
} else {
105-
bridge::LitKind::Str
106-
}
107-
}
108-
ast::LiteralKind::ByteString(data) => {
109-
if data.is_raw() {
110-
bridge::LitKind::ByteStrRaw(raw_delimiter_count(data).ok_or(Err(()))?)
111-
} else {
112-
bridge::LitKind::ByteStr
113-
}
114-
}
115-
ast::LiteralKind::CString(data) => {
116-
if data.is_raw() {
117-
bridge::LitKind::CStrRaw(raw_delimiter_count(data).ok_or(Err(()))?)
118-
} else {
119-
bridge::LitKind::CStr
120-
}
121-
}
122-
ast::LiteralKind::IntNumber(num) => {
123-
suffix = num.suffix();
124-
bridge::LitKind::Integer
125-
}
126-
ast::LiteralKind::FloatNumber(num) => {
127-
suffix = num.suffix();
128-
bridge::LitKind::Float
129-
}
130-
ast::LiteralKind::Char(_) => bridge::LitKind::Char,
131-
ast::LiteralKind::Byte(_) => bridge::LitKind::Byte,
132-
ast::LiteralKind::Bool(_) => unreachable!(),
133-
};
77+
let kind = literal_to_external(literal.kind()).ok_or(Err(()))?;
78+
79+
let suffix = match literal.kind() {
80+
ast::LiteralKind::FloatNumber(num) | ast::LiteralKind::IntNumber(num) => num.suffix(),
81+
_ => None,
82+
}
83+
.map(|suffix| Symbol::intern(self.interner, suffix));
13484

13585
Ok(bridge::Literal {
13686
kind,

crates/proc-macro-srv/src/server/token_id.rs

Lines changed: 9 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@ use std::{
66
};
77

88
use proc_macro::bridge::{self, server};
9-
use syntax::ast::{self, HasModuleItem, IsString};
9+
use syntax::ast;
1010

1111
use crate::server::{
12-
delim_to_external, delim_to_internal, token_stream::TokenStreamBuilder, LiteralFormatter,
13-
Symbol, SymbolInternerRef, SYMBOL_INTERNER,
12+
delim_to_external, delim_to_internal, literal_to_external, str_to_lit_node,
13+
token_stream::TokenStreamBuilder, LiteralFormatter, Symbol, SymbolInternerRef, SYMBOL_INTERNER,
1414
};
1515
mod tt {
1616
pub use proc_macro_api::msg::TokenId;
@@ -63,66 +63,15 @@ impl server::FreeFunctions for TokenIdServer {
6363
&mut self,
6464
s: &str,
6565
) -> Result<bridge::Literal<Self::Span, Self::Symbol>, ()> {
66-
let input = s.trim();
67-
let source_code = format!("fn f() {{ let _ = {input}; }}");
66+
let literal = str_to_lit_node(s).ok_or(Err(()))?;
6867

69-
let parse = ast::SourceFile::parse(&source_code);
70-
let file = parse.tree();
68+
let kind = literal_to_external(literal.kind()).ok_or(Err(()))?;
7169

72-
let Some(ast::Item::Fn(func)) = file.items().next() else { return Err(()) };
73-
let Some(ast::Stmt::LetStmt(stmt)) =
74-
func.body().ok_or(Err(()))?.stmt_list().ok_or(Err(()))?.statements().next()
75-
else {
76-
return Err(());
77-
};
78-
let Some(ast::Expr::Literal(lit)) = stmt.initializer() else { return Err(()) };
79-
80-
fn raw_delimiter_count<S: IsString>(s: S) -> Option<u8> {
81-
let text = s.text();
82-
let quote_range = s.text_range_between_quotes()?;
83-
let range_start = s.syntax().text_range().start();
84-
text[TextRange::up_to((quote_range - range_start).start())]
85-
.matches('#')
86-
.count()
87-
.try_into()
88-
.ok()
70+
let suffix = match literal.kind() {
71+
ast::LiteralKind::FloatNumber(num) | ast::LiteralKind::IntNumber(num) => num.suffix(),
72+
_ => None,
8973
}
90-
91-
let mut suffix = None;
92-
let kind = match lit.kind() {
93-
ast::LiteralKind::String(data) => {
94-
if data.is_raw() {
95-
bridge::LitKind::StrRaw(raw_delimiter_count(data).ok_or(Err(()))?)
96-
} else {
97-
bridge::LitKind::Str
98-
}
99-
}
100-
ast::LiteralKind::ByteString(data) => {
101-
if data.is_raw() {
102-
bridge::LitKind::ByteStrRaw(raw_delimiter_count(data).ok_or(Err(()))?)
103-
} else {
104-
bridge::LitKind::ByteStr
105-
}
106-
}
107-
ast::LiteralKind::CString(data) => {
108-
if data.is_raw() {
109-
bridge::LitKind::CStrRaw(raw_delimiter_count(data).ok_or(Err(()))?)
110-
} else {
111-
bridge::LitKind::CStr
112-
}
113-
}
114-
ast::LiteralKind::IntNumber(num) => {
115-
suffix = num.suffix();
116-
bridge::LitKind::Integer
117-
}
118-
ast::LiteralKind::FloatNumber(num) => {
119-
suffix = num.suffix();
120-
bridge::LitKind::Float
121-
}
122-
ast::LiteralKind::Char(_) => bridge::LitKind::Char,
123-
ast::LiteralKind::Byte(_) => bridge::LitKind::Byte,
124-
ast::LiteralKind::Bool(_) => unreachable!(),
125-
};
74+
.map(|suffix| Symbol::intern(self.interner, suffix));
12675

12776
Ok(bridge::Literal {
12877
kind,

0 commit comments

Comments
 (0)