diff --git a/Cargo.lock b/Cargo.lock index 729b94364..f9cca5b01 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -124,6 +124,7 @@ version = "0.6.31-nightly.0" dependencies = [ "backtrace-on-stack-overflow", "crossterm", + "erg_proc_macros", "parking_lot", "pyo3", "thread_local", @@ -152,7 +153,6 @@ dependencies = [ name = "erg_proc_macros" version = "0.6.31-nightly.0" dependencies = [ - "erg_common", "quote", "syn 1.0.109", ] diff --git a/crates/erg_common/Cargo.toml b/crates/erg_common/Cargo.toml index 6f865f063..d0ba11190 100644 --- a/crates/erg_common/Cargo.toml +++ b/crates/erg_common/Cargo.toml @@ -34,6 +34,7 @@ crossterm = { optional = true, version = "0.25.0" } parking_lot = "0.12" thread_local = "1.1" pyo3 = { workspace = true, optional = true } +erg_proc_macros = { workspace = true } [lib] path = "lib.rs" diff --git a/crates/erg_common/config.rs b/crates/erg_common/config.rs index 254202a81..657f43019 100644 --- a/crates/erg_common/config.rs +++ b/crates/erg_common/config.rs @@ -15,6 +15,11 @@ use crate::normalize_path; use crate::python_util::{detect_magic_number, get_python_version, PythonVersion}; use crate::serialize::{get_magic_num_from_bytes, get_ver_from_magic_num}; +#[cfg(not(feature = "pylib"))] +use erg_proc_macros::{new, pyclass, pymethods}; +#[cfg(feature = "pylib")] +use pyo3::prelude::*; + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum ErgMode { Lex, @@ -92,6 +97,7 @@ impl From<&str> for TranspileTarget { } } +#[pyclass] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct Package { pub name: &'static str, @@ -116,6 +122,19 @@ impl Package { } } +#[pymethods] +impl Package { + #[new] + fn _new(name: String, as_name: String, version: String, path: Option) -> Self { + Self { + name: Box::leak(name.into_boxed_str()), + as_name: Box::leak(as_name.into_boxed_str()), + version: Box::leak(version.into_boxed_str()), + path: path.map(|s| Box::leak(s.into_boxed_str()) as &'static str), + } + } +} + #[derive(Debug, Clone)] pub struct ErgConfig { pub mode: ErgMode, diff --git a/crates/erg_compiler/error/mod.rs b/crates/erg_compiler/error/mod.rs index dca91de77..f652da9fe 100644 --- a/crates/erg_compiler/error/mod.rs +++ b/crates/erg_compiler/error/mod.rs @@ -614,7 +614,7 @@ impl From for ParseErrors { #[cfg(feature = "pylib")] impl std::convert::From for pyo3::PyErr { fn from(errs: CompileErrors) -> pyo3::PyErr { - pyo3::exceptions::PyOSError::new_err(errs[0].to_string()) + pyo3::exceptions::PyOSError::new_err(format!("{} errors occurred\n{errs}", errs.len())) } } diff --git a/crates/erg_compiler/lib.rs b/crates/erg_compiler/lib.rs index 9d919e5c9..d8de18435 100644 --- a/crates/erg_compiler/lib.rs +++ b/crates/erg_compiler/lib.rs @@ -27,6 +27,9 @@ pub mod transpile; pub mod ty; pub mod varinfo; +#[allow(unused)] +use erg_common::config::Package; + pub use build_hir::{GenericHIRBuilder, HIRBuilder}; pub use erg_parser::build_ast::ASTBuilder; pub use transpile::Transpiler; @@ -36,16 +39,22 @@ use pyo3::prelude::*; #[cfg(feature = "pylib")] use pyo3::types::{IntoPyDict, PyBytes}; -/// compile(code: str, mode: str) -> code +/// compile_with_dependencies(code: str, mode: str, pkgs: list[Package]) -> code /// -- /// /// compile an Erg code as a module at runtime #[cfg(feature = "pylib")] #[pyfunction] -#[pyo3(name = "compile")] -fn _compile(py: Python<'_>, code: String, mode: &str) -> Result { +#[pyo3(name = "compile_with_dependencies")] +fn _compile_with_dependencies( + py: Python<'_>, + code: String, + mode: &str, + pkgs: Vec, +) -> Result { use erg_common::{config::ErgConfig, traits::Runnable}; - let cfg = ErgConfig::string(code); + let mut cfg = ErgConfig::string(code); + cfg.packages = pkgs; let mut compiler = Compiler::new(cfg); let src = compiler.cfg_mut().input.read(); let code = compiler @@ -59,6 +68,17 @@ fn _compile(py: Python<'_>, code: String, mode: &str) -> Result code +/// -- +/// +/// compile an Erg code as a module at runtime +#[cfg(feature = "pylib")] +#[pyfunction] +#[pyo3(name = "compile")] +fn _compile(py: Python<'_>, code: String, mode: &str) -> Result { + _compile_with_dependencies(py, code, mode, vec![]) +} + /// compile_ast(ast: erg_parser.AST, mode: str) -> code /// -- /// @@ -99,6 +119,22 @@ fn _compile_file(py: Python<'_>, path: String) -> Result code +/// -- +/// +/// compile an Erg file as a module at runtime +#[cfg(feature = "pylib")] +#[pyfunction] +#[pyo3(name = "compile_file_with_dependencies")] +fn _compile_file_with_dependencies( + py: Python<'_>, + path: String, + pkgs: Vec, +) -> Result { + let code = std::fs::read_to_string(&path).unwrap_or_else(|err| panic!("{err}, path: {path}")); + _compile_with_dependencies(py, code, "exec", pkgs) +} + /// exec(code: str) -> module /// -- /// @@ -145,9 +181,12 @@ fn _import(py: Python<'_>, name: String) -> Result, m: &PyModule) -> PyResult<()> { + m.add_class::()?; m.add_function(wrap_pyfunction!(_compile, m)?)?; + m.add_function(wrap_pyfunction!(_compile_with_dependencies, m)?)?; m.add_function(wrap_pyfunction!(_compile_ast, m)?)?; m.add_function(wrap_pyfunction!(_compile_file, m)?)?; + m.add_function(wrap_pyfunction!(_compile_file_with_dependencies, m)?)?; m.add_function(wrap_pyfunction!(_exec, m)?)?; m.add_function(wrap_pyfunction!(_exec_ast, m)?)?; m.add_function(wrap_pyfunction!(_import, m)?)?; diff --git a/crates/erg_proc_macros/Cargo.toml b/crates/erg_proc_macros/Cargo.toml index 21ea94761..d7b1cc425 100644 --- a/crates/erg_proc_macros/Cargo.toml +++ b/crates/erg_proc_macros/Cargo.toml @@ -11,7 +11,6 @@ homepage.workspace = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -erg_common = { workspace = true } syn = { version = "1.0", features = ["full"] } quote = "1.0" diff --git a/crates/erg_proc_macros/src/lib.rs b/crates/erg_proc_macros/src/lib.rs index 7fa481386..b7310e072 100644 --- a/crates/erg_proc_macros/src/lib.rs +++ b/crates/erg_proc_macros/src/lib.rs @@ -100,6 +100,12 @@ pub fn setter(_attr: TokenStream, item: TokenStream) -> TokenStream { item } +/// dummy attribute +#[proc_macro_attribute] +pub fn new(_attr: TokenStream, item: TokenStream) -> TokenStream { + item +} + fn args_to_owned(args: &PathArguments) -> PathArguments { match args { PathArguments::AngleBracketed(args) => {