mirror of
https://github.com/erg-lang/erg.git
synced 2025-09-29 04:24:43 +00:00
Add builder & linker
This commit is contained in:
parent
671fbee518
commit
201b313cd2
19 changed files with 241 additions and 109 deletions
|
@ -126,6 +126,7 @@ pub struct ErgConfig {
|
|||
pub py_server_timeout: u64,
|
||||
pub quiet_startup: bool,
|
||||
pub input: Input,
|
||||
/// module name to be executed
|
||||
pub module: &'static str,
|
||||
/// verbosity level for system messages.
|
||||
/// * 0: display errors
|
||||
|
|
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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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(())
|
||||
}
|
||||
|
|
|
@ -2839,6 +2839,7 @@ pub enum DefKind {
|
|||
Trait,
|
||||
Subsume,
|
||||
StructuralTrait,
|
||||
Module,
|
||||
Other,
|
||||
}
|
||||
|
||||
|
@ -2846,6 +2847,10 @@ impl DefKind {
|
|||
pub const fn is_trait(&self) -> bool {
|
||||
matches!(self, Self::Trait | Self::Subsume | Self::StructuralTrait)
|
||||
}
|
||||
|
||||
pub fn is_module(&self) -> bool {
|
||||
matches!(self, Self::Module)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
|
|
|
@ -6,9 +6,8 @@ use crate::ast::AST;
|
|||
use crate::desugar::Desugarer;
|
||||
use crate::error::ParserRunnerErrors;
|
||||
use crate::parse::ParserRunner;
|
||||
use crate::reorder::Reorderer;
|
||||
|
||||
/// Summarize parsing, desugaring, and reordering
|
||||
/// Summarize parsing and desugaring
|
||||
pub struct ASTBuilder {
|
||||
runner: ParserRunner,
|
||||
}
|
||||
|
@ -27,24 +26,16 @@ impl ASTBuilder {
|
|||
let mut desugarer = Desugarer::new();
|
||||
let module = desugarer.desugar(module);
|
||||
let ast = AST::new(Str::ever(self.runner.cfg().module), module);
|
||||
let reorderer = Reorderer::new();
|
||||
let ast = reorderer
|
||||
.reorder(ast)
|
||||
.map_err(|errs| ParserRunnerErrors::convert(self.runner.input(), errs))?;
|
||||
Ok(ast)
|
||||
}
|
||||
|
||||
pub fn build_with_input(&mut self, src: String) -> Result<AST, ParserRunnerErrors> {
|
||||
let module = self.runner.parse_with_input(src)?;
|
||||
pub fn build_with_str(&mut self, src: String) -> Result<AST, ParserRunnerErrors> {
|
||||
let module = self.runner.parse_with_str(src)?;
|
||||
let mut desugarer = Desugarer::new();
|
||||
let module = desugarer.desugar(module);
|
||||
let mut desugarer = Desugarer::new();
|
||||
let module = desugarer.desugar(module);
|
||||
let ast = AST::new(Str::ever(self.runner.cfg().module), module);
|
||||
let reorderer = Reorderer::new();
|
||||
let ast = reorderer
|
||||
.reorder(ast)
|
||||
.map_err(|errs| ParserRunnerErrors::convert(self.runner.input(), errs))?;
|
||||
Ok(ast)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,6 @@ pub mod desugar;
|
|||
pub mod error;
|
||||
pub mod lex;
|
||||
pub mod parse;
|
||||
pub mod reorder;
|
||||
pub mod token;
|
||||
|
||||
pub use parse::{Parser, ParserRunner};
|
||||
|
|
|
@ -193,7 +193,7 @@ impl Runnable for ParserRunner {
|
|||
}
|
||||
|
||||
fn eval(&mut self, src: String) -> Result<String, ParserRunnerErrors> {
|
||||
let ast = self.parse_with_input(src)?;
|
||||
let ast = self.parse_with_str(src)?;
|
||||
Ok(format!("{ast}"))
|
||||
}
|
||||
}
|
||||
|
@ -212,7 +212,6 @@ impl ParserRunner {
|
|||
self.parse_token_stream(ts)
|
||||
}
|
||||
|
||||
/// Parses with default configuration
|
||||
pub fn parse_with_default_config(input: Input) -> Result<Module, ParserRunnerErrors> {
|
||||
let cfg = ErgConfig {
|
||||
input,
|
||||
|
@ -222,7 +221,7 @@ impl ParserRunner {
|
|||
self_.parse()
|
||||
}
|
||||
|
||||
pub fn parse_with_input(&mut self, src: String) -> Result<Module, ParserRunnerErrors> {
|
||||
pub fn parse_with_str(&mut self, src: String) -> Result<Module, ParserRunnerErrors> {
|
||||
let ts = Lexer::new(Input::Str(src))
|
||||
.lex()
|
||||
.map_err(|errs| ParserRunnerErrors::convert(self.input(), errs))?;
|
||||
|
|
|
@ -16,15 +16,22 @@
|
|||
* `Parser` は `Lexer` と同様に `Parser::new` と `Parser::from_str` の 2 つのコンストラクタを持ち、`Parser::parse` は `AST` を返す。
|
||||
* `AST`は`Vec<Expr>`のラッパー型で、「抽象構文木」を表す。
|
||||
|
||||
### 2.5 `AST`の脱糖
|
||||
### 2.1 `AST`の脱糖
|
||||
|
||||
* ネストされた変数を展開 (`Desugarer::desugar_nest_vars_pattern`)
|
||||
* 複数パターン定義構文をmatchへ変換 (`Desugarer::desugar_multiple_pattern_def`)
|
||||
|
||||
## 3. 型チェックと推論、 `AST` -> `HIR` を変換 (compiler/lower.rs)
|
||||
## 3. `AST` -> `HIR` (compiler/lower.rs)
|
||||
|
||||
## 3.1 名前解決
|
||||
|
||||
* 型推論の前に全てのAST(importされたモジュール含む)を走査し、名前解決を行う
|
||||
* 定数の循環検査や並び替えなどが行われるほか、型推論のためのContextが作成される(ただし、このContextに登録された変数の情報ははまだ殆どが未確定)
|
||||
|
||||
### 3.2 型チェックと推論 (compiler/lower.rs)
|
||||
|
||||
* `HIR` は、すべての変数の型情報を持っており、「高レベルの中間表現」を表す。
|
||||
* `ASTLowerer は Parser や Lexer と同じように構築できる。
|
||||
* `ASTLowerer` は Parser や Lexer と同じように構築できる。
|
||||
* `ASTLowerer::lower` は、エラーが発生しなければ、`HIR` と `CompileWarnings` のタプルを出力する。
|
||||
* `ASTLowerer` は `Compiler` によって所有されている。 `ASTLowerer` は従来の構造体とは異なり、文脈を保持し、1 回限りの使い捨てではない。
|
||||
* 型推論の結果が不完全な場合(未知の型変数がある場合)、名前解決時にエラーが発生する。
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue