Implement literal_from_str for proc macro srv

This commit is contained in:
Victor Song 2024-01-30 00:10:23 -06:00
parent 3770f73bd6
commit 68365513f3
2 changed files with 128 additions and 6 deletions

View File

@ -13,6 +13,7 @@
use ::tt::{TextRange, TextSize};
use proc_macro::bridge::{self, server};
use span::{Span, FIXUP_ERASED_FILE_AST_ID_MARKER};
use syntax::ast::{self, HasModuleItem, IsString};
use crate::server::{
delim_to_external, delim_to_internal, token_stream::TokenStreamBuilder, LiteralFormatter,
@ -70,11 +71,71 @@ fn literal_from_str(
&mut self,
s: &str,
) -> Result<bridge::Literal<Self::Span, Self::Symbol>, ()> {
// FIXME: keep track of LitKind and Suffix
let input = s.trim();
let source_code = format!("fn f() {{ let _ = {input}; }}");
let parse = ast::SourceFile::parse(&source_code);
let file = parse.tree();
let Some(ast::Item::Fn(func)) = file.items().next() else { return Err(()) };
let Some(ast::Stmt::LetStmt(stmt)) =
func.body().ok_or(Err(()))?.stmt_list().ok_or(Err(()))?.statements().next()
else {
return Err(());
};
let Some(ast::Expr::Literal(lit)) = stmt.initializer() else { return Err(()) };
fn raw_delimiter_count<S: IsString>(s: S) -> Option<u8> {
let text = s.text();
let quote_range = s.text_range_between_quotes()?;
let range_start = s.syntax().text_range().start();
text[TextRange::up_to((quote_range - range_start).start())]
.matches('#')
.count()
.try_into()
.ok()
}
let mut suffix = None;
let kind = match lit.kind() {
ast::LiteralKind::String(data) => {
if data.is_raw() {
bridge::LitKind::StrRaw(raw_delimiter_count(data).ok_or(Err(()))?)
} else {
bridge::LitKind::Str
}
}
ast::LiteralKind::ByteString(data) => {
if data.is_raw() {
bridge::LitKind::ByteStrRaw(raw_delimiter_count(data).ok_or(Err(()))?)
} else {
bridge::LitKind::ByteStr
}
}
ast::LiteralKind::CString(data) => {
if data.is_raw() {
bridge::LitKind::CStrRaw(raw_delimiter_count(data).ok_or(Err(()))?)
} else {
bridge::LitKind::CStr
}
}
ast::LiteralKind::IntNumber(num) => {
suffix = num.suffix();
bridge::LitKind::Integer
}
ast::LiteralKind::FloatNumber(num) => {
suffix = num.suffix();
bridge::LitKind::Float
}
ast::LiteralKind::Char(_) => bridge::LitKind::Char,
ast::LiteralKind::Byte(_) => bridge::LitKind::Byte,
ast::LiteralKind::Bool(_) => unreachable!(),
};
Ok(bridge::Literal {
kind: bridge::LitKind::Err,
kind,
symbol: Symbol::intern(self.interner, s),
suffix: None,
suffix,
span: self.call_site,
})
}

View File

@ -6,6 +6,7 @@
};
use proc_macro::bridge::{self, server};
use syntax::ast::{self, HasModuleItem, IsString};
use crate::server::{
delim_to_external, delim_to_internal, token_stream::TokenStreamBuilder, LiteralFormatter,
@ -62,11 +63,71 @@ fn literal_from_str(
&mut self,
s: &str,
) -> Result<bridge::Literal<Self::Span, Self::Symbol>, ()> {
// FIXME: keep track of LitKind and Suffix
let input = s.trim();
let source_code = format!("fn f() {{ let _ = {input}; }}");
let parse = ast::SourceFile::parse(&source_code);
let file = parse.tree();
let Some(ast::Item::Fn(func)) = file.items().next() else { return Err(()) };
let Some(ast::Stmt::LetStmt(stmt)) =
func.body().ok_or(Err(()))?.stmt_list().ok_or(Err(()))?.statements().next()
else {
return Err(());
};
let Some(ast::Expr::Literal(lit)) = stmt.initializer() else { return Err(()) };
fn raw_delimiter_count<S: IsString>(s: S) -> Option<u8> {
let text = s.text();
let quote_range = s.text_range_between_quotes()?;
let range_start = s.syntax().text_range().start();
text[TextRange::up_to((quote_range - range_start).start())]
.matches('#')
.count()
.try_into()
.ok()
}
let mut suffix = None;
let kind = match lit.kind() {
ast::LiteralKind::String(data) => {
if data.is_raw() {
bridge::LitKind::StrRaw(raw_delimiter_count(data).ok_or(Err(()))?)
} else {
bridge::LitKind::Str
}
}
ast::LiteralKind::ByteString(data) => {
if data.is_raw() {
bridge::LitKind::ByteStrRaw(raw_delimiter_count(data).ok_or(Err(()))?)
} else {
bridge::LitKind::ByteStr
}
}
ast::LiteralKind::CString(data) => {
if data.is_raw() {
bridge::LitKind::CStrRaw(raw_delimiter_count(data).ok_or(Err(()))?)
} else {
bridge::LitKind::CStr
}
}
ast::LiteralKind::IntNumber(num) => {
suffix = num.suffix();
bridge::LitKind::Integer
}
ast::LiteralKind::FloatNumber(num) => {
suffix = num.suffix();
bridge::LitKind::Float
}
ast::LiteralKind::Char(_) => bridge::LitKind::Char,
ast::LiteralKind::Byte(_) => bridge::LitKind::Byte,
ast::LiteralKind::Bool(_) => unreachable!(),
};
Ok(bridge::Literal {
kind: bridge::LitKind::Err,
kind,
symbol: Symbol::intern(self.interner, s),
suffix: None,
suffix,
span: self.call_site,
})
}