Skip to content

Commit 2f978b9

Browse files
committed
Move most of the python!{} expansion to a macro_rules.
1 parent d742d74 commit 2f978b9

File tree

3 files changed

+35
-39
lines changed

3 files changed

+35
-39
lines changed

macros/src/lib.rs

Lines changed: 7 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
extern crate proc_macro;
66

7-
use proc_macro::{Delimiter, Group, Literal, Span, TokenStream, TokenTree};
7+
use proc_macro::{Literal, Span, TokenStream, TokenTree};
88
use pyo3::{Py, Python};
99
use std::{
1010
collections::BTreeMap,
@@ -28,42 +28,15 @@ fn python_impl(input: TokenStream) -> Result<TokenStream, TokenStream> {
2828
let bytecode = compile_to_bytecode(&python, &filename, input)?;
2929
Ok(TokenStream::from_iter([
3030
punct(':'), punct(':'), ident("inline_python"),
31-
punct(':'), punct(':'), ident("FromInlinePython"),
32-
punct(':'), punct(':'), ident("from_python_macro"),
33-
parens([
34-
TokenTree::Literal(bytecode), punct(','),
35-
punct('|'), ident("globals"), punct('|'),
36-
braces(variables.into_iter().flat_map(|(key, value)| [
37-
punct(':'), punct(':'), ident("inline_python"),
38-
punct(':'), punct(':'), ident("pyo3"),
39-
punct(':'), punct(':'), ident("prelude"),
40-
punct(':'), punct(':'), ident("PyDictMethods"),
41-
punct(':'), punct(':'), ident("set_item"),
42-
parens([
43-
ident("globals"), punct(','),
44-
string(&key), punct(','),
45-
TokenTree::Ident(value)
46-
]),
47-
punct('.'), ident("expect"), parens([string("python")]),
48-
punct(';'),
49-
])),
50-
punct(','),
51-
punct('|'), ident("e"), punct('|'),
52-
punct(':'), punct(':'), ident("std"),
53-
punct(':'), punct(':'), ident("panic"),
54-
punct(':'), punct(':'), ident("panic_any"),
55-
parens([ident("e")]),
56-
]),
31+
punct(':'), punct(':'), ident("_python_block"),
32+
punct('!'),
33+
braces(
34+
[TokenTree::Literal(bytecode)].into_iter()
35+
.chain(variables.into_iter().map(|(_, value)| TokenTree::Ident(value)))
36+
),
5737
]))
5838
}
5939

60-
fn parens(t: impl IntoIterator<Item = TokenTree>) -> TokenTree {
61-
TokenTree::Group(Group::new(
62-
Delimiter::Parenthesis,
63-
TokenStream::from_iter(t),
64-
))
65-
}
66-
6740
fn compile_to_bytecode(
6841
python: &CStr,
6942
filename: &CStr,

macros/src/shared.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -116,13 +116,13 @@ pub(crate) fn python_from_macro(
116116
&& x.as_char() == '\''
117117
&& x.spacing() == Spacing::Joint
118118
{
119-
let Some(TokenTree::Ident(name)) = tokens.next() else {
119+
let Some(TokenTree::Ident(ident)) = tokens.next() else {
120120
unreachable!()
121121
};
122-
let name_str = format!("_RUST_{name}");
123-
python.push_str(&name_str);
124-
loc.column += name_str.chars().count() - 6 + 1;
125-
variables.entry(name_str).or_insert(name);
122+
let name = ident.to_string();
123+
write!(python, "_RUST_{name}").unwrap();
124+
loc.column += name.chars().count() + 1;
125+
variables.entry(name).or_insert(ident);
126126
} else if x.as_char() == '#' && x.spacing() == Spacing::Joint {
127127
// Convert '##' to '//', because otherwise it's
128128
// impossible to use the Python operators '//' and '//='.

src/lib.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,29 @@ pub use pyo3;
143143
/// See [the crate's module level documentation](index.html) for examples.
144144
pub use inline_python_macros::python;
145145

146+
// `python!{..}` expands to `python_impl!{b"bytecode" var1 var2 …}`,
147+
// which then expands to a call to `FromInlinePython::from_python_macro`.
148+
#[macro_export]
149+
#[doc(hidden)]
150+
macro_rules! _python_block {
151+
($bytecode:literal $($var:ident)*) => {
152+
$crate::FromInlinePython::from_python_macro(
153+
// The compiled python bytecode:
154+
$bytecode,
155+
// The closure that puts all the captured variables in the 'globals' dictionary:
156+
|globals| {
157+
$(
158+
$crate::pyo3::prelude::PyDictMethods::set_item(
159+
globals, concat!("_RUST_", stringify!($var)), $var
160+
).expect("python");
161+
)*
162+
},
163+
// The closure that is used to throw panics with the right location:
164+
|e| ::std::panic::panic_any(e),
165+
)
166+
}
167+
}
168+
146169
#[doc(hidden)]
147170
pub trait FromInlinePython<F: FnOnce(&Bound<PyDict>)> {
148171
/// The `python!{}` macro expands to a call to this function.

0 commit comments

Comments
 (0)