chore: add Planner

This commit is contained in:
Shunsuke Shibayama 2023-10-05 15:10:27 +09:00
parent 3085229801
commit e71c0d7720
7 changed files with 250 additions and 14 deletions

View file

@ -117,6 +117,10 @@ impl<T: Hash> Set<T> {
{ {
self.iter().cloned().collect() self.iter().cloned().collect()
} }
pub fn into_vec(self) -> Vec<T> {
self.elems.into_iter().collect()
}
} }
impl<T: Hash> IntoIterator for Set<T> { impl<T: Hash> IntoIterator for Set<T> {

View file

@ -11,17 +11,16 @@ use erg_common::traits::{ExitStatus, Runnable, Stream};
use erg_parser::ast::VarName; use erg_parser::ast::VarName;
use crate::artifact::{CompleteArtifact, ErrorArtifact}; use crate::artifact::{CompleteArtifact, ErrorArtifact};
use crate::context::{Context, ContextProvider};
use crate::optimize::HIROptimizer;
use crate::ty::codeobj::CodeObj;
use crate::build_hir::HIRBuilder;
use crate::codegen::PyCodeGenerator; use crate::codegen::PyCodeGenerator;
use crate::context::{Context, ContextProvider};
use crate::desugar_hir::HIRDesugarer; use crate::desugar_hir::HIRDesugarer;
use crate::error::{CompileError, CompileErrors, CompileWarnings}; use crate::error::{CompileError, CompileErrors, CompileWarnings};
use crate::hir::Expr; use crate::hir::Expr;
use crate::link_hir::HIRLinker; use crate::link_hir::HIRLinker;
use crate::module::SharedCompilerResource; use crate::module::SharedCompilerResource;
use crate::optimize::HIROptimizer;
use crate::plan::Planner;
use crate::ty::codeobj::CodeObj;
use crate::varinfo::VarInfo; use crate::varinfo::VarInfo;
/// * registered as global -> Global /// * registered as global -> Global
@ -113,7 +112,7 @@ impl AccessKind {
#[derive(Debug)] #[derive(Debug)]
pub struct Compiler { pub struct Compiler {
pub cfg: ErgConfig, pub cfg: ErgConfig,
builder: HIRBuilder, planner: Planner,
shared: SharedCompilerResource, shared: SharedCompilerResource,
code_generator: PyCodeGenerator, code_generator: PyCodeGenerator,
} }
@ -133,7 +132,7 @@ impl Runnable for Compiler {
let shared = SharedCompilerResource::new(cfg.copy()); let shared = SharedCompilerResource::new(cfg.copy());
Self { Self {
shared: shared.clone(), shared: shared.clone(),
builder: HIRBuilder::new_with_cache(cfg.copy(), "<module>", shared), planner: Planner::new(cfg.copy(), shared),
code_generator: PyCodeGenerator::new(cfg.copy()), code_generator: PyCodeGenerator::new(cfg.copy()),
cfg, cfg,
} }
@ -152,13 +151,13 @@ impl Runnable for Compiler {
fn finish(&mut self) {} fn finish(&mut self) {}
fn initialize(&mut self) { fn initialize(&mut self) {
self.builder.initialize(); self.planner.builder.initialize();
self.code_generator.clear(); self.code_generator.clear();
// .mod_cache will be initialized in .builder // .mod_cache will be initialized in .builder
} }
fn clear(&mut self) { fn clear(&mut self) {
self.builder.clear(); self.planner.builder.clear();
self.code_generator.clear(); self.code_generator.clear();
} }
@ -187,15 +186,15 @@ impl Runnable for Compiler {
impl ContextProvider for Compiler { impl ContextProvider for Compiler {
fn dir(&self) -> Dict<&VarName, &VarInfo> { fn dir(&self) -> Dict<&VarName, &VarInfo> {
self.builder.dir() self.planner.builder.dir()
} }
fn get_receiver_ctx(&self, receiver_name: &str) -> Option<&Context> { fn get_receiver_ctx(&self, receiver_name: &str) -> Option<&Context> {
self.builder.get_receiver_ctx(receiver_name) self.planner.builder.get_receiver_ctx(receiver_name)
} }
fn get_var_info(&self, name: &str) -> Option<(&VarName, &VarInfo)> { fn get_var_info(&self, name: &str) -> Option<(&VarName, &VarInfo)> {
self.builder.get_var_info(name) self.planner.builder.get_var_info(name)
} }
} }
@ -263,7 +262,7 @@ impl Compiler {
src: String, src: String,
mode: &str, mode: &str,
) -> Result<CompleteArtifact, ErrorArtifact> { ) -> Result<CompleteArtifact, ErrorArtifact> {
let artifact = self.builder.build(src, mode)?; let artifact = self.planner.build(src, mode)?;
let linker = HIRLinker::new(&self.cfg, &self.shared.mod_cache); let linker = HIRLinker::new(&self.cfg, &self.shared.mod_cache);
let hir = linker.link(artifact.object); let hir = linker.link(artifact.object);
let hir = HIRDesugarer::desugar(hir); let hir = HIRDesugarer::desugar(hir);

View file

@ -525,6 +525,10 @@ impl CompileErrors {
pub fn flush(&mut self) -> Self { pub fn flush(&mut self) -> Self {
Self(self.0.drain(..).collect()) Self(self.0.drain(..).collect())
} }
pub fn take(&mut self) -> Self {
self.flush()
}
} }
pub type SingleCompileResult<T> = Result<T, CompileError>; pub type SingleCompileResult<T> = Result<T, CompileError>;

View file

@ -22,6 +22,7 @@ pub mod lower;
pub mod module; pub mod module;
pub mod optimize; pub mod optimize;
pub mod ownercheck; pub mod ownercheck;
pub mod plan;
pub mod transpile; pub mod transpile;
pub mod ty; pub mod ty;
pub mod varinfo; pub mod varinfo;

View file

@ -1,6 +1,7 @@
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use erg_common::config::ErgConfig; use erg_common::config::ErgConfig;
use erg_common::pathutil::NormalizedPathBuf;
use crate::context::Context; use crate::context::Context;
@ -48,7 +49,7 @@ impl SharedCompilerResource {
self_ self_
} }
pub fn inherit(&self, path: PathBuf) -> Self { pub fn inherit<P: Into<NormalizedPathBuf>>(&self, path: P) -> Self {
let mut _self = self.clone(); let mut _self = self.clone();
_self.promises.path = path.into(); _self.promises.path = path.into();
_self _self

View file

@ -106,6 +106,7 @@ impl ModuleGraph {
/// returns Err (and do nothing) if this operation makes a cycle /// returns Err (and do nothing) if this operation makes a cycle
pub fn inc_ref(&mut self, referrer: &Path, depends_on: PathBuf) -> Result<(), IncRefError> { pub fn inc_ref(&mut self, referrer: &Path, depends_on: PathBuf) -> Result<(), IncRefError> {
self.add_node_if_none(referrer);
let referrer = NormalizedPathBuf::new(referrer.to_path_buf()); let referrer = NormalizedPathBuf::new(referrer.to_path_buf());
let depends_on = NormalizedPathBuf::new(depends_on); let depends_on = NormalizedPathBuf::new(depends_on);
if self.ancestors(&depends_on).contains(&referrer) && referrer != depends_on { if self.ancestors(&depends_on).contains(&referrer) && referrer != depends_on {
@ -141,6 +142,9 @@ impl ModuleGraph {
pub fn remove(&mut self, path: &Path) { pub fn remove(&mut self, path: &Path) {
let path = NormalizedPathBuf::new(path.to_path_buf()); let path = NormalizedPathBuf::new(path.to_path_buf());
self.0.retain(|n| n.id != path); self.0.retain(|n| n.id != path);
for node in self.0.iter_mut() {
node.depends_on.retain(|p| *p != path);
}
} }
pub fn rename_path(&mut self, old: &Path, new: PathBuf) { pub fn rename_path(&mut self, old: &Path, new: PathBuf) {
@ -238,4 +242,8 @@ impl SharedModuleGraph {
pub fn initialize(&self) { pub fn initialize(&self) {
self.0.borrow_mut().initialize(); self.0.borrow_mut().initialize();
} }
pub fn clone_inner(&self) -> ModuleGraph {
self.0.borrow().clone()
}
} }

219
crates/erg_compiler/plan.rs Normal file
View file

@ -0,0 +1,219 @@
use std::path::Path;
use erg_common::config::ErgConfig;
use erg_common::dict::Dict;
#[allow(unused)]
use erg_common::log;
use erg_common::pathutil::NormalizedPathBuf;
use erg_common::spawn::spawn_new_thread;
use erg_common::traits::Stream;
use erg_parser::ast::{Expr, AST};
use erg_common::traits::{Locational, Runnable};
use erg_parser::build_ast::ASTBuilder;
use crate::artifact::{CompleteArtifact, ErrorArtifact, IncompleteArtifact};
use crate::error::{CompileError, CompileErrors};
use crate::module::SharedCompilerResource;
use crate::ty::ValueObj;
use crate::ty::{HasType, Type};
use crate::HIRBuilder;
#[derive(Debug)]
pub struct Submodules(Vec<AST>);
#[derive(Debug)]
pub struct Planner {
cfg: ErgConfig,
shared: SharedCompilerResource,
pub(crate) builder: HIRBuilder,
asts: Dict<NormalizedPathBuf, AST>,
parse_errors: ErrorArtifact,
sub_mods: Dict<NormalizedPathBuf, Submodules>,
}
impl Planner {
pub fn new(cfg: ErgConfig, shared: SharedCompilerResource) -> Self {
Self {
cfg: cfg.copy(),
shared: shared.clone(),
builder: HIRBuilder::new_with_cache(cfg, "<module>", shared),
asts: Dict::new(),
parse_errors: ErrorArtifact::new(CompileErrors::empty(), CompileErrors::empty()),
sub_mods: Dict::new(),
}
}
pub fn build(
&mut self,
src: String,
mode: &str,
) -> Result<CompleteArtifact, IncompleteArtifact> {
let mut ast_builder = ASTBuilder::new(self.cfg.copy());
let artifact = ast_builder
.build(src)
.map_err(|err| IncompleteArtifact::new(None, err.errors.into(), err.warns.into()))?;
self.build_module(artifact.ast, mode)
}
pub fn build_module(
&mut self,
ast: AST,
mode: &str,
) -> Result<CompleteArtifact, IncompleteArtifact> {
let from_path = self.cfg.input.path().to_path_buf();
self.plan(&ast, &from_path);
if !self.parse_errors.errors.is_empty() {
return Err(IncompleteArtifact::new(
None,
self.parse_errors.errors.flush(),
self.parse_errors.warns.flush(),
));
}
self.execute(ast, mode)
}
fn plan(&mut self, ast: &AST, from_path: &Path) {
for chunk in ast.module.iter() {
self.check_import(chunk, from_path);
}
}
fn check_import(&mut self, expr: &Expr, from_path: &Path) {
match expr {
Expr::Call(call) if call.additional_operation().is_some_and(|op| op.is_import()) => {
let op = call.additional_operation().unwrap();
let Some(Expr::Literal(mod_name)) = call.args.get_left_or_key("Path") else {
return;
};
let Ok(mod_name) = crate::hir::Literal::try_from(mod_name.token.clone()) else {
return;
};
let ValueObj::Str(__name__) = &mod_name.value else {
let name = if op.is_erg_import() {
"import"
} else {
"pyimport"
};
let err = CompileError::type_mismatch_error(
self.cfg.input.clone(),
line!() as usize,
mod_name.loc(),
"?".into(),
name,
Some(1),
&Type::Str,
&mod_name.t(),
None,
None,
);
self.shared.errors.push(err);
return;
};
let import_path = match self.cfg.input.resolve_path(Path::new(&__name__[..])) {
Some(path) => path,
None => {
return; //Err(self.import_err(line!(), __name__, loc));
}
};
let mut cfg = self.cfg.inherit(import_path.clone());
let src = cfg.input.try_read().unwrap(); // .map_err(|_| self.import_err(line!(), __name__, loc))?;
let mut ast_builder = ASTBuilder::new(self.cfg.copy());
let artifact = match ast_builder.build(src) {
Ok(art) => art,
Err(iart) => {
self.parse_errors
.errors
.extend(CompileErrors::from(iart.errors));
self.parse_errors
.warns
.extend(CompileErrors::from(iart.warns));
return;
}
};
if self
.shared
.graph
.inc_ref(from_path, import_path.clone())
.is_err()
{
if let Some(subs) = self.sub_mods.get_mut(&import_path) {
subs.0.push(artifact.ast);
} else {
let path = NormalizedPathBuf::from(import_path);
self.sub_mods.insert(path, Submodules(vec![artifact.ast]));
}
return;
}
let path = NormalizedPathBuf::from(import_path);
self.plan(&artifact.ast, &path);
self.asts.insert(path, artifact.ast);
}
Expr::Def(def) => {
def.body
.block
.iter()
.for_each(|expr| self.check_import(expr, from_path));
}
_ => {}
}
}
fn execute(&mut self, ast: AST, mode: &str) -> Result<CompleteArtifact, IncompleteArtifact> {
let path = self.cfg.input.path().to_path_buf();
let mut graph = self.shared.graph.clone_inner();
let mut ancestors = graph.ancestors(&path).into_vec();
while let Some(ancestor) = ancestors.pop() {
let ancs = graph.ancestors(&ancestor);
if ancs.is_empty() {
graph.remove(&ancestor);
let ancestor_ast = self.asts.remove(&ancestor).unwrap();
if ancestor_ast.name == ast.name {
continue;
}
let name = ancestor_ast.name.clone();
let _name = name.clone();
let _path = path.clone();
let cfg = self.cfg.inherit(ancestor.to_path_buf());
let shared = self.shared.inherit(ancestor);
let run = move || {
let mut builder = HIRBuilder::new_with_cache(cfg, _name, shared.clone());
let mode = if _path.to_string_lossy().ends_with(".d.er") {
"declare"
} else {
"exec"
};
let cache = if mode == "exec" {
&shared.mod_cache
} else {
&shared.py_mod_cache
};
match builder.check(ancestor_ast, mode) {
Ok(artifact) => {
cache.register(
_path.clone(),
None, // TODO:
Some(artifact.object),
builder.pop_mod_ctx().unwrap(),
);
shared.warns.extend(artifact.warns);
}
Err(artifact) => {
shared.warns.extend(artifact.warns);
shared.errors.extend(artifact.errors);
}
}
};
let handle = spawn_new_thread(run, &name);
self.shared.promises.insert(path.clone(), handle);
} else {
ancestors.insert(0, ancestor);
}
}
let mod_name = "<module>";
let mut builder =
HIRBuilder::new_with_cache(self.cfg.clone(), mod_name, self.shared.clone());
builder.check(ast, mode)
}
}