5
5
extern crate proc_macro;
6
6
7
7
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 } ;
13
11
14
12
mod embed_python;
15
13
mod error;
16
14
mod run;
17
15
16
+ #[ rustfmt:: skip]
18
17
fn python_impl ( input : TokenStream ) -> Result < TokenStream , TokenStream > {
19
18
let tokens = input. clone ( ) ;
20
19
@@ -31,35 +30,55 @@ fn python_impl(input: TokenStream) -> Result<TokenStream, TokenStream> {
31
30
32
31
let bytecode = unsafe {
33
32
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) ) )
42
39
} ) ;
43
40
result?
44
41
} ;
45
42
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)
63
82
}
64
83
65
84
fn ct_python_impl ( input : TokenStream ) -> Result < TokenStream , TokenStream > {
@@ -90,18 +109,38 @@ fn ct_python_impl(input: TokenStream) -> Result<TokenStream, TokenStream> {
90
109
91
110
#[ doc( hidden) ]
92
111
#[ 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) {
95
114
Ok ( tokens) => tokens,
96
115
Err ( tokens) => tokens,
97
- } )
116
+ }
98
117
}
99
118
100
119
#[ doc( hidden) ]
101
120
#[ 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) {
104
123
Ok ( tokens) => tokens,
105
124
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) )
107
146
}
0 commit comments