mirror of
https://github.com/erg-lang/erg.git
synced 2025-09-27 19:59:07 +00:00
feat: make erg_compiler
available as a Python lib
This commit is contained in:
parent
22ccf4d870
commit
8b17c6cf6c
9 changed files with 152 additions and 4 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -135,6 +135,7 @@ version = "0.6.25"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"erg_common",
|
"erg_common",
|
||||||
"erg_parser",
|
"erg_parser",
|
||||||
|
"pyo3",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
|
@ -40,15 +40,19 @@ els = ["erg_common/els"]
|
||||||
no_std = ["erg_common/no_std"]
|
no_std = ["erg_common/no_std"]
|
||||||
full-repl = ["erg_common/full-repl"]
|
full-repl = ["erg_common/full-repl"]
|
||||||
experimental = ["erg_common/experimental", "erg_parser/experimental"]
|
experimental = ["erg_common/experimental", "erg_parser/experimental"]
|
||||||
|
pylib = ["dep:pyo3", "erg_common/pylib", "erg_parser/pylib"]
|
||||||
|
pylib_compiler = ["pylib"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
erg_common = { workspace = true }
|
erg_common = { workspace = true }
|
||||||
erg_parser = { workspace = true }
|
erg_parser = { workspace = true }
|
||||||
|
pyo3 = { workspace = true, optional = true }
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
erg_common = { workspace = true }
|
erg_common = { workspace = true }
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
|
crate-type = ["cdylib", "rlib"]
|
||||||
path = "lib.rs"
|
path = "lib.rs"
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
|
|
|
@ -1,3 +1,35 @@
|
||||||
# The Erg compiler (codename: Centimetre)
|
# The Erg compiler (codename: Centimetre)
|
||||||
|
|
||||||
The overall structure is described in detail in [architecture.md(English)](../../doc/EN/compiler/architecture.md).For other language translations of architecture.md, please check them out by yourself.
|
The overall structure is described in detail in [architecture.md(English)](../../doc/EN/compiler/architecture.md).For other language translations of architecture.md, please check them out by yourself.
|
||||||
|
|
||||||
|
## Use `erg_compiler` as a Python library
|
||||||
|
|
||||||
|
`erg_compiler` can be built as a Python library by using pyo3/maturin.
|
||||||
|
|
||||||
|
### Example
|
||||||
|
|
||||||
|
```python
|
||||||
|
import erg_compiler
|
||||||
|
|
||||||
|
module = erg_compiler.exec_module(".i = 1")
|
||||||
|
# foo.er:
|
||||||
|
# .bar = 1
|
||||||
|
foo = erg_compiler.__import__("foo")
|
||||||
|
assert module.i == 1
|
||||||
|
assert foo.bar == 1
|
||||||
|
```
|
||||||
|
|
||||||
|
### Debug install (using venv)
|
||||||
|
|
||||||
|
```python
|
||||||
|
python -m venv .venv
|
||||||
|
source .venv/bin/activate
|
||||||
|
maturin develop --features pylib_compiler
|
||||||
|
```
|
||||||
|
|
||||||
|
### Release install
|
||||||
|
|
||||||
|
```python
|
||||||
|
maturin build -i python --release --features pylib_compiler
|
||||||
|
pip install <output wheel>
|
||||||
|
```
|
||||||
|
|
|
@ -175,6 +175,23 @@ pub struct CompileError {
|
||||||
|
|
||||||
impl_display_and_error!(CompileError);
|
impl_display_and_error!(CompileError);
|
||||||
|
|
||||||
|
impl From<std::io::Error> for CompileError {
|
||||||
|
fn from(value: std::io::Error) -> Self {
|
||||||
|
Self {
|
||||||
|
core: Box::new(ErrorCore::new(
|
||||||
|
vec![SubMessage::only_loc(Location::Unknown)],
|
||||||
|
value.to_string(),
|
||||||
|
0,
|
||||||
|
IoError,
|
||||||
|
Location::Unknown,
|
||||||
|
)),
|
||||||
|
input: Input::str("".into()),
|
||||||
|
caused_by: "".to_owned(),
|
||||||
|
theme: THEME,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<ParserRunnerError> for CompileError {
|
impl From<ParserRunnerError> for CompileError {
|
||||||
fn from(err: ParserRunnerError) -> Self {
|
fn from(err: ParserRunnerError) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
@ -201,6 +218,13 @@ impl From<CompileError> for ParserRunnerError {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "pylib")]
|
||||||
|
impl std::convert::From<CompileError> for pyo3::PyErr {
|
||||||
|
fn from(err: CompileError) -> pyo3::PyErr {
|
||||||
|
pyo3::exceptions::PyOSError::new_err(err.to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl ErrorDisplay for CompileError {
|
impl ErrorDisplay for CompileError {
|
||||||
fn core(&self) -> &ErrorCore {
|
fn core(&self) -> &ErrorCore {
|
||||||
&self.core
|
&self.core
|
||||||
|
@ -521,6 +545,12 @@ impl std::error::Error for CompileErrors {}
|
||||||
|
|
||||||
impl_stream!(CompileErrors, CompileError);
|
impl_stream!(CompileErrors, CompileError);
|
||||||
|
|
||||||
|
impl From<std::io::Error> for CompileErrors {
|
||||||
|
fn from(value: std::io::Error) -> Self {
|
||||||
|
Self::from(vec![value.into()])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<ParserRunnerErrors> for CompileErrors {
|
impl From<ParserRunnerErrors> for CompileErrors {
|
||||||
fn from(err: ParserRunnerErrors) -> Self {
|
fn from(err: ParserRunnerErrors) -> Self {
|
||||||
Self(err.into_iter().map(CompileError::from).collect())
|
Self(err.into_iter().map(CompileError::from).collect())
|
||||||
|
@ -557,6 +587,13 @@ impl From<CompileErrors> for ParseErrors {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "pylib")]
|
||||||
|
impl std::convert::From<CompileErrors> for pyo3::PyErr {
|
||||||
|
fn from(errs: CompileErrors) -> pyo3::PyErr {
|
||||||
|
pyo3::exceptions::PyOSError::new_err(errs[0].to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl MultiErrorDisplay<CompileError> for CompileErrors {}
|
impl MultiErrorDisplay<CompileError> for CompileErrors {}
|
||||||
|
|
||||||
impl fmt::Display for CompileErrors {
|
impl fmt::Display for CompileErrors {
|
||||||
|
|
|
@ -30,3 +30,67 @@ pub mod varinfo;
|
||||||
pub use build_hir::{GenericHIRBuilder, HIRBuilder};
|
pub use build_hir::{GenericHIRBuilder, HIRBuilder};
|
||||||
pub use erg_parser::build_ast::ASTBuilder;
|
pub use erg_parser::build_ast::ASTBuilder;
|
||||||
pub use transpile::Transpiler;
|
pub use transpile::Transpiler;
|
||||||
|
|
||||||
|
#[cfg(feature = "pylib")]
|
||||||
|
use pyo3::prelude::*;
|
||||||
|
|
||||||
|
#[cfg(feature = "pylib")]
|
||||||
|
#[pyfunction]
|
||||||
|
#[pyo3(name = "compile")]
|
||||||
|
fn _compile(py: Python<'_>, code: String) -> Result<PyObject, error::CompileErrors> {
|
||||||
|
use erg_common::config::ErgConfig;
|
||||||
|
use pyo3::types::{IntoPyDict, PyBytes};
|
||||||
|
let cfg = ErgConfig::string(code);
|
||||||
|
let mut compiler = Compiler::new(cfg);
|
||||||
|
let code = compiler
|
||||||
|
.compile_module()
|
||||||
|
.map(|art| art.object)
|
||||||
|
.map_err(|iart| iart.errors)?;
|
||||||
|
let bytes = code.into_bytes(py.version().parse().unwrap());
|
||||||
|
let dict = [("bytes", PyBytes::new(py, &bytes))].into_py_dict(py);
|
||||||
|
py.run("import marshal", None, None).unwrap();
|
||||||
|
Ok(py
|
||||||
|
.eval("marshal.loads(bytes)", None, Some(dict))
|
||||||
|
.unwrap()
|
||||||
|
.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "pylib")]
|
||||||
|
#[pyfunction]
|
||||||
|
#[pyo3(name = "compile_file")]
|
||||||
|
fn _compile_file(py: Python<'_>, path: String) -> Result<PyObject, error::CompileErrors> {
|
||||||
|
let code = std::fs::read_to_string(path)?;
|
||||||
|
_compile(py, code)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "pylib")]
|
||||||
|
#[pyfunction]
|
||||||
|
#[pyo3(name = "exec_module")]
|
||||||
|
fn _exec_module(py: Python<'_>, code: String) -> Result<PyObject, error::CompileErrors> {
|
||||||
|
use pyo3::types::IntoPyDict;
|
||||||
|
|
||||||
|
let code = _compile(py, code)?;
|
||||||
|
let module = pyo3::types::PyModule::new(py, "<erg>").unwrap();
|
||||||
|
let dic = [("code", code), ("dict", PyObject::from(module.dict()))].into_py_dict(py);
|
||||||
|
py.run("exec(code, dict)", None, Some(dic)).unwrap();
|
||||||
|
Ok(module.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "pylib")]
|
||||||
|
#[pyfunction]
|
||||||
|
#[pyo3(name = "__import__")]
|
||||||
|
fn _import(py: Python<'_>, name: String) -> Result<PyObject, error::CompileErrors> {
|
||||||
|
let path = format!("{name}.er");
|
||||||
|
let code = std::fs::read_to_string(path)?;
|
||||||
|
_exec_module(py, code)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "pylib")]
|
||||||
|
#[pymodule]
|
||||||
|
fn erg_compiler(_py: Python<'_>, m: &PyModule) -> PyResult<()> {
|
||||||
|
m.add_function(wrap_pyfunction!(_compile, m)?)?;
|
||||||
|
m.add_function(wrap_pyfunction!(_compile_file, m)?)?;
|
||||||
|
m.add_function(wrap_pyfunction!(_exec_module, m)?)?;
|
||||||
|
m.add_function(wrap_pyfunction!(_import, m)?)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
|
@ -37,7 +37,7 @@ impl HIROptimizer {
|
||||||
fn eliminate_unused_def(&mut self, expr: &mut Expr) {
|
fn eliminate_unused_def(&mut self, expr: &mut Expr) {
|
||||||
match expr {
|
match expr {
|
||||||
Expr::Def(def) => {
|
Expr::Def(def) => {
|
||||||
if def.sig.ident().is_discarded() {
|
if def.sig.ident().is_discarded() || def.sig.vis().is_public() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if self
|
if self
|
||||||
|
|
|
@ -19,6 +19,7 @@ pretty = ["erg_common/pretty"]
|
||||||
large_thread = ["erg_common/large_thread"]
|
large_thread = ["erg_common/large_thread"]
|
||||||
experimental = ["erg_common/experimental"]
|
experimental = ["erg_common/experimental"]
|
||||||
pylib = ["dep:pyo3", "erg_common/pylib"]
|
pylib = ["dep:pyo3", "erg_common/pylib"]
|
||||||
|
pylib_parser = ["pylib"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
erg_common = { workspace = true }
|
erg_common = { workspace = true }
|
||||||
|
|
|
@ -15,8 +15,17 @@ for chunk in module:
|
||||||
assert chunk.sig.inspect() == "x"
|
assert chunk.sig.inspect() == "x"
|
||||||
```
|
```
|
||||||
|
|
||||||
### Debug install
|
### Debug install (using venv)
|
||||||
|
|
||||||
```python
|
```python
|
||||||
maturin develop --features pylib
|
python -m venv .venv
|
||||||
|
source .venv/bin/activate
|
||||||
|
maturin develop --features pylib_parser
|
||||||
|
```
|
||||||
|
|
||||||
|
### Release install
|
||||||
|
|
||||||
|
```python
|
||||||
|
maturin build -i python --release --features pylib_parser
|
||||||
|
pip install <output wheel>
|
||||||
```
|
```
|
||||||
|
|
|
@ -30,7 +30,7 @@ fn _parse(code: String) -> Result<ast::Module, error::ParseErrors> {
|
||||||
.map_err(|iart| iart.errors)
|
.map_err(|iart| iart.errors)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "pylib")]
|
#[cfg(feature = "pylib_parser")]
|
||||||
#[pymodule]
|
#[pymodule]
|
||||||
fn erg_parser(py: Python<'_>, m: &PyModule) -> PyResult<()> {
|
fn erg_parser(py: Python<'_>, m: &PyModule) -> PyResult<()> {
|
||||||
m.add_function(wrap_pyfunction!(_parse, m)?)?;
|
m.add_function(wrap_pyfunction!(_parse, m)?)?;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue