erg_compiler/
lib.rs

1//! defines the compiler for Erg (ergc).
2#![allow(clippy::large_enum_variant)]
3#![allow(clippy::result_large_err)]
4extern crate erg_common;
5pub extern crate erg_parser;
6
7pub mod artifact;
8pub mod build_hir;
9mod compile;
10pub use compile::*;
11pub mod build_package;
12mod codegen;
13pub mod context;
14pub mod declare;
15pub mod desugar_hir;
16pub mod effectcheck;
17pub mod error;
18pub mod hir;
19pub mod link_ast;
20pub mod link_hir;
21pub mod lint;
22pub mod lower;
23pub mod module;
24pub mod optimize;
25pub mod ownercheck;
26pub mod transpile;
27pub mod ty;
28pub mod varinfo;
29
30#[allow(unused)]
31use erg_common::config::{ErgConfig, Package};
32#[allow(unused)]
33use erg_common::io::Input;
34#[allow(unused)]
35use erg_common::traits::Runnable;
36
37pub use build_hir::{GenericHIRBuilder, HIRBuilder};
38pub use erg_parser::build_ast::ASTBuilder;
39pub use transpile::Transpiler;
40
41#[cfg(feature = "pylib")]
42use pyo3::prelude::*;
43#[cfg(feature = "pylib")]
44use pyo3::types::{IntoPyDict, PyBytes};
45
46#[cfg(feature = "pylib")]
47#[pyclass(unsendable)]
48#[pyo3(name = "Compiler")]
49#[derive(Debug)]
50struct _Compiler {
51    compiler: compile::Compiler,
52}
53
54#[cfg(feature = "pylib")]
55#[pymethods]
56impl _Compiler {
57    #[new]
58    fn new(deps: Vec<Package>, path: Option<String>) -> Self {
59        let input = path.map_or(Input::repl(), |path| Input::file(path.into()));
60        let cfg = ErgConfig {
61            packages: erg_common::ArcArray::from(deps),
62            input,
63            ..ErgConfig::default()
64        };
65        Self {
66            compiler: compile::Compiler::new(cfg),
67        }
68    }
69
70    #[pyo3(name = "clear")]
71    fn _clear(&mut self) {
72        self.compiler.clear();
73    }
74
75    /// compile(code: str, mode: str) -> code
76    /// --
77    ///
78    /// compile an Erg code as a module at runtime
79    #[pyo3(name = "compile")]
80    fn _compile(
81        &mut self,
82        py: Python<'_>,
83        code: String,
84        mode: &str,
85    ) -> Result<PyObject, error::CompileErrors> {
86        self.compiler.set_input(Input::str(code));
87        let src = self.compiler.cfg_mut().input.read();
88        let code = self
89            .compiler
90            .compile(src, mode)
91            .map(|art| art.object)
92            .map_err(|iart| iart.errors)?;
93        let bytes = code.into_bytes(py.version().parse().unwrap());
94        let dict = [("bytes", PyBytes::new_bound(py, &bytes))].into_py_dict_bound(py);
95        py.run_bound("import marshal", None, None).unwrap();
96        let code = py
97            .eval_bound("marshal.loads(bytes)", None, Some(&dict))
98            .unwrap();
99        Ok(code.into())
100    }
101
102    /// compile_file(path: str) -> code
103    /// --
104    ///
105    /// compile an Erg file as a module at runtime
106    #[pyo3(name = "compile_file")]
107    fn _compile_file(
108        &mut self,
109        py: Python<'_>,
110        path: String,
111    ) -> Result<PyObject, error::CompileErrors> {
112        let code =
113            std::fs::read_to_string(&path).unwrap_or_else(|err| panic!("{err}, path: {path}"));
114        self._compile(py, code, "exec")
115    }
116
117    /// compile_ast(ast: erg_parser.AST, mode: str) -> code
118    /// --
119    ///
120    /// compile an Erg AST as a module at runtime with dependencies
121    #[pyo3(name = "compile_ast")]
122    fn _compile_ast(
123        &mut self,
124        py: Python<'_>,
125        ast: erg_parser::ast::AST,
126        mode: &str,
127    ) -> Result<PyObject, error::CompileErrors> {
128        let code = self
129            .compiler
130            .compile_ast(ast, mode)
131            .map(|art| art.object)
132            .map_err(|iart| iart.errors)?;
133        let bytes = code.into_bytes(py.version().parse().unwrap());
134        let dict = [("bytes", PyBytes::new_bound(py, &bytes))].into_py_dict_bound(py);
135        py.run_bound("import marshal", None, None).unwrap();
136        Ok(py
137            .eval_bound("marshal.loads(bytes)", None, Some(&dict))
138            .unwrap()
139            .into())
140    }
141}
142
143/// compile_with_dependencies(code: str, mode: str, pkgs: list[Package]) -> code
144/// --
145///
146/// compile an Erg code as a module at runtime with dependencies
147#[cfg(feature = "pylib")]
148#[pyfunction]
149#[pyo3(name = "compile_with_dependencies")]
150fn _compile_with_dependencies(
151    py: Python<'_>,
152    code: String,
153    mode: &str,
154    pkgs: Vec<Package>,
155    path: Option<String>,
156) -> Result<PyObject, error::CompileErrors> {
157    let mut compiler = _Compiler::new(pkgs, path);
158    compiler._compile(py, code, mode)
159}
160
161/// compile(code: str, mode: str) -> code
162/// --
163///
164/// compile an Erg code as a module at runtime
165#[cfg(feature = "pylib")]
166#[pyfunction]
167#[pyo3(name = "compile")]
168fn _compile(
169    py: Python<'_>,
170    code: String,
171    mode: &str,
172    path: Option<String>,
173) -> Result<PyObject, error::CompileErrors> {
174    _compile_with_dependencies(py, code, mode, vec![], path)
175}
176
177/// compile_ast_with_dependencies(ast: erg_parser.AST, mode: str, pkgs: list[Package]) -> code
178/// --
179///
180/// compile an Erg AST as a module at runtime with dependencies
181#[cfg(feature = "pylib")]
182#[pyfunction]
183#[pyo3(name = "compile_ast_with_dependencies")]
184fn _compile_ast_with_dependencies(
185    py: Python<'_>,
186    ast: erg_parser::ast::AST,
187    mode: &str,
188    pkgs: Vec<Package>,
189    path: Option<String>,
190) -> Result<PyObject, error::CompileErrors> {
191    let mut compiler = _Compiler::new(pkgs, path);
192    compiler._compile_ast(py, ast, mode)
193}
194
195/// compile_ast(ast: erg_parser.AST, mode: str) -> code
196/// --
197///
198/// compile an Erg AST as a module at runtime
199#[cfg(feature = "pylib")]
200#[pyfunction]
201#[pyo3(name = "compile_ast")]
202fn _compile_ast(
203    py: Python<'_>,
204    ast: erg_parser::ast::AST,
205    mode: &str,
206    path: Option<String>,
207) -> Result<PyObject, error::CompileErrors> {
208    _compile_ast_with_dependencies(py, ast, mode, vec![], path)
209}
210
211/// compile_file_with_dependencies(path: str, pkgs: list[Package]) -> code
212/// --
213///
214/// compile an Erg file as a module at runtime with dependencies
215#[cfg(feature = "pylib")]
216#[pyfunction]
217#[pyo3(name = "compile_file_with_dependencies")]
218fn _compile_file_with_dependencies(
219    py: Python<'_>,
220    path: String,
221    pkgs: Vec<Package>,
222) -> Result<PyObject, error::CompileErrors> {
223    let code = std::fs::read_to_string(&path).unwrap_or_else(|err| panic!("{err}, path: {path}"));
224    _compile_with_dependencies(py, code, "exec", pkgs, Some(path))
225}
226
227/// compile_file(path: str) -> code
228/// --
229///
230/// compile an Erg file as a module at runtime
231#[cfg(feature = "pylib")]
232#[pyfunction]
233#[pyo3(name = "compile_file")]
234fn _compile_file(py: Python<'_>, path: String) -> Result<PyObject, error::CompileErrors> {
235    _compile_file_with_dependencies(py, path, vec![])
236}
237
238/// exec_with_dependencies(code: str, pkgs: list[Package]) -> module
239/// --
240///
241/// compile and execute an Erg code as a module at runtime with dependencies
242///
243#[cfg(feature = "pylib")]
244#[pyfunction]
245#[pyo3(name = "exec_with_dependencies")]
246fn _exec_with_dependencies(
247    py: Python<'_>,
248    code: String,
249    pkgs: Vec<Package>,
250    path: Option<String>,
251) -> Result<PyObject, error::CompileErrors> {
252    let code = _compile_with_dependencies(py, code, "exec", pkgs, path)?;
253    let module = pyo3::types::PyModule::new_bound(py, "<erg>").unwrap();
254    let dic = [("code", code), ("dict", PyObject::from(module.dict()))].into_py_dict_bound(py);
255    py.run_bound("exec(code, dict)", None, Some(&dic)).unwrap();
256    Ok(module.into())
257}
258
259/// exec(code: str) -> module
260/// --
261///
262/// compile and execute an Erg code as a module at runtime
263#[cfg(feature = "pylib")]
264#[pyfunction]
265#[pyo3(name = "exec")]
266fn _exec(
267    py: Python<'_>,
268    code: String,
269    path: Option<String>,
270) -> Result<PyObject, error::CompileErrors> {
271    _exec_with_dependencies(py, code, vec![], path)
272}
273
274/// exec_with_dependencies(code: str, pkgs: list[Package]) -> module
275/// --
276///
277/// compile and execute an Erg code as a module at runtime
278#[cfg(feature = "pylib")]
279#[pyfunction]
280#[pyo3(name = "exec_file_with_dependencies")]
281fn _exec_file_with_dependencies(
282    py: Python<'_>,
283    path: String,
284    pkgs: Vec<Package>,
285) -> Result<PyObject, error::CompileErrors> {
286    let code = std::fs::read_to_string(&path).unwrap_or_else(|err| panic!("{err}, path: {path}"));
287    _exec_with_dependencies(py, code, pkgs, Some(path))
288}
289
290/// exec_file(path: str) -> module
291/// --
292///
293/// compile and execute an Erg file as a module at runtime
294#[cfg(feature = "pylib")]
295#[pyfunction]
296#[pyo3(name = "exec_file")]
297fn _exec_file(py: Python<'_>, path: String) -> Result<PyObject, error::CompileErrors> {
298    _exec_file_with_dependencies(py, path, vec![])
299}
300
301/// exec_ast_with_dependencies(ast: erg_parser.AST, pkgs: list[Package]) -> module
302/// --
303///
304/// compile and execute an Erg AST as a module at runtime with dependencies
305#[cfg(feature = "pylib")]
306#[pyfunction]
307#[pyo3(name = "exec_ast_with_dependencies")]
308fn _exec_ast_with_dependencies(
309    py: Python<'_>,
310    ast: erg_parser::ast::AST,
311    pkgs: Vec<Package>,
312    path: Option<String>,
313) -> Result<PyObject, error::CompileErrors> {
314    let code = _compile_ast_with_dependencies(py, ast, "exec", pkgs, path)?;
315    let module = pyo3::types::PyModule::new_bound(py, "<erg>").unwrap();
316    let dic = [("code", code), ("dict", PyObject::from(module.dict()))].into_py_dict_bound(py);
317    py.run_bound("exec(code, dict)", None, Some(&dic)).unwrap();
318    Ok(module.into())
319}
320
321/// exec_ast(ast: erg_parser.AST) -> module
322/// --
323///
324/// compile and execute an Erg AST as a module at runtime
325#[cfg(feature = "pylib")]
326#[pyfunction]
327#[pyo3(name = "exec_ast")]
328fn _exec_ast(
329    py: Python<'_>,
330    ast: erg_parser::ast::AST,
331    path: Option<String>,
332) -> Result<PyObject, error::CompileErrors> {
333    _exec_ast_with_dependencies(py, ast, vec![], path)
334}
335
336/// __import__(name: str) -> module
337/// --
338///
339/// import an Erg module at runtime
340#[cfg(feature = "pylib")]
341#[pyfunction]
342#[pyo3(name = "__import__")]
343fn _import(py: Python<'_>, name: String) -> Result<PyObject, error::CompileErrors> {
344    let path = format!("{name}.er");
345    let code = std::fs::read_to_string(&path).unwrap_or_else(|err| panic!("{err}, path: {path}"));
346    _exec(py, code, Some(path))
347}
348
349#[cfg(feature = "pylib")]
350#[pymodule]
351fn erg_compiler(py: Python<'_>, m: &Bound<PyModule>) -> PyResult<()> {
352    m.add_class::<Package>()?;
353    m.add_class::<_Compiler>()?;
354    m.add_function(wrap_pyfunction!(_compile, m)?)?;
355    m.add_function(wrap_pyfunction!(_compile_with_dependencies, m)?)?;
356    m.add_function(wrap_pyfunction!(_compile_ast, m)?)?;
357    m.add_function(wrap_pyfunction!(_compile_ast_with_dependencies, m)?)?;
358    m.add_function(wrap_pyfunction!(_compile_file, m)?)?;
359    m.add_function(wrap_pyfunction!(_compile_file_with_dependencies, m)?)?;
360    m.add_function(wrap_pyfunction!(_exec, m)?)?;
361    m.add_function(wrap_pyfunction!(_exec_with_dependencies, m)?)?;
362    m.add_function(wrap_pyfunction!(_exec_ast, m)?)?;
363    m.add_function(wrap_pyfunction!(_exec_ast_with_dependencies, m)?)?;
364    m.add_function(wrap_pyfunction!(_exec_file, m)?)?;
365    m.add_function(wrap_pyfunction!(_exec_file_with_dependencies, m)?)?;
366    m.add_function(wrap_pyfunction!(_import, m)?)?;
367
368    use crate::erg_parser::erg_parser;
369    let parser = PyModule::new_bound(py, "erg_parser")?;
370    erg_parser(py, &parser)?;
371    m.add_submodule(&parser)?;
372
373    py.run_bound(
374        "\
375import sys
376sys.modules['erg_compiler.erg_parser'] = erg_parser
377sys.modules['erg_compiler.erg_parser.ast'] = erg_parser.ast
378sys.modules['erg_compiler.erg_parser.expr'] = erg_parser.expr
379",
380        None,
381        Some(&m.dict()),
382    )?;
383
384    Ok(())
385}