mirror of
https://github.com/erg-lang/erg.git
synced 2025-09-28 04:09:05 +00:00
chore: add Planner
This commit is contained in:
parent
3085229801
commit
e71c0d7720
7 changed files with 250 additions and 14 deletions
|
@ -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> {
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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>;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
219
crates/erg_compiler/plan.rs
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue