1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
//! defines the compiler for Erg (ergc).
#![allow(clippy::large_enum_variant)]
#![allow(clippy::result_large_err)]
extern crate erg_common;
pub extern crate erg_parser;

pub mod artifact;
pub mod build_hir;
mod compile;
pub use compile::*;
pub mod build_package;
mod codegen;
pub mod context;
pub mod declare;
pub mod desugar_hir;
pub mod effectcheck;
pub mod error;
pub mod hir;
pub mod link_ast;
pub mod link_hir;
pub mod lint;
pub mod lower;
pub mod module;
pub mod optimize;
pub mod ownercheck;
pub mod transpile;
pub mod ty;
pub mod varinfo;

pub use build_hir::{GenericHIRBuilder, HIRBuilder};
pub use erg_parser::build_ast::ASTBuilder;
pub use transpile::Transpiler;

#[cfg(feature = "pylib")]
use pyo3::prelude::*;
#[cfg(feature = "pylib")]
use pyo3::types::{IntoPyDict, PyBytes};

/// compile(code: str, mode: str) -> 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<PyObject, error::CompileErrors> {
    use erg_common::{config::ErgConfig, traits::Runnable};
    let cfg = ErgConfig::string(code);
    let mut compiler = Compiler::new(cfg);
    let src = compiler.cfg_mut().input.read();
    let code = compiler
        .compile(src, mode)
        .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();
    let code = py.eval("marshal.loads(bytes)", None, Some(dict)).unwrap();
    Ok(code.into())
}

/// compile_ast(ast: erg_parser.AST, mode: str) -> code
/// --
///
/// compile an Erg AST as a module at runtime
#[cfg(feature = "pylib")]
#[pyfunction]
#[pyo3(name = "compile_ast")]
fn _compile_ast(
    py: Python<'_>,
    ast: erg_parser::ast::AST,
    mode: &str,
) -> Result<PyObject, error::CompileErrors> {
    use erg_common::config::ErgConfig;
    let cfg = ErgConfig::default();
    let mut compiler = Compiler::new(cfg);
    let code = compiler
        .compile_ast(ast, mode)
        .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())
}

/// compile_file(path: str) -> code
/// --
///
/// compile an Erg file as a module at runtime
#[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).unwrap_or_else(|err| panic!("{err}, path: {path}"));
    _compile(py, code, "exec")
}

/// exec(code: str) -> module
/// --
///
/// compile and execute an Erg code as a module at runtime
#[cfg(feature = "pylib")]
#[pyfunction]
#[pyo3(name = "exec")]
fn _exec(py: Python<'_>, code: String) -> Result<PyObject, error::CompileErrors> {
    let code = _compile(py, code, "exec")?;
    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())
}

/// exec_ast(ast: erg_parser.AST) -> module
/// --
///
/// compile and execute an Erg AST as a module at runtime
#[cfg(feature = "pylib")]
#[pyfunction]
#[pyo3(name = "exec_ast")]
fn _exec_ast(py: Python<'_>, ast: erg_parser::ast::AST) -> Result<PyObject, error::CompileErrors> {
    let code = _compile_ast(py, ast, "exec")?;
    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())
}

/// __import__(name: str) -> module
/// --
///
/// import an Erg module at runtime
#[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).unwrap_or_else(|err| panic!("{err}, path: {path}"));
    _exec(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_ast, m)?)?;
    m.add_function(wrap_pyfunction!(_compile_file, m)?)?;
    m.add_function(wrap_pyfunction!(_exec, m)?)?;
    m.add_function(wrap_pyfunction!(_exec_ast, m)?)?;
    m.add_function(wrap_pyfunction!(_import, m)?)?;

    use crate::erg_parser::erg_parser;
    let parser = PyModule::new(py, "erg_parser")?;
    erg_parser(py, parser)?;
    m.add_submodule(parser)?;

    py.run(
        "\
import sys
sys.modules['erg_compiler.erg_parser'] = erg_parser
sys.modules['erg_compiler.erg_parser.ast'] = erg_parser.ast
sys.modules['erg_compiler.erg_parser.expr'] = erg_parser.expr
",
        None,
        Some(m.dict()),
    )?;

    Ok(())
}