Skip to content

Commit 6836551

Browse files
committed
Implement literal_from_str for proc macro srv
1 parent 3770f73 commit 6836551

File tree

2 files changed

+128
-6
lines changed

2 files changed

+128
-6
lines changed

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

Lines changed: 64 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use std::{
1313
use ::tt::{TextRange, TextSize};
1414
use proc_macro::bridge::{self, server};
1515
use span::{Span, FIXUP_ERASED_FILE_AST_ID_MARKER};
16+
use syntax::ast::{self, HasModuleItem, IsString};
1617

1718
use crate::server::{
1819
delim_to_external, delim_to_internal, token_stream::TokenStreamBuilder, LiteralFormatter,
@@ -70,11 +71,71 @@ impl server::FreeFunctions for RaSpanServer {
7071
&mut self,
7172
s: &str,
7273
) -> Result<bridge::Literal<Self::Span, Self::Symbol>, ()> {
73-
// FIXME: keep track of LitKind and Suffix
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+
}
98+
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+
};
134+
74135
Ok(bridge::Literal {
75-
kind: bridge::LitKind::Err,
136+
kind,
76137
symbol: Symbol::intern(self.interner, s),
77-
suffix: None,
138+
suffix,
78139
span: self.call_site,
79140
})
80141
}

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

Lines changed: 64 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use std::{
66
};
77

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

1011
use crate::server::{
1112
delim_to_external, delim_to_internal, token_stream::TokenStreamBuilder, LiteralFormatter,
@@ -62,11 +63,71 @@ impl server::FreeFunctions for TokenIdServer {
6263
&mut self,
6364
s: &str,
6465
) -> Result<bridge::Literal<Self::Span, Self::Symbol>, ()> {
65-
// FIXME: keep track of LitKind and Suffix
66+
let input = s.trim();
67+
let source_code = format!("fn f() {{ let _ = {input}; }}");
68+
69+
let parse = ast::SourceFile::parse(&source_code);
70+
let file = parse.tree();
71+
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()
89+
}
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+
};
126+
66127
Ok(bridge::Literal {
67-
kind: bridge::LitKind::Err,
128+
kind,
68129
symbol: Symbol::intern(self.interner, s),
69-
suffix: None,
130+
suffix,
70131
span: self.call_site,
71132
})
72133
}

0 commit comments

Comments
 (0)