mirror of https://github.com/mtshiba/pylyzer
Add `NameInfo::defined_block_id`
This commit is contained in:
parent
2590cd6ab4
commit
4c99de6125
|
|
@ -0,0 +1,20 @@
|
|||
repos:
|
||||
- repo: local
|
||||
hooks:
|
||||
- id: rustfmt
|
||||
name: rustfmt
|
||||
description: Check if all files follow the rustfmt style
|
||||
entry: cargo fmt --all
|
||||
language: system
|
||||
pass_filenames: false
|
||||
- id: cargo-test
|
||||
name: Cargo test
|
||||
entry: cargo test
|
||||
language: system
|
||||
pass_filenames: false
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v4.3.0
|
||||
hooks:
|
||||
- id: end-of-file-fixer
|
||||
- id: trailing-whitespace
|
||||
- id: check-merge-conflict
|
||||
|
|
@ -206,7 +206,7 @@ checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797"
|
|||
[[package]]
|
||||
name = "els"
|
||||
version = "0.1.13-nightly.0"
|
||||
source = "git+https://github.com/erg-lang/erg-language-server?branch=main#ba96e0d1e86f496600b659c4a3fd70ec215587f3"
|
||||
source = "git+https://github.com/erg-lang/erg-language-server?branch=main#8cef57fb31a5c1505f23041b2720925650f18539"
|
||||
dependencies = [
|
||||
"erg_common",
|
||||
"erg_compiler",
|
||||
|
|
@ -227,7 +227,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "erg_common"
|
||||
version = "0.6.0"
|
||||
source = "git+https://github.com/erg-lang/erg?branch=main#16b50347d4e97b9b193e068a2d5fdba2340771ab"
|
||||
source = "git+https://github.com/erg-lang/erg?branch=main#ee8492eb4205e4ea479d9b7c804a471b61797559"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
|
|
@ -237,7 +237,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "erg_compiler"
|
||||
version = "0.6.0"
|
||||
source = "git+https://github.com/erg-lang/erg?branch=main#16b50347d4e97b9b193e068a2d5fdba2340771ab"
|
||||
source = "git+https://github.com/erg-lang/erg?branch=main#ee8492eb4205e4ea479d9b7c804a471b61797559"
|
||||
dependencies = [
|
||||
"erg_common",
|
||||
"erg_parser",
|
||||
|
|
@ -246,7 +246,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "erg_parser"
|
||||
version = "0.6.0"
|
||||
source = "git+https://github.com/erg-lang/erg?branch=main#16b50347d4e97b9b193e068a2d5fdba2340771ab"
|
||||
source = "git+https://github.com/erg-lang/erg?branch=main#ee8492eb4205e4ea479d9b7c804a471b61797559"
|
||||
dependencies = [
|
||||
"erg_common",
|
||||
"unicode-xid 0.2.4",
|
||||
|
|
@ -716,18 +716,18 @@ checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde"
|
|||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.151"
|
||||
version = "1.0.152"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "97fed41fc1a24994d044e6db6935e69511a1153b52c15eb42493b26fa87feba0"
|
||||
checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.151"
|
||||
version = "1.0.152"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "255abe9a125a985c05190d687b320c12f9b1f0b99445e608c21ba0782c719ad8"
|
||||
checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,6 +1,6 @@
|
|||
use erg_common::switch_lang;
|
||||
use erg_common::config::Input;
|
||||
use erg_common::error::{Location, ErrorCore, ErrorKind, SubMessage};
|
||||
use erg_common::error::{ErrorCore, ErrorKind, Location, SubMessage};
|
||||
use erg_common::switch_lang;
|
||||
use erg_compiler::error::CompileError;
|
||||
|
||||
pub(crate) fn reassign_func_error(
|
||||
|
|
@ -27,11 +27,7 @@ pub(crate) fn reassign_func_error(
|
|||
)
|
||||
}
|
||||
|
||||
pub(crate) fn self_not_found_error(
|
||||
input: Input,
|
||||
loc: Location,
|
||||
caused_by: String,
|
||||
) -> CompileError {
|
||||
pub(crate) fn self_not_found_error(input: Input, loc: Location, caused_by: String) -> CompileError {
|
||||
CompileError::new(
|
||||
ErrorCore::new(
|
||||
vec![SubMessage::only_loc(loc)],
|
||||
|
|
@ -50,11 +46,7 @@ pub(crate) fn self_not_found_error(
|
|||
)
|
||||
}
|
||||
|
||||
pub(crate) fn init_var_error(
|
||||
input: Input,
|
||||
loc: Location,
|
||||
caused_by: String,
|
||||
) -> CompileError {
|
||||
pub(crate) fn init_var_error(input: Input, loc: Location, caused_by: String) -> CompileError {
|
||||
CompileError::new(
|
||||
ErrorCore::new(
|
||||
vec![SubMessage::only_loc(loc)],
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
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_common::log;
|
||||
use erg_compiler::hir::{Expr, HIR};
|
||||
use erg_compiler::ty::HasType;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
|
|
@ -31,7 +31,11 @@ fn escape_type(typ: String) -> 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() };
|
||||
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) => {
|
||||
|
|
@ -55,7 +59,11 @@ pub fn gen_decl_er(hir: HIR, status: CheckStatus) -> DeclFile {
|
|||
|
||||
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() };
|
||||
let mut path = if let Input::File(path) = input {
|
||||
path
|
||||
} else {
|
||||
PathBuf::new()
|
||||
};
|
||||
path.pop();
|
||||
path.push("__pycache__");
|
||||
let pycache_dir = path.as_path();
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
mod convert;
|
||||
mod gen_decl;
|
||||
mod error;
|
||||
mod gen_decl;
|
||||
|
||||
pub use convert::*;
|
||||
pub use gen_decl::*;
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
use erg_common::config::ErgConfig;
|
||||
use erg_common::error::{ErrorCore, ErrorKind, MultiErrorDisplay};
|
||||
use erg_common::style::{BLUE, GREEN, RED, RESET, YELLOW};
|
||||
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};
|
||||
use erg_compiler::artifact::{BuildRunnable, Buildable, CompleteArtifact, IncompleteArtifact};
|
||||
use erg_compiler::context::Context;
|
||||
use erg_compiler::erg_parser::ast::AST;
|
||||
use erg_compiler::error::{CompileErrors, CompileError};
|
||||
use erg_compiler::error::{CompileError, CompileErrors};
|
||||
use erg_compiler::lower::ASTLowerer;
|
||||
use py2erg::{CheckStatus, ShadowingMode};
|
||||
use py2erg::dump_decl_er;
|
||||
use py2erg::{CheckStatus, ShadowingMode};
|
||||
use rustpython_parser::parser;
|
||||
|
||||
use crate::handle_err;
|
||||
|
|
@ -22,13 +22,10 @@ pub struct PythonAnalyzer {
|
|||
impl Runnable for PythonAnalyzer {
|
||||
type Err = CompileError;
|
||||
type Errs = CompileErrors;
|
||||
const NAME: &'static str = "Python Analyzer";
|
||||
const NAME: &'static str = "Python Analyzer";
|
||||
fn new(cfg: ErgConfig) -> Self {
|
||||
let checker = ASTLowerer::new(cfg.clone());
|
||||
Self {
|
||||
checker,
|
||||
cfg,
|
||||
}
|
||||
Self { checker, cfg }
|
||||
}
|
||||
#[inline]
|
||||
fn cfg(&self) -> &ErgConfig {
|
||||
|
|
@ -74,7 +71,11 @@ impl PythonAnalyzer {
|
|||
Runnable::new(cfg)
|
||||
}
|
||||
|
||||
pub fn analyze(&mut self, py_code: String, mode: &str) -> Result<CompleteArtifact, IncompleteArtifact> {
|
||||
pub fn analyze(
|
||||
&mut self,
|
||||
py_code: String,
|
||||
mode: &str,
|
||||
) -> Result<CompleteArtifact, IncompleteArtifact> {
|
||||
let filename = self.cfg.input.filename();
|
||||
let py_program = parser::parse_program(&py_code).map_err(|err| {
|
||||
let core = ErrorCore::new(
|
||||
|
|
@ -82,9 +83,9 @@ impl PythonAnalyzer {
|
|||
err.to_string(),
|
||||
0,
|
||||
ErrorKind::SyntaxError,
|
||||
erg_common::error::Location::Line(err.location.row())
|
||||
erg_common::error::Location::Line(err.location.row()),
|
||||
);
|
||||
let err = CompileError::new(core, self.cfg.input.clone(), "".into());
|
||||
let err = CompileError::new(core, self.cfg.input.clone(), "".into());
|
||||
IncompleteArtifact::new(None, CompileErrors::from(err), CompileErrors::empty())
|
||||
})?;
|
||||
let shadowing = if cfg!(feature = "debug") {
|
||||
|
|
@ -99,11 +100,16 @@ impl PythonAnalyzer {
|
|||
match self.checker.lower(erg_ast, mode) {
|
||||
Ok(mut artifact) => {
|
||||
artifact.warns.extend(warns);
|
||||
artifact.warns = handle_err::filter_errors(self.checker.get_mod_ctx(), artifact.warns);
|
||||
artifact.warns =
|
||||
handle_err::filter_errors(self.checker.get_mod_ctx(), artifact.warns);
|
||||
if errors.is_empty() {
|
||||
Ok(artifact)
|
||||
} else {
|
||||
Err(IncompleteArtifact::new(Some(artifact.object), errors, artifact.warns))
|
||||
Err(IncompleteArtifact::new(
|
||||
Some(artifact.object),
|
||||
errors,
|
||||
artifact.warns,
|
||||
))
|
||||
}
|
||||
}
|
||||
Err(iart) => {
|
||||
|
|
@ -123,32 +129,52 @@ impl PythonAnalyzer {
|
|||
match self.analyze(py_code, "exec") {
|
||||
Ok(artifact) => {
|
||||
if !artifact.warns.is_empty() {
|
||||
println!("{YELLOW}Found {} warnings{RESET}: {}", artifact.warns.len(), self.cfg.input.filename());
|
||||
println!(
|
||||
"{YELLOW}Found {} warnings{RESET}: {}",
|
||||
artifact.warns.len(),
|
||||
self.cfg.input.filename()
|
||||
);
|
||||
artifact.warns.fmt_all_stderr();
|
||||
}
|
||||
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, CheckStatus::Succeed);
|
||||
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!("{YELLOW}Found {} warnings{RESET}: {}", artifact.warns.len(), self.cfg.input.filename());
|
||||
println!(
|
||||
"{YELLOW}Found {} warnings{RESET}: {}",
|
||||
artifact.warns.len(),
|
||||
self.cfg.input.filename()
|
||||
);
|
||||
artifact.warns.fmt_all_stderr();
|
||||
}
|
||||
let code = if artifact.errors.is_empty() {
|
||||
println!("{GREEN}All checks OK{RESET}: {}", self.cfg.input.filename());
|
||||
0
|
||||
} else {
|
||||
println!("{RED}Found {} errors{RESET}: {}", artifact.errors.len(), self.cfg.input.filename());
|
||||
println!(
|
||||
"{RED}Found {} errors{RESET}: {}",
|
||||
artifact.errors.len(),
|
||||
self.cfg.input.filename()
|
||||
);
|
||||
artifact.errors.fmt_all_stderr();
|
||||
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);
|
||||
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);
|
||||
|
|
|
|||
|
|
@ -1,11 +1,14 @@
|
|||
use erg_common::error::ErrorKind;
|
||||
use erg_common::log;
|
||||
// use erg_common::style::{remove_style, StyledString, Color};
|
||||
use erg_compiler::error::{CompileErrors, CompileError};
|
||||
use erg_compiler::context::Context;
|
||||
use erg_compiler::error::{CompileError, CompileErrors};
|
||||
|
||||
pub(crate) fn filter_errors(ctx: &Context, errors: CompileErrors) -> CompileErrors {
|
||||
errors.into_iter().filter_map(|error| filter_error(ctx, error)).collect()
|
||||
errors
|
||||
.into_iter()
|
||||
.filter_map(|error| filter_error(ctx, error))
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn filter_error(_ctx: &Context, error: CompileError) -> Option<CompileError> {
|
||||
|
|
@ -18,7 +21,10 @@ fn filter_error(_ctx: &Context, error: CompileError) -> Option<CompileError> {
|
|||
ErrorKind::VisibilityError => None,
|
||||
// exclude doc strings
|
||||
ErrorKind::UnusedWarning => {
|
||||
let code = error.input.reread_lines(error.core.loc.ln_begin().unwrap(), error.core.loc.ln_end().unwrap());
|
||||
let code = error.input.reread_lines(
|
||||
error.core.loc.ln_begin().unwrap(),
|
||||
error.core.loc.ln_end().unwrap(),
|
||||
);
|
||||
if code[0].trim().starts_with("\"\"\"") {
|
||||
None
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
mod handle_err;
|
||||
mod analyze;
|
||||
mod handle_err;
|
||||
|
||||
use std::env;
|
||||
use std::path::PathBuf;
|
||||
|
|
@ -7,13 +7,16 @@ use std::str::FromStr;
|
|||
|
||||
use analyze::PythonAnalyzer;
|
||||
use els::Server;
|
||||
use erg_common::config::{Input, ErgConfig};
|
||||
use erg_common::config::{ErgConfig, Input};
|
||||
use erg_common::spawn::exec_new_thread;
|
||||
|
||||
pub fn parse_args() -> ErgConfig {
|
||||
let mut args = env::args();
|
||||
args.next(); // "pylyzer"
|
||||
let mut cfg = ErgConfig{ python_compatible_mode: true, ..ErgConfig::default() };
|
||||
let mut cfg = ErgConfig {
|
||||
python_compatible_mode: true,
|
||||
..ErgConfig::default()
|
||||
};
|
||||
while let Some(arg) = args.next() {
|
||||
match &arg[..] {
|
||||
"--" => {
|
||||
|
|
|
|||
|
|
@ -15,8 +15,14 @@ for i in [1, 2, 3]:
|
|||
j = i + "aa"
|
||||
print(j)
|
||||
|
||||
i: int # OK
|
||||
i = 1
|
||||
i: str # ERR
|
||||
i = "aa" if True else "bb"
|
||||
i: str # OK
|
||||
|
||||
while "aaa": # ERR
|
||||
print("invalid")
|
||||
i += 1 # ERR
|
||||
break
|
||||
|
||||
class C:
|
||||
|
|
@ -27,9 +33,3 @@ print(dic["c"]) # ERR
|
|||
|
||||
a = [1, 2, 3]
|
||||
print(a[4]) # ERR
|
||||
|
||||
i: int # OK
|
||||
i = 1
|
||||
i: str # ERR
|
||||
i = "aa" if True else "bb"
|
||||
i: str # OK
|
||||
|
|
@ -1,12 +1,16 @@
|
|||
use std::path::PathBuf;
|
||||
|
||||
use erg_common::traits::Stream;
|
||||
use erg_common::config::{ErgConfig, Input};
|
||||
use erg_compiler::artifact::{IncompleteArtifact, CompleteArtifact};
|
||||
use erg_common::traits::Stream;
|
||||
use erg_compiler::artifact::{CompleteArtifact, IncompleteArtifact};
|
||||
use pylyzer::PythonAnalyzer;
|
||||
|
||||
pub fn exec_analyzer(file_path: &'static str) -> Result<CompleteArtifact, IncompleteArtifact> {
|
||||
let cfg = ErgConfig { python_compatible_mode: true, input: Input::File(PathBuf::from(file_path)), ..Default::default() };
|
||||
let cfg = ErgConfig {
|
||||
python_compatible_mode: true,
|
||||
input: Input::File(PathBuf::from(file_path)),
|
||||
..Default::default()
|
||||
};
|
||||
let mut analyzer = PythonAnalyzer::new(cfg);
|
||||
let py_code = analyzer.cfg.input.read();
|
||||
analyzer.analyze(py_code, "exec")
|
||||
|
|
@ -27,7 +31,7 @@ pub fn expect(file_path: &'static str, warns: usize, errors: usize) {
|
|||
|
||||
#[test]
|
||||
fn exec_test() {
|
||||
expect("tests/test.py", 0, 9);
|
||||
expect("tests/test.py", 0, 10);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
|||
Loading…
Reference in New Issue