mirror of
https://github.com/erg-lang/erg.git
synced 2025-09-29 12:24:45 +00:00
85 lines
3.7 KiB
Rust
85 lines
3.7 KiB
Rust
use erg_common::config::ErgConfig;
|
|
use erg_common::traits::{Locational, Stream};
|
|
use erg_common::Str;
|
|
use erg_common::{enum_unwrap, log};
|
|
|
|
use erg_parser::ast::DefId;
|
|
use erg_parser::token::Token;
|
|
|
|
use erg_type::Type;
|
|
|
|
use crate::hir::{Accessor, Args, Block, Call, Def, DefBody, Expr, Identifier, PosArg, HIR};
|
|
use crate::mod_cache::SharedModuleCache;
|
|
|
|
pub struct Linker {}
|
|
|
|
impl Linker {
|
|
pub fn link(cfg: ErgConfig, mut main: HIR, mod_cache: SharedModuleCache) -> HIR {
|
|
log!(info "the linking process has started.");
|
|
for chunk in main.module.iter_mut() {
|
|
match chunk {
|
|
// x = import "mod"
|
|
// ↓
|
|
// x = ModuleType("mod")
|
|
// exec(code, x.__dict__) # `code` is the mod's content
|
|
Expr::Def(ref def) if def.def_kind().is_module() => {
|
|
// In the case of REPL, entries cannot be used up
|
|
let hir = if cfg.input.is_repl() {
|
|
mod_cache
|
|
.get(&def.sig.ident().inspect()[..])
|
|
.and_then(|entry| entry.hir.clone())
|
|
} else {
|
|
mod_cache
|
|
.remove(&def.sig.ident().inspect()[..])
|
|
.and_then(|entry| entry.hir)
|
|
};
|
|
let mod_name = enum_unwrap!(def.body.block.first().unwrap(), Expr::Call)
|
|
.args
|
|
.get_left_or_key("path")
|
|
.unwrap();
|
|
// let sig = option_enum_unwrap!(&def.sig, Signature::Var)
|
|
// .unwrap_or_else(|| todo!("module subroutines are not allowed"));
|
|
if let Some(hir) = hir {
|
|
let code = Expr::Code(Block::new(Vec::from(hir.module)));
|
|
let module_type = Expr::Accessor(Accessor::private_with_line(
|
|
Str::ever("#ModuleType"),
|
|
def.ln_begin().unwrap(),
|
|
));
|
|
let args =
|
|
Args::new(vec![PosArg::new(mod_name.clone())], None, vec![], None);
|
|
let block = Block::new(vec![Expr::Call(Call::new(
|
|
module_type,
|
|
None,
|
|
args,
|
|
Type::Uninited,
|
|
))]);
|
|
let mod_def = Expr::Def(Def::new(
|
|
def.sig.clone(),
|
|
DefBody::new(Token::dummy(), block, DefId(0)),
|
|
));
|
|
let exec = Expr::Accessor(Accessor::public_with_line(
|
|
Str::ever("exec"),
|
|
mod_def.ln_begin().unwrap(),
|
|
));
|
|
let module = Expr::Accessor(Accessor::Ident(def.sig.ident().clone()));
|
|
let __dict__ = Identifier::public("__dict__");
|
|
let m_dict =
|
|
Expr::Accessor(Accessor::attr(module, __dict__, Type::Uninited));
|
|
let args = Args::new(
|
|
vec![PosArg::new(code), PosArg::new(m_dict)],
|
|
None,
|
|
vec![],
|
|
None,
|
|
);
|
|
let exec_code = Expr::Call(Call::new(exec, None, args, Type::Uninited));
|
|
let compound = Block::new(vec![mod_def, exec_code]);
|
|
*chunk = Expr::Compound(compound);
|
|
}
|
|
}
|
|
_ => {}
|
|
}
|
|
}
|
|
log!(info "linked: {main}");
|
|
main
|
|
}
|
|
}
|