From f0cf267da2fb931254ad8ab8f25d0aee9bbc70dd Mon Sep 17 00:00:00 2001 From: Shunsuke Shibayama Date: Sun, 25 Dec 2022 18:17:39 +0900 Subject: [PATCH] Update: generate type definition files even in errors --- Cargo.lock | 6 +++--- crates/py2erg/gen_decl.rs | 25 +++++++++++++++++++++---- src/analyze.rs | 29 ++++++++++++++++++----------- 3 files changed, 42 insertions(+), 18 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2b421c6..3fd77e9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -227,7 +227,7 @@ dependencies = [ [[package]] name = "erg_common" version = "0.6.0-beta.4" -source = "git+https://github.com/erg-lang/erg?branch=main#46418987c1e6bf24baa774827cb1e4be8fe25b67" +source = "git+https://github.com/erg-lang/erg?branch=main#1c607cfe5ba87b0dc37c4a3393629c023d85e317" dependencies = [ "hermit-abi", "libc", @@ -237,7 +237,7 @@ dependencies = [ [[package]] name = "erg_compiler" version = "0.6.0-beta.4" -source = "git+https://github.com/erg-lang/erg?branch=main#46418987c1e6bf24baa774827cb1e4be8fe25b67" +source = "git+https://github.com/erg-lang/erg?branch=main#1c607cfe5ba87b0dc37c4a3393629c023d85e317" dependencies = [ "erg_common", "erg_parser", @@ -246,7 +246,7 @@ dependencies = [ [[package]] name = "erg_parser" version = "0.6.0-beta.4" -source = "git+https://github.com/erg-lang/erg?branch=main#46418987c1e6bf24baa774827cb1e4be8fe25b67" +source = "git+https://github.com/erg-lang/erg?branch=main#1c607cfe5ba87b0dc37c4a3393629c023d85e317" dependencies = [ "erg_common", "unicode-xid 0.2.4", diff --git a/crates/py2erg/gen_decl.rs b/crates/py2erg/gen_decl.rs index 6337454..716ec33 100644 --- a/crates/py2erg/gen_decl.rs +++ b/crates/py2erg/gen_decl.rs @@ -1,10 +1,26 @@ use std::io::Write; use std::path::PathBuf; +use erg_common::log; use erg_common::config::Input; use erg_compiler::hir::{HIR, Expr}; use erg_compiler::ty::HasType; +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum CheckStatus { + Succeed, + Failed, +} + +impl CheckStatus { + pub const fn is_succeed(&self) -> bool { + matches!(self, CheckStatus::Succeed) + } + pub const fn is_failed(&self) -> bool { + matches!(self, CheckStatus::Failed) + } +} + pub struct DeclFile { pub filename: String, pub code: String, @@ -14,8 +30,8 @@ fn escape_type(typ: String) -> String { typ.replace('%', "Type_") } -pub fn gen_decl_er(hir: HIR) -> DeclFile { - let mut code = "".to_string(); +pub fn gen_decl_er(hir: HIR, status: CheckStatus) -> DeclFile { + let mut code = if status.is_failed() { "# failed\n".to_string() } else { "# succeed\n".to_string() }; for chunk in hir.module.into_iter() { match chunk { Expr::Def(def) => { @@ -32,12 +48,13 @@ pub fn gen_decl_er(hir: HIR) -> DeclFile { } code.push('\n'); } + log!("code:\n{code}"); let filename = hir.name.replace(".py", ".d.er"); DeclFile { filename, code } } -pub fn dump_decl_er(input: Input, hir: HIR) { - let file = gen_decl_er(hir); +pub fn dump_decl_er(input: Input, hir: HIR, status: CheckStatus) { + let file = gen_decl_er(hir, status); let mut path = if let Input::File(path) = input { path } else { PathBuf::new() }; path.pop(); path.push("__pycache__"); diff --git a/src/analyze.rs b/src/analyze.rs index 2733ee5..a0e9704 100644 --- a/src/analyze.rs +++ b/src/analyze.rs @@ -1,4 +1,5 @@ use erg_common::traits::{Runnable, Stream}; +use erg_common::style::{GREEN, BLUE, RED, YELLOW, RESET}; use erg_common::config::{ErgConfig}; use erg_common::error::{MultiErrorDisplay, ErrorCore, ErrorKind}; use erg_compiler::artifact::{BuildRunnable, CompleteArtifact, IncompleteArtifact, Buildable}; @@ -6,7 +7,7 @@ use erg_compiler::context::Context; use erg_compiler::erg_parser::ast::AST; use erg_compiler::error::{CompileErrors, CompileError}; use erg_compiler::lower::ASTLowerer; -use py2erg::ShadowingMode; +use py2erg::{CheckStatus, ShadowingMode}; use py2erg::dump_decl_er; use rustpython_parser::parser; @@ -118,33 +119,39 @@ impl PythonAnalyzer { pub fn run(&mut self) { let filename = self.cfg.input.filename(); let py_code = self.cfg.input.read(); - println!("Start checking: {filename}"); + println!("{BLUE}Start checking{RESET}: {filename}"); match self.analyze(py_code, "exec") { Ok(artifact) => { if !artifact.warns.is_empty() { - println!("Found warnings: {}", artifact.warns.len()); + println!("{YELLOW}Found {} warnings{RESET}: {}", artifact.warns.len(), self.cfg.input.filename()); artifact.warns.fmt_all_stderr(); } - println!("All checks OK."); + println!("{GREEN}All checks OK{RESET}: {}", self.cfg.input.filename()); if self.cfg.output_dir.is_some() { - dump_decl_er(self.cfg.input.clone(), artifact.object); + dump_decl_er(self.cfg.input.clone(), artifact.object, CheckStatus::Succeed); println!("A declaration file has been generated to __pycache__ directory."); } std::process::exit(0); } Err(artifact) => { if !artifact.warns.is_empty() { - println!("Found warnings: {}", artifact.warns.len()); + println!("{YELLOW}Found {} warnings{RESET}: {}", artifact.warns.len(), self.cfg.input.filename()); artifact.warns.fmt_all_stderr(); } - if artifact.errors.is_empty() { - println!("All checks OK."); - std::process::exit(0); + let code = if artifact.errors.is_empty() { + println!("{GREEN}All checks OK{RESET}: {}", self.cfg.input.filename()); + 0 } else { - println!("Found errors: {}", artifact.errors.len()); + println!("{RED}Found {} errors{RESET}: {}", artifact.errors.len(), self.cfg.input.filename()); artifact.errors.fmt_all_stderr(); - std::process::exit(1); + 1 + }; + // Even if type checking fails, some APIs are still valid, so generate a file + if self.cfg.output_dir.is_some() { + dump_decl_er(self.cfg.input.clone(), artifact.object.unwrap(), CheckStatus::Failed); + println!("A declaration file has been generated to __pycache__ directory."); } + std::process::exit(code); } } }