mirror of
https://github.com/erg-lang/erg.git
synced 2025-09-29 20:34:44 +00:00
Add builder & linker
This commit is contained in:
parent
671fbee518
commit
201b313cd2
19 changed files with 241 additions and 109 deletions
57
compiler/erg_compiler/builder.rs
Normal file
57
compiler/erg_compiler/builder.rs
Normal file
|
@ -0,0 +1,57 @@
|
|||
use erg_common::config::{ErgConfig, Input};
|
||||
use erg_common::traits::Stream;
|
||||
|
||||
use erg_parser::ast::VarName;
|
||||
use erg_parser::builder::ASTBuilder;
|
||||
|
||||
use crate::error::{CompileError, CompileErrors, TyCheckErrors};
|
||||
// use crate::hir::HIR;
|
||||
use crate::check::Checker;
|
||||
use crate::mod_cache::SharedModuleCache;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct HIRBuilder {
|
||||
checker: Checker,
|
||||
mod_cache: SharedModuleCache,
|
||||
}
|
||||
|
||||
impl HIRBuilder {
|
||||
fn convert(&self, errs: TyCheckErrors) -> CompileErrors {
|
||||
errs.into_iter()
|
||||
.map(|e| CompileError::new(e.core, self.checker.cfg.input.clone(), e.caused_by))
|
||||
.collect::<Vec<_>>()
|
||||
.into()
|
||||
}
|
||||
|
||||
pub fn new(cfg: ErgConfig, mod_cache: SharedModuleCache) -> Self {
|
||||
Self {
|
||||
checker: Checker::new(cfg, mod_cache.clone()),
|
||||
mod_cache,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn build_and_cache(&mut self, var_name: VarName) -> Result<(), CompileErrors> {
|
||||
let mut ast_builder = ASTBuilder::new(self.checker.cfg.copy());
|
||||
let ast = ast_builder.build()?;
|
||||
let (hir, ctx) = self
|
||||
.checker
|
||||
.check(ast, "exec")
|
||||
.map_err(|errs| self.convert(errs))?;
|
||||
self.mod_cache.register(var_name, Some(hir), ctx);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn build_and_cache_main(&mut self, src: String, mode: &str) -> Result<(), CompileErrors> {
|
||||
let mut cfg = self.checker.cfg.copy();
|
||||
cfg.input = Input::Str(src);
|
||||
let mut ast_builder = ASTBuilder::new(cfg);
|
||||
let ast = ast_builder.build()?;
|
||||
let (hir, ctx) = self
|
||||
.checker
|
||||
.check(ast, mode)
|
||||
.map_err(|errs| self.convert(errs))?;
|
||||
let name = VarName::from_static("<module>");
|
||||
self.mod_cache.register(name, Some(hir), ctx);
|
||||
Ok(())
|
||||
}
|
||||
}
|
|
@ -5,36 +5,61 @@ use erg_common::traits::Runnable;
|
|||
use erg_parser::ast::AST;
|
||||
use erg_parser::builder::ASTBuilder;
|
||||
|
||||
use crate::context::Context;
|
||||
use crate::effectcheck::SideEffectChecker;
|
||||
use crate::error::{TyCheckError, TyCheckErrors};
|
||||
use crate::hir::HIR;
|
||||
use crate::lower::ASTLowerer;
|
||||
use crate::mod_cache::SharedModuleCache;
|
||||
use crate::ownercheck::OwnershipChecker;
|
||||
|
||||
/// Summarize lowering, side-effect checking, and ownership checking
|
||||
#[derive(Debug)]
|
||||
pub struct Checker {
|
||||
cfg: ErgConfig,
|
||||
pub cfg: ErgConfig,
|
||||
lowerer: ASTLowerer,
|
||||
ownership_checker: OwnershipChecker,
|
||||
}
|
||||
|
||||
impl Runnable for Checker {
|
||||
impl Checker {
|
||||
pub fn new(cfg: ErgConfig, mod_cache: SharedModuleCache) -> Self {
|
||||
Self {
|
||||
cfg,
|
||||
lowerer: ASTLowerer::new(mod_cache),
|
||||
ownership_checker: OwnershipChecker::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check(&mut self, ast: AST, mode: &str) -> Result<(HIR, Context), TyCheckErrors> {
|
||||
let (hir, ctx, warns) = self.lowerer.lower(ast, mode)?;
|
||||
if self.cfg.verbose >= 2 {
|
||||
warns.fmt_all_stderr();
|
||||
}
|
||||
let effect_checker = SideEffectChecker::new();
|
||||
let hir = effect_checker.check(hir)?;
|
||||
let hir = self.ownership_checker.check(hir)?;
|
||||
Ok((hir, ctx))
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CheckerRunner {
|
||||
checker: Checker,
|
||||
}
|
||||
|
||||
impl Runnable for CheckerRunner {
|
||||
type Err = TyCheckError;
|
||||
type Errs = TyCheckErrors;
|
||||
const NAME: &'static str = "Erg type-checker";
|
||||
|
||||
fn new(cfg: ErgConfig) -> Self {
|
||||
Self {
|
||||
ownership_checker: OwnershipChecker::new(),
|
||||
lowerer: ASTLowerer::new(),
|
||||
cfg,
|
||||
checker: Checker::new(cfg, SharedModuleCache::new()),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn cfg(&self) -> &ErgConfig {
|
||||
&self.cfg
|
||||
&self.checker.cfg
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -43,30 +68,17 @@ impl Runnable for Checker {
|
|||
fn clear(&mut self) {}
|
||||
|
||||
fn exec(&mut self) -> Result<(), Self::Errs> {
|
||||
let mut builder = ASTBuilder::new(self.cfg.copy());
|
||||
let mut builder = ASTBuilder::new(self.cfg().copy());
|
||||
let ast = builder.build()?;
|
||||
let hir = self.check(ast, "exec")?;
|
||||
let (hir, _) = self.checker.check(ast, "exec")?;
|
||||
println!("{hir}");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn eval(&mut self, src: String) -> Result<String, TyCheckErrors> {
|
||||
let mut builder = ASTBuilder::new(self.cfg.copy());
|
||||
let ast = builder.build_with_input(src)?;
|
||||
let hir = self.check(ast, "eval")?;
|
||||
let mut builder = ASTBuilder::new(self.cfg().copy());
|
||||
let ast = builder.build_with_str(src)?;
|
||||
let (hir, _) = self.checker.check(ast, "eval")?;
|
||||
Ok(hir.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl Checker {
|
||||
pub fn check(&mut self, ast: AST, mode: &str) -> Result<HIR, TyCheckErrors> {
|
||||
let (hir, warns) = self.lowerer.lower(ast, mode)?;
|
||||
if self.cfg.verbose >= 2 {
|
||||
warns.fmt_all_stderr();
|
||||
}
|
||||
let effect_checker = SideEffectChecker::new();
|
||||
let hir = effect_checker.check(hir)?;
|
||||
let hir = self.ownership_checker.check(hir)?;
|
||||
Ok(hir)
|
||||
}
|
||||
}
|
|
@ -3,16 +3,16 @@
|
|||
//! コンパイラーを定義する
|
||||
use std::path::Path;
|
||||
|
||||
use erg_common::config::{ErgConfig, Input};
|
||||
use erg_common::config::ErgConfig;
|
||||
use erg_common::log;
|
||||
use erg_common::traits::{Runnable, Stream};
|
||||
use erg_type::codeobj::CodeObj;
|
||||
|
||||
use erg_parser::builder::ASTBuilder;
|
||||
|
||||
use crate::checker::Checker;
|
||||
use crate::builder::HIRBuilder;
|
||||
use crate::codegen::CodeGenerator;
|
||||
use crate::error::{CompileError, CompileErrors, TyCheckErrors};
|
||||
use crate::error::{CompileError, CompileErrors};
|
||||
use crate::link::Linker;
|
||||
use crate::mod_cache::SharedModuleCache;
|
||||
|
||||
/// * registered as global -> Global
|
||||
/// * defined in the toplevel scope (and called in the inner scope) -> Global
|
||||
|
@ -91,7 +91,7 @@ impl AccessKind {
|
|||
#[derive(Debug)]
|
||||
pub struct Compiler {
|
||||
cfg: ErgConfig,
|
||||
checker: Checker,
|
||||
mod_cache: SharedModuleCache,
|
||||
code_generator: CodeGenerator,
|
||||
}
|
||||
|
||||
|
@ -101,9 +101,10 @@ impl Runnable for Compiler {
|
|||
const NAME: &'static str = "Erg compiler";
|
||||
|
||||
fn new(cfg: ErgConfig) -> Self {
|
||||
let mod_cache = SharedModuleCache::new();
|
||||
Self {
|
||||
checker: Checker::new(cfg.copy()),
|
||||
code_generator: CodeGenerator::new(cfg.copy()),
|
||||
mod_cache,
|
||||
cfg,
|
||||
}
|
||||
}
|
||||
|
@ -133,13 +134,6 @@ impl Runnable for Compiler {
|
|||
}
|
||||
|
||||
impl Compiler {
|
||||
fn convert(&self, errs: TyCheckErrors) -> CompileErrors {
|
||||
errs.into_iter()
|
||||
.map(|e| CompileError::new(e.core, self.input().clone(), e.caused_by))
|
||||
.collect::<Vec<_>>()
|
||||
.into()
|
||||
}
|
||||
|
||||
pub fn compile_and_dump_as_pyc<P: AsRef<Path>>(
|
||||
&mut self,
|
||||
src: String,
|
||||
|
@ -154,14 +148,9 @@ impl Compiler {
|
|||
|
||||
pub fn compile(&mut self, src: String, mode: &str) -> Result<CodeObj, CompileErrors> {
|
||||
log!(info "the compiling process has started.");
|
||||
let mut cfg = self.cfg.copy();
|
||||
cfg.input = Input::Str(src);
|
||||
let mut ast_builder = ASTBuilder::new(cfg);
|
||||
let ast = ast_builder.build()?;
|
||||
let hir = self
|
||||
.checker
|
||||
.check(ast, mode)
|
||||
.map_err(|errs| self.convert(errs))?;
|
||||
let mut hir_builder = HIRBuilder::new(self.cfg.copy(), self.mod_cache.clone());
|
||||
hir_builder.build_and_cache_main(src, mode)?;
|
||||
let hir = Linker::link(self.mod_cache.clone());
|
||||
let codeobj = self.code_generator.emit(hir);
|
||||
log!(info "code object:\n{}", codeobj.code_info());
|
||||
log!(
|
||||
|
|
|
@ -1783,13 +1783,13 @@ impl Context {
|
|||
ctx
|
||||
}
|
||||
|
||||
pub fn new_main_module() -> Self {
|
||||
pub fn new_main_module(mod_cache: SharedModuleCache) -> Self {
|
||||
Context::new(
|
||||
"<module>".into(),
|
||||
ContextKind::Module,
|
||||
vec![],
|
||||
Some(Context::init_builtins()),
|
||||
Some(SharedModuleCache::new()),
|
||||
Some(mod_cache),
|
||||
Context::TOP_LEVEL,
|
||||
)
|
||||
}
|
||||
|
|
|
@ -238,6 +238,7 @@ impl From<DefKind> for ContextKind {
|
|||
DefKind::Class | DefKind::Inherit => Self::Class,
|
||||
DefKind::Trait | DefKind::Subsume => Self::Trait,
|
||||
DefKind::StructuralTrait => Self::StructuralTrait,
|
||||
DefKind::Module => Self::Module,
|
||||
DefKind::Other => Self::Instant,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
use std::option::Option; // conflicting to Type::Option
|
||||
|
||||
use erg_common::config::{ErgConfig, Input};
|
||||
use erg_common::error::MultiErrorDisplay;
|
||||
use erg_common::traits::{Locational, Stream};
|
||||
use erg_common::vis::Visibility;
|
||||
use erg_common::Str;
|
||||
|
@ -14,11 +16,12 @@ use erg_type::value::{GenTypeObj, TypeKind, TypeObj, ValueObj};
|
|||
use erg_type::{HasType, ParamTy, SubrType, TyBound, Type};
|
||||
use Type::*;
|
||||
|
||||
use crate::builder::HIRBuilder;
|
||||
use crate::context::{ClassDefType, Context, DefaultInfo, RegistrationMode, TraitInstance};
|
||||
use crate::error::readable_name;
|
||||
use crate::error::{TyCheckError, TyCheckResult};
|
||||
use crate::hir;
|
||||
use crate::mod_cache::ModuleEntry;
|
||||
use crate::mod_cache::SharedModuleCache;
|
||||
use crate::varinfo::{Mutability, ParamIdx, VarInfo, VarKind};
|
||||
use Mutability::*;
|
||||
use RegistrationMode::*;
|
||||
|
@ -763,56 +766,55 @@ impl Context {
|
|||
match mod_name {
|
||||
hir::Expr::Lit(lit) => {
|
||||
if self.subtype_of(&lit.value.class(), &Str) {
|
||||
let name = enum_unwrap!(lit.value.clone(), ValueObj::Str);
|
||||
if let Some(mod_cache) = self.mod_cache.as_mut() {
|
||||
match &name[..] {
|
||||
let __name__ = enum_unwrap!(lit.value.clone(), ValueObj::Str);
|
||||
if let Some(mod_cache) = self.mod_cache.as_ref() {
|
||||
match &__name__[..] {
|
||||
"importlib" => {
|
||||
mod_cache.register(
|
||||
var_name.clone(),
|
||||
ModuleEntry::builtin(Self::init_py_importlib_mod()),
|
||||
None,
|
||||
Self::init_py_importlib_mod(),
|
||||
);
|
||||
}
|
||||
"io" => {
|
||||
mod_cache.register(
|
||||
var_name.clone(),
|
||||
ModuleEntry::builtin(Self::init_py_io_mod()),
|
||||
);
|
||||
mod_cache.register(var_name.clone(), None, Self::init_py_io_mod());
|
||||
}
|
||||
"math" => {
|
||||
mod_cache.register(
|
||||
var_name.clone(),
|
||||
ModuleEntry::builtin(Self::init_py_math_mod()),
|
||||
None,
|
||||
Self::init_py_math_mod(),
|
||||
);
|
||||
}
|
||||
"random" => {
|
||||
mod_cache.register(
|
||||
var_name.clone(),
|
||||
ModuleEntry::builtin(Self::init_py_random_mod()),
|
||||
None,
|
||||
Self::init_py_random_mod(),
|
||||
);
|
||||
}
|
||||
"socket" => {
|
||||
mod_cache.register(
|
||||
var_name.clone(),
|
||||
ModuleEntry::builtin(Self::init_py_socket_mod()),
|
||||
None,
|
||||
Self::init_py_socket_mod(),
|
||||
);
|
||||
}
|
||||
"sys" => {
|
||||
mod_cache.register(
|
||||
var_name.clone(),
|
||||
ModuleEntry::builtin(Self::init_py_sys_mod()),
|
||||
);
|
||||
mod_cache.register(var_name.clone(), None, Self::init_py_sys_mod());
|
||||
}
|
||||
"time" => {
|
||||
mod_cache.register(
|
||||
var_name.clone(),
|
||||
ModuleEntry::builtin(Self::init_py_time_mod()),
|
||||
None,
|
||||
Self::init_py_time_mod(),
|
||||
);
|
||||
}
|
||||
other => todo!("importing {other}"),
|
||||
_ => self.import_user_module(var_name, __name__, mod_cache),
|
||||
}
|
||||
} else {
|
||||
// maybe unreachable
|
||||
todo!("importing {name} in the builtin module")
|
||||
todo!("importing {__name__} in the builtin module")
|
||||
}
|
||||
} else {
|
||||
return Err(TyCheckError::type_mismatch_error(
|
||||
|
@ -839,6 +841,17 @@ impl Context {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn import_user_module(&self, var_name: &VarName, __name__: Str, mod_cache: &SharedModuleCache) {
|
||||
let cfg = ErgConfig {
|
||||
input: Input::File(format!("{__name__}.er")),
|
||||
..ErgConfig::default()
|
||||
};
|
||||
let mut hir_builder = HIRBuilder::new(cfg, mod_cache.clone());
|
||||
if let Err(errs) = hir_builder.build_and_cache(var_name.clone()) {
|
||||
errs.fmt_all_stderr();
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn _push_subtype_bound(&mut self, sub: Type, sup: Type) {
|
||||
self.bounds.push(TyBound::subtype_of(sub, sup));
|
||||
}
|
||||
|
|
|
@ -1332,6 +1332,7 @@ impl Def {
|
|||
DefKind::Other
|
||||
}
|
||||
}
|
||||
Some("import") => DefKind::Module,
|
||||
_ => DefKind::Other,
|
||||
},
|
||||
_ => DefKind::Other,
|
||||
|
|
|
@ -3,7 +3,8 @@
|
|||
extern crate erg_common;
|
||||
pub extern crate erg_parser;
|
||||
|
||||
mod checker;
|
||||
mod builder;
|
||||
mod check;
|
||||
mod compile;
|
||||
pub use compile::*;
|
||||
mod codegen;
|
||||
|
@ -11,8 +12,10 @@ pub mod context;
|
|||
pub mod effectcheck;
|
||||
pub mod error;
|
||||
pub mod hir;
|
||||
pub mod link;
|
||||
pub mod lower;
|
||||
pub mod mod_cache;
|
||||
// pub mod name_resolve;
|
||||
pub mod optimize;
|
||||
pub mod ownercheck;
|
||||
pub mod varinfo;
|
||||
|
|
19
compiler/erg_compiler/link.rs
Normal file
19
compiler/erg_compiler/link.rs
Normal file
|
@ -0,0 +1,19 @@
|
|||
use erg_common::traits::Stream;
|
||||
|
||||
use crate::hir::{Expr, HIR};
|
||||
use crate::mod_cache::SharedModuleCache;
|
||||
|
||||
pub struct Linker {}
|
||||
|
||||
impl Linker {
|
||||
pub fn link(mod_cache: SharedModuleCache) -> HIR {
|
||||
let mut main_mod_hir = mod_cache.remove("<module>").unwrap().hir.unwrap();
|
||||
for chunk in main_mod_hir.module.iter_mut() {
|
||||
match chunk {
|
||||
Expr::Def(def) if def.def_kind().is_module() => {}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
main_mod_hir
|
||||
}
|
||||
}
|
|
@ -27,6 +27,7 @@ use crate::error::{
|
|||
};
|
||||
use crate::hir;
|
||||
use crate::hir::HIR;
|
||||
use crate::mod_cache::SharedModuleCache;
|
||||
use crate::varinfo::VarKind;
|
||||
use Visibility::*;
|
||||
|
||||
|
@ -48,7 +49,7 @@ impl Runnable for ASTLowererRunner {
|
|||
fn new(cfg: ErgConfig) -> Self {
|
||||
Self {
|
||||
cfg,
|
||||
lowerer: ASTLowerer::new(),
|
||||
lowerer: ASTLowerer::new(SharedModuleCache::new()),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -63,7 +64,7 @@ impl Runnable for ASTLowererRunner {
|
|||
fn exec(&mut self) -> Result<(), Self::Errs> {
|
||||
let mut ast_builder = ASTBuilder::new(self.cfg.copy());
|
||||
let ast = ast_builder.build()?;
|
||||
let (hir, warns) = self
|
||||
let (hir, _, warns) = self
|
||||
.lowerer
|
||||
.lower(ast, "exec")
|
||||
.map_err(|errs| self.convert(errs))?;
|
||||
|
@ -77,8 +78,8 @@ impl Runnable for ASTLowererRunner {
|
|||
|
||||
fn eval(&mut self, src: String) -> Result<String, CompileErrors> {
|
||||
let mut ast_builder = ASTBuilder::new(self.cfg.copy());
|
||||
let ast = ast_builder.build_with_input(src)?;
|
||||
let (hir, _) = self
|
||||
let ast = ast_builder.build_with_str(src)?;
|
||||
let (hir, ..) = self
|
||||
.lowerer
|
||||
.lower(ast, "eval")
|
||||
.map_err(|errs| self.convert(errs))?;
|
||||
|
@ -105,14 +106,14 @@ pub struct ASTLowerer {
|
|||
|
||||
impl Default for ASTLowerer {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
Self::new(SharedModuleCache::new())
|
||||
}
|
||||
}
|
||||
|
||||
impl ASTLowerer {
|
||||
pub fn new() -> Self {
|
||||
pub fn new(mod_cache: SharedModuleCache) -> Self {
|
||||
Self {
|
||||
ctx: Context::new_main_module(),
|
||||
ctx: Context::new_main_module(mod_cache),
|
||||
errs: LowerErrors::empty(),
|
||||
warns: LowerWarnings::empty(),
|
||||
}
|
||||
|
@ -1008,7 +1009,11 @@ impl ASTLowerer {
|
|||
Ok(hir::Block::new(hir_block))
|
||||
}
|
||||
|
||||
pub fn lower(&mut self, ast: AST, mode: &str) -> Result<(HIR, LowerWarnings), LowerErrors> {
|
||||
pub fn lower(
|
||||
&mut self,
|
||||
ast: AST,
|
||||
mode: &str,
|
||||
) -> Result<(HIR, Context, LowerWarnings), LowerErrors> {
|
||||
log!(info "the AST lowering process has started.");
|
||||
log!(info "the type-checking process has started.");
|
||||
let mut module = hir::Module::with_capacity(ast.module.len());
|
||||
|
@ -1035,7 +1040,11 @@ impl ASTLowerer {
|
|||
if self.errs.is_empty() {
|
||||
log!(info "HIR:\n{hir}");
|
||||
log!(info "the AST lowering process has completed.");
|
||||
Ok((hir, LowerWarnings::from(self.warns.take_all())))
|
||||
Ok((
|
||||
hir,
|
||||
self.ctx.pop()?,
|
||||
LowerWarnings::from(self.warns.take_all()),
|
||||
))
|
||||
} else {
|
||||
log!(err "the AST lowering process has failed.");
|
||||
Err(LowerErrors::from(self.errs.take_all()))
|
||||
|
|
|
@ -27,24 +27,24 @@ impl ModId {
|
|||
|
||||
#[derive(Debug)]
|
||||
pub struct ModuleEntry {
|
||||
_id: ModId, // builtin == 0, __main__ == 1
|
||||
_hir: Option<HIR>,
|
||||
id: ModId, // builtin == 0, __main__ == 1
|
||||
pub hir: Option<HIR>,
|
||||
ctx: Rc<Context>,
|
||||
}
|
||||
|
||||
impl ModuleEntry {
|
||||
pub fn new(id: ModId, hir: Option<HIR>, ctx: Context) -> Self {
|
||||
Self {
|
||||
_id: id,
|
||||
_hir: hir,
|
||||
id,
|
||||
hir,
|
||||
ctx: Rc::new(ctx),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn builtin(ctx: Context) -> Self {
|
||||
Self {
|
||||
_id: ModId::builtin(),
|
||||
_hir: None,
|
||||
id: ModId::builtin(),
|
||||
hir: None,
|
||||
ctx: Rc::new(ctx),
|
||||
}
|
||||
}
|
||||
|
@ -53,11 +53,15 @@ impl ModuleEntry {
|
|||
#[derive(Debug, Default)]
|
||||
pub struct ModuleCache {
|
||||
cache: Dict<VarName, ModuleEntry>,
|
||||
last_id: usize,
|
||||
}
|
||||
|
||||
impl ModuleCache {
|
||||
pub fn new() -> Self {
|
||||
Self { cache: Dict::new() }
|
||||
Self {
|
||||
cache: Dict::new(),
|
||||
last_id: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get<Q: Eq + Hash + ?Sized>(&self, name: &Q) -> Option<&ModuleEntry>
|
||||
|
@ -67,7 +71,10 @@ impl ModuleCache {
|
|||
self.cache.get(name)
|
||||
}
|
||||
|
||||
pub fn register(&mut self, name: VarName, entry: ModuleEntry) {
|
||||
pub fn register(&mut self, name: VarName, hir: Option<HIR>, ctx: Context) {
|
||||
self.last_id += 1;
|
||||
let id = ModId::new(self.last_id);
|
||||
let entry = ModuleEntry::new(id, hir, ctx);
|
||||
self.cache.insert(name, entry);
|
||||
}
|
||||
|
||||
|
@ -77,6 +84,20 @@ impl ModuleCache {
|
|||
{
|
||||
self.cache.remove(name)
|
||||
}
|
||||
|
||||
pub fn remove_by_id(&mut self, id: ModId) -> Option<ModuleEntry> {
|
||||
if let Some(name) = self.cache.iter().find_map(|(name, ent)| {
|
||||
if ent.id == id {
|
||||
Some(name.clone())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}) {
|
||||
self.remove(&name)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
|
@ -102,14 +123,18 @@ impl SharedModuleCache {
|
|||
ref_.get(name).map(|entry| entry.ctx.as_ref())
|
||||
}
|
||||
|
||||
pub fn register(&self, name: VarName, entry: ModuleEntry) {
|
||||
self.0.borrow_mut().register(name, entry);
|
||||
pub fn register(&self, name: VarName, hir: Option<HIR>, ctx: Context) {
|
||||
self.0.borrow_mut().register(name, hir, ctx);
|
||||
}
|
||||
|
||||
pub fn remove<Q: Eq + Hash + ?Sized>(&mut self, name: &Q) -> Option<ModuleEntry>
|
||||
pub fn remove<Q: Eq + Hash + ?Sized>(&self, name: &Q) -> Option<ModuleEntry>
|
||||
where
|
||||
VarName: Borrow<Q>,
|
||||
{
|
||||
self.0.borrow_mut().remove(name)
|
||||
}
|
||||
|
||||
pub fn remove_by_id(&self, id: ModId) -> Option<ModuleEntry> {
|
||||
self.0.borrow_mut().remove_by_id(id)
|
||||
}
|
||||
}
|
||||
|
|
113
compiler/erg_compiler/reorder.rs
Normal file
113
compiler/erg_compiler/reorder.rs
Normal file
|
@ -0,0 +1,113 @@
|
|||
use erg_common::dict::Dict;
|
||||
use erg_common::log;
|
||||
use erg_common::traits::{Locational, Stream};
|
||||
use erg_common::Str;
|
||||
|
||||
use crate::ast::{ClassDef, Expr, Methods, Module, PreDeclTypeSpec, TypeSpec, AST};
|
||||
use crate::error::{ParseError, ParseErrors};
|
||||
|
||||
/// Combine method definitions across multiple modules, specialized class contexts, etc.
|
||||
#[derive(Debug, Default)]
|
||||
pub struct Reorderer {
|
||||
// TODO: inner scope types
|
||||
pub def_root_pos_map: Dict<Str, usize>,
|
||||
pub deps: Dict<Str, Vec<Str>>,
|
||||
pub errs: ParseErrors,
|
||||
}
|
||||
|
||||
impl Reorderer {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
def_root_pos_map: Dict::new(),
|
||||
deps: Dict::new(),
|
||||
errs: ParseErrors::empty(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn reorder(mut self, mut ast: AST) -> Result<AST, ParseErrors> {
|
||||
log!(info "the reordering process has started.");
|
||||
let mut new = vec![];
|
||||
while let Some(chunk) = ast.module.lpop() {
|
||||
match chunk {
|
||||
Expr::Def(def) => {
|
||||
match def.body.block.first().unwrap() {
|
||||
Expr::Call(call) => {
|
||||
match call.obj.get_name().map(|s| &s[..]) {
|
||||
// TODO: decorator
|
||||
Some("Class" | "Inherit" | "Inheritable") => {
|
||||
self.def_root_pos_map.insert(
|
||||
def.sig.ident().unwrap().inspect().clone(),
|
||||
new.len(),
|
||||
);
|
||||
let type_def = ClassDef::new(def, vec![]);
|
||||
new.push(Expr::ClassDef(type_def));
|
||||
}
|
||||
_ => {
|
||||
new.push(Expr::Def(def));
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
new.push(Expr::Def(def));
|
||||
}
|
||||
}
|
||||
}
|
||||
Expr::Methods(methods) => match &methods.class {
|
||||
TypeSpec::PreDeclTy(PreDeclTypeSpec::Simple(simple)) => {
|
||||
self.link_methods(simple.name.inspect().clone(), &mut new, methods)
|
||||
}
|
||||
TypeSpec::TypeApp { spec, .. } => {
|
||||
if let TypeSpec::PreDeclTy(PreDeclTypeSpec::Simple(simple)) = spec.as_ref()
|
||||
{
|
||||
self.link_methods(simple.name.inspect().clone(), &mut new, methods)
|
||||
} else {
|
||||
let similar_name = self
|
||||
.def_root_pos_map
|
||||
.keys()
|
||||
.fold("".to_string(), |acc, key| acc + &key[..] + ",");
|
||||
self.errs.push(ParseError::no_var_error(
|
||||
line!() as usize,
|
||||
methods.class.loc(),
|
||||
&methods.class.to_string(),
|
||||
Some(similar_name),
|
||||
));
|
||||
}
|
||||
}
|
||||
other => todo!("{other}"),
|
||||
},
|
||||
other => {
|
||||
new.push(other);
|
||||
}
|
||||
}
|
||||
}
|
||||
let ast = AST::new(ast.name, Module::new(new));
|
||||
log!(info "the reordering process has completed:\n{}", ast);
|
||||
if self.errs.is_empty() {
|
||||
Ok(ast)
|
||||
} else {
|
||||
Err(self.errs)
|
||||
}
|
||||
}
|
||||
|
||||
fn link_methods(&mut self, name: Str, new: &mut Vec<Expr>, methods: Methods) {
|
||||
if let Some(pos) = self.def_root_pos_map.get(&name) {
|
||||
let mut class_def = match new.remove(*pos) {
|
||||
Expr::ClassDef(class_def) => class_def,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
class_def.methods_list.push(methods);
|
||||
new.insert(*pos, Expr::ClassDef(class_def));
|
||||
} else {
|
||||
let similar_name = self
|
||||
.def_root_pos_map
|
||||
.keys()
|
||||
.fold("".to_string(), |acc, key| acc + &key[..] + ",");
|
||||
self.errs.push(ParseError::no_var_error(
|
||||
line!() as usize,
|
||||
methods.class.loc(),
|
||||
&name,
|
||||
Some(similar_name),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,15 +1,16 @@
|
|||
use erg_compiler::context::Context;
|
||||
use erg_compiler::mod_cache::SharedModuleCache;
|
||||
|
||||
#[test]
|
||||
fn test_subtyping() -> Result<(), ()> {
|
||||
let context = Context::new_main_module();
|
||||
let context = Context::new_main_module(SharedModuleCache::new());
|
||||
context.test_refinement_subtyping()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_instantiation_and_generalization() -> Result<(), ()> {
|
||||
let context = Context::new_main_module();
|
||||
let context = Context::new_main_module(SharedModuleCache::new());
|
||||
context.test_instantiation_and_generalization()?;
|
||||
Ok(())
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue