mpy
| -rw-r--r-- | .gitignore | 2 | ||||
| -rw-r--r-- | Cargo.toml | 13 | ||||
| -rw-r--r-- | src/lib.rs | 10 | ||||
| -rw-r--r-- | src/run.rs | 99 | ||||
| -rw-r--r-- | tests/test.rs | 4 |
5 files changed, 128 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5556cac --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +Cargo.lock +ronner
\ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..0d21af6 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "mpy" +version = "0.1.0" +edition = "2024" + +[dependencies] +syn = "2.0.104" +proc-macro2 = "1.0.78" +quote = "1.0.40" +pyo3 = { version = "0.25.1", features = ["extension-module"] } + +[lib] +proc-macro = true diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..d332303 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,10 @@ +#![feature(if_let_guard, proc_macro_quote)] +mod run; +use std::ffi::CString; + +use proc_macro::TokenStream; +use syn::Lit; +#[proc_macro] +pub fn eval(i: TokenStream) -> TokenStream { + run::exec(&CString::new(i.to_string()).unwrap()).into() +} diff --git a/src/run.rs b/src/run.rs new file mode 100644 index 0000000..e12450f --- /dev/null +++ b/src/run.rs @@ -0,0 +1,99 @@ +pub fn runpy(py: String) {} +use proc_macro::Ident; +use proc_macro::Literal; +use proc_macro::TokenStream; +use proc_macro::quote; +use std::cell::RefCell; +use std::ffi::CStr; +use std::ffi::CString; +use std::sync::Mutex; +use std::sync::RwLock; + +use proc_macro::Span; +use proc_macro::TokenTree; +use pyo3::exceptions::PyTypeError; +use pyo3::prelude::*; +use pyo3::types::*; + +struct R(proc_macro::TokenStream); +impl<'py, 's> FromPyObject<'py> for R { + fn extract_bound(x: &Bound<'py, PyAny>) -> Result<R, PyErr> { + let tree: TokenTree = match () { + () if let Ok(x) = x.extract::<i128>() => Literal::i128_unsuffixed(x).into(), + () if let Ok(x) = x.extract::<f64>() => Literal::f64_unsuffixed(x).into(), + () if let Ok(x) = x.extract::<bool>() => { + Ident::new(&x.to_string(), Span::call_site()).into() + } + () if let Ok(x) = x.extract::<String>() => { + return Ok(R(x + .parse::<TokenStream>() + .unwrap_or(quote::quote!(compile_error!("lex failure")).into()))); + } + + // () if let Ok(x) = x.downcast::<PyList>() => { + // if let Ok(y) = x.get_item(0) { + // match () { + // () if y.is_instance_of::<PyFloat>() => Val::Array(Array::Float( + // x.into_iter().map(|x| x.extract::<f64>()).try_collect()?, + // )), + // () if y.is_instance_of::<PyInt>() => Val::Array(Array::Int( + // x.into_iter().map(|x| x.extract::<i128>()).try_collect()?, + // )), + // _ => { + // return Err(PyTypeError::new_err("bad array types")); + // } + // } + // } else { + // Val::Array(Array::Int(vec![])) + // } + // } + // () if let Ok(x) = x.downcast::<PySet>() => Val::Set( + // x.into_iter() + // .map(|x| x.extract::<Val<'s>>()) + // .try_collect()?, + // ), + _ => return Err(PyTypeError::new_err("bad types")), + }; + let mut t = TokenStream::new(); + t.extend([tree]); + Ok(R(t)) + } +} + +pub fn exec<'s>(code: &CStr) -> TokenStream { + pyo3::prepare_freethreaded_python(); + Python::with_gil(|g| { + g.run( + cr#"__import__("sys").stdout = __import__("io").StringIO()"#, + None, + None, + ) + .unwrap(); + Ok::<_, ()>( + g.run(&code, None, None) + .map(|()| { + g.eval(cr#"__import__("sys").stdout.getvalue()"#, None, None) + .unwrap() + .extract::<String>() + .unwrap() + .parse::<TokenStream>() + .unwrap() + }) + .unwrap_or_else(|x| { + eprintln!("error:"); + x.display(g); + let e = x.to_string(); + quote::quote!(compile_error!("there was a problem running the python: ", #e)) + .into() + }), + ) + // stack.extend( + // x.into_iter() + // .skip(n.saturating_sub(argc.output)) + // .map(|x| x.extract::<Val<'_>>().map(|x| x.spun(span))) + // .try_collect::<Vec<_>>() + // .map_err(|_| Error::lazy(code.span, "nooo"))?, + // ); + }) + .unwrap() +} diff --git a/tests/test.rs b/tests/test.rs new file mode 100644 index 0000000..3500511 --- /dev/null +++ b/tests/test.rs @@ -0,0 +1,4 @@ +#[test] +fn main() { + dbg!(mpy::eval! { "print([n for n in range(2)])" }); +} |