about summary refs log tree commit diff
diff options
context:
space:
mode:
authorVictor Song <vsong1618@gmail.com>2024-01-30 00:10:23 -0600
committerVictor Song <vsong1618@gmail.com>2024-02-13 00:00:02 -0600
commit68365513f36a73d9c7ea906f2f08f561a99e63c5 (patch)
tree8be92b9acf46a827a3a7b2660b5bf463021ca044
parent3770f73bd661514b14a67f9ebd314e9ffa264fd7 (diff)
downloadrust-68365513f36a73d9c7ea906f2f08f561a99e63c5.tar.gz
rust-68365513f36a73d9c7ea906f2f08f561a99e63c5.zip
Implement `literal_from_str` for proc macro srv
-rw-r--r--crates/proc-macro-srv/src/server/rust_analyzer_span.rs67
-rw-r--r--crates/proc-macro-srv/src/server/token_id.rs67
2 files changed, 128 insertions, 6 deletions
diff --git a/crates/proc-macro-srv/src/server/rust_analyzer_span.rs b/crates/proc-macro-srv/src/server/rust_analyzer_span.rs
index c7c7bea9941..f7bbbcc09d4 100644
--- a/crates/proc-macro-srv/src/server/rust_analyzer_span.rs
+++ b/crates/proc-macro-srv/src/server/rust_analyzer_span.rs
@@ -13,6 +13,7 @@ use std::{
 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 @@ impl server::FreeFunctions for RaSpanServer {
         &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,
         })
     }
diff --git a/crates/proc-macro-srv/src/server/token_id.rs b/crates/proc-macro-srv/src/server/token_id.rs
index edbdc67b482..5c74c15b360 100644
--- a/crates/proc-macro-srv/src/server/token_id.rs
+++ b/crates/proc-macro-srv/src/server/token_id.rs
@@ -6,6 +6,7 @@ use std::{
 };
 
 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 @@ impl server::FreeFunctions for TokenIdServer {
         &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,
         })
     }