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 py_server_timeout: u64,
|
||||||
pub quiet_startup: bool,
|
pub quiet_startup: bool,
|
||||||
pub input: Input,
|
pub input: Input,
|
||||||
|
/// module name to be executed
|
||||||
pub module: &'static str,
|
pub module: &'static str,
|
||||||
/// verbosity level for system messages.
|
/// verbosity level for system messages.
|
||||||
/// * 0: display errors
|
/// * 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::ast::AST;
|
||||||
use erg_parser::builder::ASTBuilder;
|
use erg_parser::builder::ASTBuilder;
|
||||||
|
|
||||||
|
use crate::context::Context;
|
||||||
use crate::effectcheck::SideEffectChecker;
|
use crate::effectcheck::SideEffectChecker;
|
||||||
use crate::error::{TyCheckError, TyCheckErrors};
|
use crate::error::{TyCheckError, TyCheckErrors};
|
||||||
use crate::hir::HIR;
|
use crate::hir::HIR;
|
||||||
use crate::lower::ASTLowerer;
|
use crate::lower::ASTLowerer;
|
||||||
|
use crate::mod_cache::SharedModuleCache;
|
||||||
use crate::ownercheck::OwnershipChecker;
|
use crate::ownercheck::OwnershipChecker;
|
||||||
|
|
||||||
/// Summarize lowering, side-effect checking, and ownership checking
|
/// Summarize lowering, side-effect checking, and ownership checking
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Checker {
|
pub struct Checker {
|
||||||
cfg: ErgConfig,
|
pub cfg: ErgConfig,
|
||||||
lowerer: ASTLowerer,
|
lowerer: ASTLowerer,
|
||||||
ownership_checker: OwnershipChecker,
|
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 Err = TyCheckError;
|
||||||
type Errs = TyCheckErrors;
|
type Errs = TyCheckErrors;
|
||||||
const NAME: &'static str = "Erg type-checker";
|
const NAME: &'static str = "Erg type-checker";
|
||||||
|
|
||||||
fn new(cfg: ErgConfig) -> Self {
|
fn new(cfg: ErgConfig) -> Self {
|
||||||
Self {
|
Self {
|
||||||
ownership_checker: OwnershipChecker::new(),
|
checker: Checker::new(cfg, SharedModuleCache::new()),
|
||||||
lowerer: ASTLowerer::new(),
|
|
||||||
cfg,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn cfg(&self) -> &ErgConfig {
|
fn cfg(&self) -> &ErgConfig {
|
||||||
&self.cfg
|
&self.checker.cfg
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -43,30 +68,17 @@ impl Runnable for Checker {
|
||||||
fn clear(&mut self) {}
|
fn clear(&mut self) {}
|
||||||
|
|
||||||
fn exec(&mut self) -> Result<(), Self::Errs> {
|
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 ast = builder.build()?;
|
||||||
let hir = self.check(ast, "exec")?;
|
let (hir, _) = self.checker.check(ast, "exec")?;
|
||||||
println!("{hir}");
|
println!("{hir}");
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval(&mut self, src: String) -> Result<String, TyCheckErrors> {
|
fn eval(&mut self, src: String) -> Result<String, TyCheckErrors> {
|
||||||
let mut builder = ASTBuilder::new(self.cfg.copy());
|
let mut builder = ASTBuilder::new(self.cfg().copy());
|
||||||
let ast = builder.build_with_input(src)?;
|
let ast = builder.build_with_str(src)?;
|
||||||
let hir = self.check(ast, "eval")?;
|
let (hir, _) = self.checker.check(ast, "eval")?;
|
||||||
Ok(hir.to_string())
|
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 std::path::Path;
|
||||||
|
|
||||||
use erg_common::config::{ErgConfig, Input};
|
use erg_common::config::ErgConfig;
|
||||||
use erg_common::log;
|
use erg_common::log;
|
||||||
use erg_common::traits::{Runnable, Stream};
|
use erg_common::traits::{Runnable, Stream};
|
||||||
use erg_type::codeobj::CodeObj;
|
use erg_type::codeobj::CodeObj;
|
||||||
|
|
||||||
use erg_parser::builder::ASTBuilder;
|
use crate::builder::HIRBuilder;
|
||||||
|
|
||||||
use crate::checker::Checker;
|
|
||||||
use crate::codegen::CodeGenerator;
|
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
|
/// * registered as global -> Global
|
||||||
/// * defined in the toplevel scope (and called in the inner scope) -> Global
|
/// * defined in the toplevel scope (and called in the inner scope) -> Global
|
||||||
|
@ -91,7 +91,7 @@ impl AccessKind {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Compiler {
|
pub struct Compiler {
|
||||||
cfg: ErgConfig,
|
cfg: ErgConfig,
|
||||||
checker: Checker,
|
mod_cache: SharedModuleCache,
|
||||||
code_generator: CodeGenerator,
|
code_generator: CodeGenerator,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,9 +101,10 @@ impl Runnable for Compiler {
|
||||||
const NAME: &'static str = "Erg compiler";
|
const NAME: &'static str = "Erg compiler";
|
||||||
|
|
||||||
fn new(cfg: ErgConfig) -> Self {
|
fn new(cfg: ErgConfig) -> Self {
|
||||||
|
let mod_cache = SharedModuleCache::new();
|
||||||
Self {
|
Self {
|
||||||
checker: Checker::new(cfg.copy()),
|
|
||||||
code_generator: CodeGenerator::new(cfg.copy()),
|
code_generator: CodeGenerator::new(cfg.copy()),
|
||||||
|
mod_cache,
|
||||||
cfg,
|
cfg,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -133,13 +134,6 @@ impl Runnable for Compiler {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl 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>>(
|
pub fn compile_and_dump_as_pyc<P: AsRef<Path>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
src: String,
|
src: String,
|
||||||
|
@ -154,14 +148,9 @@ impl Compiler {
|
||||||
|
|
||||||
pub fn compile(&mut self, src: String, mode: &str) -> Result<CodeObj, CompileErrors> {
|
pub fn compile(&mut self, src: String, mode: &str) -> Result<CodeObj, CompileErrors> {
|
||||||
log!(info "the compiling process has started.");
|
log!(info "the compiling process has started.");
|
||||||
let mut cfg = self.cfg.copy();
|
let mut hir_builder = HIRBuilder::new(self.cfg.copy(), self.mod_cache.clone());
|
||||||
cfg.input = Input::Str(src);
|
hir_builder.build_and_cache_main(src, mode)?;
|
||||||
let mut ast_builder = ASTBuilder::new(cfg);
|
let hir = Linker::link(self.mod_cache.clone());
|
||||||
let ast = ast_builder.build()?;
|
|
||||||
let hir = self
|
|
||||||
.checker
|
|
||||||
.check(ast, mode)
|
|
||||||
.map_err(|errs| self.convert(errs))?;
|
|
||||||
let codeobj = self.code_generator.emit(hir);
|
let codeobj = self.code_generator.emit(hir);
|
||||||
log!(info "code object:\n{}", codeobj.code_info());
|
log!(info "code object:\n{}", codeobj.code_info());
|
||||||
log!(
|
log!(
|
||||||
|
|
|
@ -1783,13 +1783,13 @@ impl Context {
|
||||||
ctx
|
ctx
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_main_module() -> Self {
|
pub fn new_main_module(mod_cache: SharedModuleCache) -> Self {
|
||||||
Context::new(
|
Context::new(
|
||||||
"<module>".into(),
|
"<module>".into(),
|
||||||
ContextKind::Module,
|
ContextKind::Module,
|
||||||
vec![],
|
vec![],
|
||||||
Some(Context::init_builtins()),
|
Some(Context::init_builtins()),
|
||||||
Some(SharedModuleCache::new()),
|
Some(mod_cache),
|
||||||
Context::TOP_LEVEL,
|
Context::TOP_LEVEL,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -238,6 +238,7 @@ impl From<DefKind> for ContextKind {
|
||||||
DefKind::Class | DefKind::Inherit => Self::Class,
|
DefKind::Class | DefKind::Inherit => Self::Class,
|
||||||
DefKind::Trait | DefKind::Subsume => Self::Trait,
|
DefKind::Trait | DefKind::Subsume => Self::Trait,
|
||||||
DefKind::StructuralTrait => Self::StructuralTrait,
|
DefKind::StructuralTrait => Self::StructuralTrait,
|
||||||
|
DefKind::Module => Self::Module,
|
||||||
DefKind::Other => Self::Instant,
|
DefKind::Other => Self::Instant,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
use std::option::Option; // conflicting to Type::Option
|
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::traits::{Locational, Stream};
|
||||||
use erg_common::vis::Visibility;
|
use erg_common::vis::Visibility;
|
||||||
use erg_common::Str;
|
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 erg_type::{HasType, ParamTy, SubrType, TyBound, Type};
|
||||||
use Type::*;
|
use Type::*;
|
||||||
|
|
||||||
|
use crate::builder::HIRBuilder;
|
||||||
use crate::context::{ClassDefType, Context, DefaultInfo, RegistrationMode, TraitInstance};
|
use crate::context::{ClassDefType, Context, DefaultInfo, RegistrationMode, TraitInstance};
|
||||||
use crate::error::readable_name;
|
use crate::error::readable_name;
|
||||||
use crate::error::{TyCheckError, TyCheckResult};
|
use crate::error::{TyCheckError, TyCheckResult};
|
||||||
use crate::hir;
|
use crate::hir;
|
||||||
use crate::mod_cache::ModuleEntry;
|
use crate::mod_cache::SharedModuleCache;
|
||||||
use crate::varinfo::{Mutability, ParamIdx, VarInfo, VarKind};
|
use crate::varinfo::{Mutability, ParamIdx, VarInfo, VarKind};
|
||||||
use Mutability::*;
|
use Mutability::*;
|
||||||
use RegistrationMode::*;
|
use RegistrationMode::*;
|
||||||
|
@ -763,56 +766,55 @@ impl Context {
|
||||||
match mod_name {
|
match mod_name {
|
||||||
hir::Expr::Lit(lit) => {
|
hir::Expr::Lit(lit) => {
|
||||||
if self.subtype_of(&lit.value.class(), &Str) {
|
if self.subtype_of(&lit.value.class(), &Str) {
|
||||||
let name = enum_unwrap!(lit.value.clone(), ValueObj::Str);
|
let __name__ = enum_unwrap!(lit.value.clone(), ValueObj::Str);
|
||||||
if let Some(mod_cache) = self.mod_cache.as_mut() {
|
if let Some(mod_cache) = self.mod_cache.as_ref() {
|
||||||
match &name[..] {
|
match &__name__[..] {
|
||||||
"importlib" => {
|
"importlib" => {
|
||||||
mod_cache.register(
|
mod_cache.register(
|
||||||
var_name.clone(),
|
var_name.clone(),
|
||||||
ModuleEntry::builtin(Self::init_py_importlib_mod()),
|
None,
|
||||||
|
Self::init_py_importlib_mod(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
"io" => {
|
"io" => {
|
||||||
mod_cache.register(
|
mod_cache.register(var_name.clone(), None, Self::init_py_io_mod());
|
||||||
var_name.clone(),
|
|
||||||
ModuleEntry::builtin(Self::init_py_io_mod()),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
"math" => {
|
"math" => {
|
||||||
mod_cache.register(
|
mod_cache.register(
|
||||||
var_name.clone(),
|
var_name.clone(),
|
||||||
ModuleEntry::builtin(Self::init_py_math_mod()),
|
None,
|
||||||
|
Self::init_py_math_mod(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
"random" => {
|
"random" => {
|
||||||
mod_cache.register(
|
mod_cache.register(
|
||||||
var_name.clone(),
|
var_name.clone(),
|
||||||
ModuleEntry::builtin(Self::init_py_random_mod()),
|
None,
|
||||||
|
Self::init_py_random_mod(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
"socket" => {
|
"socket" => {
|
||||||
mod_cache.register(
|
mod_cache.register(
|
||||||
var_name.clone(),
|
var_name.clone(),
|
||||||
ModuleEntry::builtin(Self::init_py_socket_mod()),
|
None,
|
||||||
|
Self::init_py_socket_mod(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
"sys" => {
|
"sys" => {
|
||||||
mod_cache.register(
|
mod_cache.register(var_name.clone(), None, Self::init_py_sys_mod());
|
||||||
var_name.clone(),
|
|
||||||
ModuleEntry::builtin(Self::init_py_sys_mod()),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
"time" => {
|
"time" => {
|
||||||
mod_cache.register(
|
mod_cache.register(
|
||||||
var_name.clone(),
|
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 {
|
} else {
|
||||||
// maybe unreachable
|
// maybe unreachable
|
||||||
todo!("importing {name} in the builtin module")
|
todo!("importing {__name__} in the builtin module")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return Err(TyCheckError::type_mismatch_error(
|
return Err(TyCheckError::type_mismatch_error(
|
||||||
|
@ -839,6 +841,17 @@ impl Context {
|
||||||
Ok(())
|
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) {
|
pub(crate) fn _push_subtype_bound(&mut self, sub: Type, sup: Type) {
|
||||||
self.bounds.push(TyBound::subtype_of(sub, sup));
|
self.bounds.push(TyBound::subtype_of(sub, sup));
|
||||||
}
|
}
|
||||||
|
|
|
@ -1332,6 +1332,7 @@ impl Def {
|
||||||
DefKind::Other
|
DefKind::Other
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Some("import") => DefKind::Module,
|
||||||
_ => DefKind::Other,
|
_ => DefKind::Other,
|
||||||
},
|
},
|
||||||
_ => DefKind::Other,
|
_ => DefKind::Other,
|
||||||
|
|
|
@ -3,7 +3,8 @@
|
||||||
extern crate erg_common;
|
extern crate erg_common;
|
||||||
pub extern crate erg_parser;
|
pub extern crate erg_parser;
|
||||||
|
|
||||||
mod checker;
|
mod builder;
|
||||||
|
mod check;
|
||||||
mod compile;
|
mod compile;
|
||||||
pub use compile::*;
|
pub use compile::*;
|
||||||
mod codegen;
|
mod codegen;
|
||||||
|
@ -11,8 +12,10 @@ pub mod context;
|
||||||
pub mod effectcheck;
|
pub mod effectcheck;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod hir;
|
pub mod hir;
|
||||||
|
pub mod link;
|
||||||
pub mod lower;
|
pub mod lower;
|
||||||
pub mod mod_cache;
|
pub mod mod_cache;
|
||||||
|
// pub mod name_resolve;
|
||||||
pub mod optimize;
|
pub mod optimize;
|
||||||
pub mod ownercheck;
|
pub mod ownercheck;
|
||||||
pub mod varinfo;
|
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;
|
||||||
use crate::hir::HIR;
|
use crate::hir::HIR;
|
||||||
|
use crate::mod_cache::SharedModuleCache;
|
||||||
use crate::varinfo::VarKind;
|
use crate::varinfo::VarKind;
|
||||||
use Visibility::*;
|
use Visibility::*;
|
||||||
|
|
||||||
|
@ -48,7 +49,7 @@ impl Runnable for ASTLowererRunner {
|
||||||
fn new(cfg: ErgConfig) -> Self {
|
fn new(cfg: ErgConfig) -> Self {
|
||||||
Self {
|
Self {
|
||||||
cfg,
|
cfg,
|
||||||
lowerer: ASTLowerer::new(),
|
lowerer: ASTLowerer::new(SharedModuleCache::new()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,7 +64,7 @@ impl Runnable for ASTLowererRunner {
|
||||||
fn exec(&mut self) -> Result<(), Self::Errs> {
|
fn exec(&mut self) -> Result<(), Self::Errs> {
|
||||||
let mut ast_builder = ASTBuilder::new(self.cfg.copy());
|
let mut ast_builder = ASTBuilder::new(self.cfg.copy());
|
||||||
let ast = ast_builder.build()?;
|
let ast = ast_builder.build()?;
|
||||||
let (hir, warns) = self
|
let (hir, _, warns) = self
|
||||||
.lowerer
|
.lowerer
|
||||||
.lower(ast, "exec")
|
.lower(ast, "exec")
|
||||||
.map_err(|errs| self.convert(errs))?;
|
.map_err(|errs| self.convert(errs))?;
|
||||||
|
@ -77,8 +78,8 @@ impl Runnable for ASTLowererRunner {
|
||||||
|
|
||||||
fn eval(&mut self, src: String) -> Result<String, CompileErrors> {
|
fn eval(&mut self, src: String) -> Result<String, CompileErrors> {
|
||||||
let mut ast_builder = ASTBuilder::new(self.cfg.copy());
|
let mut ast_builder = ASTBuilder::new(self.cfg.copy());
|
||||||
let ast = ast_builder.build_with_input(src)?;
|
let ast = ast_builder.build_with_str(src)?;
|
||||||
let (hir, _) = self
|
let (hir, ..) = self
|
||||||
.lowerer
|
.lowerer
|
||||||
.lower(ast, "eval")
|
.lower(ast, "eval")
|
||||||
.map_err(|errs| self.convert(errs))?;
|
.map_err(|errs| self.convert(errs))?;
|
||||||
|
@ -105,14 +106,14 @@ pub struct ASTLowerer {
|
||||||
|
|
||||||
impl Default for ASTLowerer {
|
impl Default for ASTLowerer {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self::new()
|
Self::new(SharedModuleCache::new())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ASTLowerer {
|
impl ASTLowerer {
|
||||||
pub fn new() -> Self {
|
pub fn new(mod_cache: SharedModuleCache) -> Self {
|
||||||
Self {
|
Self {
|
||||||
ctx: Context::new_main_module(),
|
ctx: Context::new_main_module(mod_cache),
|
||||||
errs: LowerErrors::empty(),
|
errs: LowerErrors::empty(),
|
||||||
warns: LowerWarnings::empty(),
|
warns: LowerWarnings::empty(),
|
||||||
}
|
}
|
||||||
|
@ -1008,7 +1009,11 @@ impl ASTLowerer {
|
||||||
Ok(hir::Block::new(hir_block))
|
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 AST lowering process has started.");
|
||||||
log!(info "the type-checking process has started.");
|
log!(info "the type-checking process has started.");
|
||||||
let mut module = hir::Module::with_capacity(ast.module.len());
|
let mut module = hir::Module::with_capacity(ast.module.len());
|
||||||
|
@ -1035,7 +1040,11 @@ impl ASTLowerer {
|
||||||
if self.errs.is_empty() {
|
if self.errs.is_empty() {
|
||||||
log!(info "HIR:\n{hir}");
|
log!(info "HIR:\n{hir}");
|
||||||
log!(info "the AST lowering process has completed.");
|
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 {
|
} else {
|
||||||
log!(err "the AST lowering process has failed.");
|
log!(err "the AST lowering process has failed.");
|
||||||
Err(LowerErrors::from(self.errs.take_all()))
|
Err(LowerErrors::from(self.errs.take_all()))
|
||||||
|
|
|
@ -27,24 +27,24 @@ impl ModId {
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ModuleEntry {
|
pub struct ModuleEntry {
|
||||||
_id: ModId, // builtin == 0, __main__ == 1
|
id: ModId, // builtin == 0, __main__ == 1
|
||||||
_hir: Option<HIR>,
|
pub hir: Option<HIR>,
|
||||||
ctx: Rc<Context>,
|
ctx: Rc<Context>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ModuleEntry {
|
impl ModuleEntry {
|
||||||
pub fn new(id: ModId, hir: Option<HIR>, ctx: Context) -> Self {
|
pub fn new(id: ModId, hir: Option<HIR>, ctx: Context) -> Self {
|
||||||
Self {
|
Self {
|
||||||
_id: id,
|
id,
|
||||||
_hir: hir,
|
hir,
|
||||||
ctx: Rc::new(ctx),
|
ctx: Rc::new(ctx),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn builtin(ctx: Context) -> Self {
|
pub fn builtin(ctx: Context) -> Self {
|
||||||
Self {
|
Self {
|
||||||
_id: ModId::builtin(),
|
id: ModId::builtin(),
|
||||||
_hir: None,
|
hir: None,
|
||||||
ctx: Rc::new(ctx),
|
ctx: Rc::new(ctx),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -53,11 +53,15 @@ impl ModuleEntry {
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct ModuleCache {
|
pub struct ModuleCache {
|
||||||
cache: Dict<VarName, ModuleEntry>,
|
cache: Dict<VarName, ModuleEntry>,
|
||||||
|
last_id: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ModuleCache {
|
impl ModuleCache {
|
||||||
pub fn new() -> Self {
|
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>
|
pub fn get<Q: Eq + Hash + ?Sized>(&self, name: &Q) -> Option<&ModuleEntry>
|
||||||
|
@ -67,7 +71,10 @@ impl ModuleCache {
|
||||||
self.cache.get(name)
|
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);
|
self.cache.insert(name, entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,6 +84,20 @@ impl ModuleCache {
|
||||||
{
|
{
|
||||||
self.cache.remove(name)
|
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)]
|
#[derive(Debug, Clone, Default)]
|
||||||
|
@ -102,14 +123,18 @@ impl SharedModuleCache {
|
||||||
ref_.get(name).map(|entry| entry.ctx.as_ref())
|
ref_.get(name).map(|entry| entry.ctx.as_ref())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn register(&self, name: VarName, entry: ModuleEntry) {
|
pub fn register(&self, name: VarName, hir: Option<HIR>, ctx: Context) {
|
||||||
self.0.borrow_mut().register(name, entry);
|
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
|
where
|
||||||
VarName: Borrow<Q>,
|
VarName: Borrow<Q>,
|
||||||
{
|
{
|
||||||
self.0.borrow_mut().remove(name)
|
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::context::Context;
|
||||||
|
use erg_compiler::mod_cache::SharedModuleCache;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_subtyping() -> Result<(), ()> {
|
fn test_subtyping() -> Result<(), ()> {
|
||||||
let context = Context::new_main_module();
|
let context = Context::new_main_module(SharedModuleCache::new());
|
||||||
context.test_refinement_subtyping()?;
|
context.test_refinement_subtyping()?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_instantiation_and_generalization() -> Result<(), ()> {
|
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()?;
|
context.test_instantiation_and_generalization()?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -2839,6 +2839,7 @@ pub enum DefKind {
|
||||||
Trait,
|
Trait,
|
||||||
Subsume,
|
Subsume,
|
||||||
StructuralTrait,
|
StructuralTrait,
|
||||||
|
Module,
|
||||||
Other,
|
Other,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2846,6 +2847,10 @@ impl DefKind {
|
||||||
pub const fn is_trait(&self) -> bool {
|
pub const fn is_trait(&self) -> bool {
|
||||||
matches!(self, Self::Trait | Self::Subsume | Self::StructuralTrait)
|
matches!(self, Self::Trait | Self::Subsume | Self::StructuralTrait)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_module(&self) -> bool {
|
||||||
|
matches!(self, Self::Module)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
|
|
|
@ -6,9 +6,8 @@ use crate::ast::AST;
|
||||||
use crate::desugar::Desugarer;
|
use crate::desugar::Desugarer;
|
||||||
use crate::error::ParserRunnerErrors;
|
use crate::error::ParserRunnerErrors;
|
||||||
use crate::parse::ParserRunner;
|
use crate::parse::ParserRunner;
|
||||||
use crate::reorder::Reorderer;
|
|
||||||
|
|
||||||
/// Summarize parsing, desugaring, and reordering
|
/// Summarize parsing and desugaring
|
||||||
pub struct ASTBuilder {
|
pub struct ASTBuilder {
|
||||||
runner: ParserRunner,
|
runner: ParserRunner,
|
||||||
}
|
}
|
||||||
|
@ -27,24 +26,16 @@ impl ASTBuilder {
|
||||||
let mut desugarer = Desugarer::new();
|
let mut desugarer = Desugarer::new();
|
||||||
let module = desugarer.desugar(module);
|
let module = desugarer.desugar(module);
|
||||||
let ast = AST::new(Str::ever(self.runner.cfg().module), 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)
|
Ok(ast)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build_with_input(&mut self, src: String) -> Result<AST, ParserRunnerErrors> {
|
pub fn build_with_str(&mut self, src: String) -> Result<AST, ParserRunnerErrors> {
|
||||||
let module = self.runner.parse_with_input(src)?;
|
let module = self.runner.parse_with_str(src)?;
|
||||||
let mut desugarer = Desugarer::new();
|
let mut desugarer = Desugarer::new();
|
||||||
let module = desugarer.desugar(module);
|
let module = desugarer.desugar(module);
|
||||||
let mut desugarer = Desugarer::new();
|
let mut desugarer = Desugarer::new();
|
||||||
let module = desugarer.desugar(module);
|
let module = desugarer.desugar(module);
|
||||||
let ast = AST::new(Str::ever(self.runner.cfg().module), 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)
|
Ok(ast)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,6 @@ pub mod desugar;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod lex;
|
pub mod lex;
|
||||||
pub mod parse;
|
pub mod parse;
|
||||||
pub mod reorder;
|
|
||||||
pub mod token;
|
pub mod token;
|
||||||
|
|
||||||
pub use parse::{Parser, ParserRunner};
|
pub use parse::{Parser, ParserRunner};
|
||||||
|
|
|
@ -193,7 +193,7 @@ impl Runnable for ParserRunner {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval(&mut self, src: String) -> Result<String, ParserRunnerErrors> {
|
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}"))
|
Ok(format!("{ast}"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -212,7 +212,6 @@ impl ParserRunner {
|
||||||
self.parse_token_stream(ts)
|
self.parse_token_stream(ts)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parses with default configuration
|
|
||||||
pub fn parse_with_default_config(input: Input) -> Result<Module, ParserRunnerErrors> {
|
pub fn parse_with_default_config(input: Input) -> Result<Module, ParserRunnerErrors> {
|
||||||
let cfg = ErgConfig {
|
let cfg = ErgConfig {
|
||||||
input,
|
input,
|
||||||
|
@ -222,7 +221,7 @@ impl ParserRunner {
|
||||||
self_.parse()
|
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))
|
let ts = Lexer::new(Input::Str(src))
|
||||||
.lex()
|
.lex()
|
||||||
.map_err(|errs| ParserRunnerErrors::convert(self.input(), errs))?;
|
.map_err(|errs| ParserRunnerErrors::convert(self.input(), errs))?;
|
||||||
|
|
|
@ -16,15 +16,22 @@
|
||||||
* `Parser` は `Lexer` と同様に `Parser::new` と `Parser::from_str` の 2 つのコンストラクタを持ち、`Parser::parse` は `AST` を返す。
|
* `Parser` は `Lexer` と同様に `Parser::new` と `Parser::from_str` の 2 つのコンストラクタを持ち、`Parser::parse` は `AST` を返す。
|
||||||
* `AST`は`Vec<Expr>`のラッパー型で、「抽象構文木」を表す。
|
* `AST`は`Vec<Expr>`のラッパー型で、「抽象構文木」を表す。
|
||||||
|
|
||||||
### 2.5 `AST`の脱糖
|
### 2.1 `AST`の脱糖
|
||||||
|
|
||||||
* ネストされた変数を展開 (`Desugarer::desugar_nest_vars_pattern`)
|
* ネストされた変数を展開 (`Desugarer::desugar_nest_vars_pattern`)
|
||||||
* 複数パターン定義構文をmatchへ変換 (`Desugarer::desugar_multiple_pattern_def`)
|
* 複数パターン定義構文を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` は、すべての変数の型情報を持っており、「高レベルの中間表現」を表す。
|
* `HIR` は、すべての変数の型情報を持っており、「高レベルの中間表現」を表す。
|
||||||
* `ASTLowerer は Parser や Lexer と同じように構築できる。
|
* `ASTLowerer` は Parser や Lexer と同じように構築できる。
|
||||||
* `ASTLowerer::lower` は、エラーが発生しなければ、`HIR` と `CompileWarnings` のタプルを出力する。
|
* `ASTLowerer::lower` は、エラーが発生しなければ、`HIR` と `CompileWarnings` のタプルを出力する。
|
||||||
* `ASTLowerer` は `Compiler` によって所有されている。 `ASTLowerer` は従来の構造体とは異なり、文脈を保持し、1 回限りの使い捨てではない。
|
* `ASTLowerer` は `Compiler` によって所有されている。 `ASTLowerer` は従来の構造体とは異なり、文脈を保持し、1 回限りの使い捨てではない。
|
||||||
* 型推論の結果が不完全な場合(未知の型変数がある場合)、名前解決時にエラーが発生する。
|
* 型推論の結果が不完全な場合(未知の型変数がある場合)、名前解決時にエラーが発生する。
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue