Skip to content

Commit 766d5f5

Browse files
committed
Remove proc_macro2 and quote dependencies.
1 parent 51ef3d1 commit 766d5f5

File tree

5 files changed

+94
-67
lines changed

5 files changed

+94
-67
lines changed

macros/Cargo.toml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,6 @@ repository = "https://github.com/m-ou-se/inline-python"
1010
proc-macro = true
1111

1212
[dependencies]
13-
proc-macro2 = { version = "1.0", features = ["span-locations"] }
14-
quote = "1.0"
1513
pyo3 = { version = "0.24", default-features = false, features = ["auto-initialize"] }
1614

1715
[target.'cfg(unix)'.dependencies]

macros/src/embed_python.rs

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
use proc_macro::Span;
2-
use proc_macro2::{Delimiter, Ident, Spacing, TokenStream, TokenTree};
3-
use quote::quote_spanned;
1+
use super::compile_error;
2+
use proc_macro::{Delimiter, Ident, Spacing, Span, TokenStream, TokenTree};
43
use std::collections::BTreeMap;
54
use std::fmt::Write;
65

@@ -34,7 +33,7 @@ impl EmbedPython {
3433
}
3534
let first_indent = *self.first_indent.get_or_insert(column);
3635
let indent = column.checked_sub(first_indent);
37-
let indent = indent.ok_or_else(|| quote_spanned!(span.into() => compile_error!{"Invalid indentation"}))?;
36+
let indent = indent.ok_or_else(|| compile_error(Some((span, span)), "invalid indent"))?;
3837
for _ in 0..indent {
3938
self.python.push(' ');
4039
}
@@ -53,7 +52,7 @@ impl EmbedPython {
5352
let mut tokens = input.into_iter();
5453

5554
while let Some(token) = tokens.next() {
56-
let span = token.span().unwrap();
55+
let span = token.span();
5756
self.add_whitespace(span, span.line(), span.column())?;
5857

5958
match &token {
@@ -67,7 +66,7 @@ impl EmbedPython {
6766
self.python.push_str(start);
6867
self.column += start.len();
6968
self.add(x.stream())?;
70-
let end_span = token.span().unwrap().end();
69+
let end_span = token.span().end();
7170
self.add_whitespace(span, end_span.line(), end_span.column().saturating_sub(end.len()))?;
7271
self.python.push_str(end);
7372
self.column += end.len();
@@ -107,7 +106,7 @@ impl EmbedPython {
107106
}
108107
TokenTree::Ident(x) => {
109108
write!(&mut self.python, "{}", x).unwrap();
110-
let end_span = token.span().unwrap().end();
109+
let end_span = token.span().end();
111110
self.line = end_span.line();
112111
self.column = end_span.column();
113112
}
@@ -122,7 +121,7 @@ impl EmbedPython {
122121
self.python.pop();
123122
}
124123
self.python += &s;
125-
let end_span = token.span().unwrap().end();
124+
let end_span = token.span().end();
126125
self.line = end_span.line();
127126
self.column = end_span.column();
128127
}

macros/src/error.rs

Lines changed: 11 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,21 @@
1-
use proc_macro::{TokenTree, Span, TokenStream as TokenStream1};
2-
use proc_macro2::TokenStream;
3-
use pyo3::{prelude::*, types::PyTraceback, Bound, IntoPyObject, PyErr, PyResult, PyTypeInfo, Python};
4-
use quote::{quote, quote_spanned};
1+
use super::compile_error;
2+
use proc_macro::{Span, TokenStream, TokenTree};
3+
use pyo3::{Bound, IntoPyObject, PyErr, PyResult, PyTypeInfo, Python, prelude::*, types::PyTraceback};
54

65
/// Format a nice error message for a python compilation error.
76
pub fn compile_error_msg(py: Python, error: PyErr, tokens: TokenStream) -> TokenStream {
87
let value = (&error).into_pyobject(py).unwrap();
98

109
if value.is_none() {
11-
let error = format!("python: {}", error.get_type(py).name().unwrap());
12-
return quote!(compile_error! {#error});
10+
return compile_error(None, &error.get_type(py).name().unwrap());
1311
}
1412

1513
if let Ok(true) = error.matches(py, pyo3::exceptions::PySyntaxError::type_object(py)) {
1614
let line: Option<usize> = value.getattr("lineno").ok().and_then(|x| x.extract().ok());
1715
let msg: Option<String> = value.getattr("msg").ok().and_then(|x| x.extract().ok());
1816
if let (Some(line), Some(msg)) = (line, msg) {
19-
if let Some(spans) = spans_for_line(tokens.clone().into(), line) {
20-
return compile_error(spans, format!("python: {msg}"));
17+
if let Some(spans) = spans_for_line(tokens.clone(), line) {
18+
return compile_error(Some(spans), &msg);
2119
}
2220
}
2321
}
@@ -26,16 +24,15 @@ pub fn compile_error_msg(py: Python, error: PyErr, tokens: TokenStream) -> Token
2624
if let Ok((file, line)) = get_traceback_info(tb) {
2725
if file == Span::call_site().file() {
2826
if let Ok(msg) = value.str() {
29-
if let Some(spans) = spans_for_line(tokens.into(), line) {
30-
return compile_error(spans, format!("python: {msg}"));
27+
if let Some(spans) = spans_for_line(tokens, line) {
28+
return compile_error(Some(spans), &msg);
3129
}
3230
}
3331
}
3432
}
3533
}
3634

37-
let error = format!("python: {}", value.str().unwrap());
38-
quote!(compile_error! {#error})
35+
compile_error(None, &value.str().unwrap())
3936
}
4037

4138
fn get_traceback_info(tb: &Bound<'_, PyTraceback>) -> PyResult<(String, usize)> {
@@ -46,7 +43,7 @@ fn get_traceback_info(tb: &Bound<'_, PyTraceback>) -> PyResult<(String, usize)>
4643
Ok((file, line))
4744
}
4845

49-
fn for_all_spans(input: TokenStream1, f: &mut impl FnMut(Span)) {
46+
fn for_all_spans(input: TokenStream, f: &mut impl FnMut(Span)) {
5047
for token in input {
5148
match token {
5249
TokenTree::Group(group) => {
@@ -60,7 +57,7 @@ fn for_all_spans(input: TokenStream1, f: &mut impl FnMut(Span)) {
6057
}
6158

6259
/// Get the first and last span for a specific line of input from a TokenStream.
63-
fn spans_for_line(input: TokenStream1, line: usize) -> Option<(Span, Span)> {
60+
fn spans_for_line(input: TokenStream, line: usize) -> Option<(Span, Span)> {
6461
let mut spans = None;
6562
for_all_spans(input, &mut |span| {
6663
if span.start().line() == line {
@@ -69,9 +66,3 @@ fn spans_for_line(input: TokenStream1, line: usize) -> Option<(Span, Span)> {
6966
});
7067
spans
7168
}
72-
73-
/// Create a compile_error!{} using two spans that mark the start and end of the error.
74-
fn compile_error(spans: (Span, Span), error: String) -> TokenStream {
75-
let path = quote_spanned!(spans.0.into() => ::core::compile_error);
76-
quote_spanned!(spans.1.into() => #path!{#error})
77-
}

macros/src/lib.rs

Lines changed: 75 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,15 @@
55
extern crate proc_macro;
66

77
use self::embed_python::EmbedPython;
8-
use proc_macro::{Span, TokenStream as TokenStream1};
9-
use proc_macro2::{Literal, TokenStream};
10-
use pyo3::{ffi, Py, PyObject, Python};
11-
use quote::quote;
12-
use std::ffi::CString;
8+
use proc_macro::{Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree};
9+
use pyo3::{Py, PyObject, Python, ffi};
10+
use std::{ffi::CString, fmt::Display};
1311

1412
mod embed_python;
1513
mod error;
1614
mod run;
1715

16+
#[rustfmt::skip]
1817
fn python_impl(input: TokenStream) -> Result<TokenStream, TokenStream> {
1918
let tokens = input.clone();
2019

@@ -31,35 +30,55 @@ fn python_impl(input: TokenStream) -> Result<TokenStream, TokenStream> {
3130

3231
let bytecode = unsafe {
3332
let result: Result<Literal, TokenStream> = Python::with_gil(|py| {
34-
let code = PyObject::from_owned_ptr_or_err(py, ffi::Py_CompileString(python.as_ptr(), filename.as_ptr(), ffi::Py_file_input))
35-
.map_err(|err| error::compile_error_msg(py, err, tokens))?;
36-
37-
Ok(Literal::byte_string(
38-
Py::from_owned_ptr_or_err(py, ffi::PyMarshal_WriteObjectToString(code.as_ptr(), pyo3::marshal::VERSION))
39-
.map_err(|_e| quote!(compile_error! {"failed to generate python bytecode"}))?
40-
.as_bytes(py),
41-
))
33+
let code = PyObject::from_owned_ptr_or_err(py,
34+
ffi::Py_CompileString(python.as_ptr(), filename.as_ptr(), ffi::Py_file_input)
35+
).map_err(|err| error::compile_error_msg(py, err, tokens))?;
36+
Ok(Literal::byte_string(Py::from_owned_ptr_or_err(py,
37+
ffi::PyMarshal_WriteObjectToString(code.as_ptr(), pyo3::marshal::VERSION)
38+
).map_err(|_| compile_error(None, "failed to generate bytecode"))?.as_bytes(py)))
4239
});
4340
result?
4441
};
4542

46-
let varname = variables.keys();
47-
let var = variables.values();
48-
49-
Ok(quote! {
50-
::inline_python::FromInlinePython::from_python_macro(
51-
#bytecode,
52-
|globals| {
53-
#(
54-
::inline_python::pyo3::prelude::PyDictMethods::set_item(
55-
globals,
56-
#varname,
57-
#var
58-
).expect("Unable to convert variable to Python");
59-
)*
60-
},
61-
)
62-
})
43+
Ok(TokenStream::from_iter([
44+
punct(':'), punct(':'), ident("inline_python"),
45+
punct(':'), punct(':'), ident("FromInlinePython"),
46+
punct(':'), punct(':'), ident("from_python_macro"),
47+
parens([
48+
TokenTree::Literal(bytecode), punct(','),
49+
punct('|'), ident("globals"), punct('|'),
50+
braces(variables.into_iter().flat_map(|(key, value)| [
51+
punct(':'), punct(':'), ident("inline_python"),
52+
punct(':'), punct(':'), ident("pyo3"),
53+
punct(':'), punct(':'), ident("prelude"),
54+
punct(':'), punct(':'), ident("PyDictMethods"),
55+
punct(':'), punct(':'), ident("set_item"),
56+
parens([
57+
ident("globals"), punct(','),
58+
string(&key), punct(','),
59+
TokenTree::Ident(value)
60+
]),
61+
punct('.'), ident("expect"), parens([string("python")]),
62+
punct(';'),
63+
]))
64+
]),
65+
]))
66+
}
67+
68+
/// Create a compile_error!{} using two spans that mark the start and end of the error.
69+
#[rustfmt::skip]
70+
fn compile_error(spans: Option<(Span, Span)>, error: &(impl Display + ?Sized)) -> TokenStream {
71+
let mut tokens = [
72+
punct(':'), punct(':'), ident("core"),
73+
punct(':'), punct(':'), ident("compile_error"),
74+
punct('!'), braces([string(&format!("python: {error}"))]),
75+
];
76+
if let Some((span1, span2)) = spans {
77+
for (i, t) in tokens.iter_mut().enumerate() {
78+
t.set_span(if i < 6 { span1 } else { span2 });
79+
}
80+
}
81+
TokenStream::from_iter(tokens)
6382
}
6483

6584
fn ct_python_impl(input: TokenStream) -> Result<TokenStream, TokenStream> {
@@ -90,18 +109,38 @@ fn ct_python_impl(input: TokenStream) -> Result<TokenStream, TokenStream> {
90109

91110
#[doc(hidden)]
92111
#[proc_macro]
93-
pub fn python(input: TokenStream1) -> TokenStream1 {
94-
TokenStream1::from(match python_impl(TokenStream::from(input)) {
112+
pub fn python(input: TokenStream) -> TokenStream {
113+
match python_impl(input) {
95114
Ok(tokens) => tokens,
96115
Err(tokens) => tokens,
97-
})
116+
}
98117
}
99118

100119
#[doc(hidden)]
101120
#[proc_macro]
102-
pub fn ct_python(input: TokenStream1) -> TokenStream1 {
103-
TokenStream1::from(match ct_python_impl(TokenStream::from(input)) {
121+
pub fn ct_python(input: TokenStream) -> TokenStream {
122+
match ct_python_impl(input) {
104123
Ok(tokens) => tokens,
105124
Err(tokens) => tokens,
106-
})
125+
}
126+
}
127+
128+
fn punct(p: char) -> TokenTree {
129+
TokenTree::Punct(Punct::new(p, Spacing::Joint))
130+
}
131+
132+
fn ident(s: &str) -> TokenTree {
133+
TokenTree::Ident(Ident::new(s, Span::call_site()))
134+
}
135+
136+
fn parens(t: impl IntoIterator<Item = TokenTree>) -> TokenTree {
137+
TokenTree::Group(Group::new(Delimiter::Parenthesis, TokenStream::from_iter(t)))
138+
}
139+
140+
fn braces(t: impl IntoIterator<Item = TokenTree>) -> TokenTree {
141+
TokenTree::Group(Group::new(Delimiter::Brace, TokenStream::from_iter(t)))
142+
}
143+
144+
fn string(s: &str) -> TokenTree {
145+
TokenTree::Literal(Literal::string(s))
107146
}

macros/src/run.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::error::compile_error_msg;
2-
use proc_macro2::TokenStream;
2+
use proc_macro::TokenStream;
33
use pyo3::{ffi, prelude::*, PyObject, PyResult, Python};
44
use std::str::FromStr;
55

0 commit comments

Comments
 (0)