mirror of https://github.com/mtshiba/pylyzer
feat: support inheritance
This commit is contained in:
parent
bd90b57c58
commit
0d2bfb294f
|
|
@ -252,8 +252,9 @@ checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91"
|
|||
|
||||
[[package]]
|
||||
name = "els"
|
||||
version = "0.1.19-nightly.2"
|
||||
source = "git+https://github.com/erg-lang/erg?branch=main#228a74d29d83907ffcb62dd849036200bd167c06"
|
||||
version = "0.1.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "94694dcfb56e12207fb27ff73158b9fb759497485790c71de98aa4b0136c72f6"
|
||||
dependencies = [
|
||||
"erg_common",
|
||||
"erg_compiler",
|
||||
|
|
@ -273,8 +274,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "erg_common"
|
||||
version = "0.6.7-nightly.2"
|
||||
source = "git+https://github.com/erg-lang/erg?branch=main#228a74d29d83907ffcb62dd849036200bd167c06"
|
||||
version = "0.6.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "88c9d058b405901b41dbc282f9927fd5295dc46c50fa2f8fc75f2c3d7783ac77"
|
||||
dependencies = [
|
||||
"backtrace-on-stack-overflow",
|
||||
"hermit-abi",
|
||||
|
|
@ -284,8 +286,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "erg_compiler"
|
||||
version = "0.6.7-nightly.2"
|
||||
source = "git+https://github.com/erg-lang/erg?branch=main#228a74d29d83907ffcb62dd849036200bd167c06"
|
||||
version = "0.6.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ffb25a8403805eb864bb3f56c920dfafadca30bf2ff8be5c733d3449e16ae224"
|
||||
dependencies = [
|
||||
"erg_common",
|
||||
"erg_parser",
|
||||
|
|
@ -293,8 +296,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "erg_parser"
|
||||
version = "0.6.7-nightly.2"
|
||||
source = "git+https://github.com/erg-lang/erg?branch=main#228a74d29d83907ffcb62dd849036200bd167c06"
|
||||
version = "0.6.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ea28285bc487cc9807beafd63664c0903bf8bca86c5ac692dd8a3b783c03bdb7"
|
||||
dependencies = [
|
||||
"erg_common",
|
||||
"unicode-xid 0.2.4",
|
||||
|
|
|
|||
12
Cargo.toml
12
Cargo.toml
|
|
@ -22,13 +22,13 @@ edition = "2021"
|
|||
repository = "https://github.com/mtshiba/pylyzer"
|
||||
|
||||
[workspace.dependencies]
|
||||
# erg_common = { version = "0.6.7-nightly.2", features = ["py_compatible", "els"] }
|
||||
# erg_compiler = { version = "0.6.7-nightly.2", features = ["py_compatible", "els"] }
|
||||
# els = { version = "0.1.19-nightly.2", features = ["py_compatible"] }
|
||||
erg_common = { version = "0.6.7", features = ["py_compatible", "els"] }
|
||||
erg_compiler = { version = "0.6.7", features = ["py_compatible", "els"] }
|
||||
els = { version = "0.1.19", features = ["py_compatible"] }
|
||||
rustpython-parser = "0.1.2"
|
||||
erg_compiler = { git = "https://github.com/erg-lang/erg", branch = "main", features = ["py_compatible", "els"] }
|
||||
erg_common = { git = "https://github.com/erg-lang/erg", branch = "main", features = ["py_compatible", "els"] }
|
||||
els = { git = "https://github.com/erg-lang/erg", branch = "main", features = ["py_compatible"] }
|
||||
# erg_compiler = { git = "https://github.com/erg-lang/erg", branch = "main", features = ["py_compatible", "els"] }
|
||||
# erg_common = { git = "https://github.com/erg-lang/erg", branch = "main", features = ["py_compatible", "els"] }
|
||||
# els = { git = "https://github.com/erg-lang/erg", branch = "main", features = ["py_compatible"] }
|
||||
|
||||
[features]
|
||||
debug = ["erg_compiler/debug", "erg_common/debug", "py2erg/debug"]
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
<a href="https://github.com/mtshiba/pylyzer/releases"><img alt="Build status" src="https://img.shields.io/github/v/release/mtshiba/pylyzer.svg"></a>
|
||||
<a href="https://github.com/mtshiba/pylyzer/actions/workflows/rust.yml"><img alt="Build status" src="https://github.com/mtshiba/pylyzer/actions/workflows/rust.yml/badge.svg"></a>
|
||||
|
||||
`pylyzer` is a static code analyzer / language server for Python written in Rust.
|
||||
`pylyzer` is a static code analyzer / language server for Python, written in Rust.
|
||||
|
||||
## Installation
|
||||
|
||||
|
|
@ -20,8 +20,7 @@ cargo install pylyzer
|
|||
pip install pylyzer
|
||||
```
|
||||
|
||||
If installed this way, type resolution for the standard libraries is not available.
|
||||
If you want to use it, you need to [install Erg](https://github.com/mtshiba/ergup).
|
||||
If installed this way, you also need to [install Erg](https://github.com/mtshiba/ergup).
|
||||
|
||||
```bash
|
||||
curl -L https://github.com/mtshiba/ergup/raw/main/ergup.py | python3
|
||||
|
|
|
|||
|
|
@ -1019,7 +1019,7 @@ impl ASTConverter {
|
|||
ConstArgs::empty(),
|
||||
)));
|
||||
let sig = Signature::Subr(SubrSignature::new(
|
||||
HashSet::new(),
|
||||
set! { Decorator(Expr::static_local("Override")) },
|
||||
call_ident,
|
||||
TypeBoundSpecs::empty(),
|
||||
params,
|
||||
|
|
@ -1046,7 +1046,7 @@ impl ASTConverter {
|
|||
ConstArgs::empty(),
|
||||
)));
|
||||
let sig = Signature::Subr(SubrSignature::new(
|
||||
HashSet::new(),
|
||||
set! { Decorator(Expr::static_local("Override")) },
|
||||
call_ident,
|
||||
TypeBoundSpecs::empty(),
|
||||
params,
|
||||
|
|
@ -1059,13 +1059,23 @@ impl ASTConverter {
|
|||
Def::new(sig, body)
|
||||
}
|
||||
|
||||
fn extract_method(&mut self, body: Vec<Located<StatementType>>) -> (Option<Expr>, ClassAttrs) {
|
||||
fn extract_method(
|
||||
&mut self,
|
||||
body: Vec<Located<StatementType>>,
|
||||
inherit: bool,
|
||||
) -> (Option<Expr>, ClassAttrs) {
|
||||
let mut base_type = None;
|
||||
let mut attrs = vec![];
|
||||
let mut init_is_defined = false;
|
||||
for stmt in body {
|
||||
match self.convert_statement(stmt, true) {
|
||||
Expr::Def(def) => {
|
||||
Expr::Def(mut def) => {
|
||||
if inherit {
|
||||
if let Signature::Subr(subr) = &mut def.sig {
|
||||
subr.decorators
|
||||
.insert(Decorator(Expr::static_local("Override")));
|
||||
}
|
||||
}
|
||||
if def
|
||||
.sig
|
||||
.ident()
|
||||
|
|
@ -1124,7 +1134,7 @@ impl ASTConverter {
|
|||
_other => {} // TODO:
|
||||
}
|
||||
}
|
||||
if !init_is_defined {
|
||||
if !init_is_defined && !inherit {
|
||||
attrs.insert(0, ClassAttr::Def(self.gen_default_init(0)));
|
||||
}
|
||||
(base_type, ClassAttrs::new(attrs))
|
||||
|
|
@ -1134,13 +1144,14 @@ impl ASTConverter {
|
|||
&mut self,
|
||||
ident: Identifier,
|
||||
body: Vec<Located<StatementType>>,
|
||||
inherit: bool,
|
||||
) -> (Option<Expr>, Vec<Methods>) {
|
||||
let class = TypeSpec::PreDeclTy(PreDeclTypeSpec::Simple(SimpleTypeSpec::new(
|
||||
ident.clone(),
|
||||
ConstArgs::empty(),
|
||||
)));
|
||||
let class_as_expr = Expr::Accessor(Accessor::Ident(ident));
|
||||
let (base_type, attrs) = self.extract_method(body);
|
||||
let (base_type, attrs) = self.extract_method(body, inherit);
|
||||
let methods = Methods::new(class, class_as_expr, VisModifierSpec::Public(DOT), attrs);
|
||||
(base_type, vec![methods])
|
||||
}
|
||||
|
|
@ -1205,6 +1216,13 @@ impl ASTConverter {
|
|||
/// ```erg
|
||||
/// Foo = Inheritable Class()
|
||||
/// ```
|
||||
/// ```python
|
||||
/// class Foo(Bar): pass
|
||||
/// ```
|
||||
/// ↓
|
||||
/// ```erg
|
||||
/// Foo = Inherit Bar
|
||||
/// ```
|
||||
fn convert_classdef(
|
||||
&mut self,
|
||||
name: String,
|
||||
|
|
@ -1217,16 +1235,29 @@ impl ASTConverter {
|
|||
.into_iter()
|
||||
.map(|deco| self.convert_expr(deco))
|
||||
.collect::<Vec<_>>();
|
||||
let _bases = bases
|
||||
let mut bases = bases
|
||||
.into_iter()
|
||||
.map(|base| self.convert_expr(base))
|
||||
.collect::<Vec<_>>();
|
||||
let inherit = !bases.is_empty();
|
||||
self.register_name_info(&name, NameKind::Class);
|
||||
let class_name_loc = PyLocation::new(loc.row(), loc.column() + 6);
|
||||
let ident = self.convert_ident(name, class_name_loc);
|
||||
let sig = Signature::Var(VarSignature::new(VarPattern::Ident(ident.clone()), None));
|
||||
self.namespace.push(ident.inspect().to_string());
|
||||
let (base_type, methods) = self.extract_method_list(ident, body);
|
||||
let (base_type, methods) = self.extract_method_list(ident, body, inherit);
|
||||
let classdef = if inherit {
|
||||
// TODO: multiple inheritance
|
||||
let pos_args = vec![PosArg::new(bases.remove(0))];
|
||||
let args = Args::pos_only(pos_args, None);
|
||||
let inherit_acc = Expr::Accessor(Accessor::Ident(
|
||||
self.convert_ident("Inherit".to_string(), loc),
|
||||
));
|
||||
let inherit_call = inherit_acc.call_expr(args);
|
||||
let body = DefBody::new(EQUAL, Block::new(vec![inherit_call]), DefId(0));
|
||||
let def = Def::new(sig, body);
|
||||
ClassDef::new(def, methods)
|
||||
} else {
|
||||
let pos_args = if let Some(base) = base_type {
|
||||
vec![PosArg::new(base)]
|
||||
} else {
|
||||
|
|
@ -1244,7 +1275,8 @@ impl ASTConverter {
|
|||
inheritable_acc.call_expr(Args::pos_only(vec![PosArg::new(class_call)], None));
|
||||
let body = DefBody::new(EQUAL, Block::new(vec![inheritable_call]), DefId(0));
|
||||
let def = Def::new(sig, body);
|
||||
let classdef = ClassDef::new(def, methods);
|
||||
ClassDef::new(def, methods)
|
||||
};
|
||||
self.namespace.pop();
|
||||
Expr::ClassDef(classdef)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,11 +36,19 @@ class D:
|
|||
return D(self.c - other.x)
|
||||
def __neg__(self):
|
||||
return D(-self.c)
|
||||
def __gt__(self, other: D):
|
||||
return self.c > other.c
|
||||
def __init__(self, c):
|
||||
self.c = c
|
||||
|
||||
class E(D):
|
||||
def __add__(self, other: E):
|
||||
return E(self.c + other.c)
|
||||
|
||||
c1 = D(1).c + 1
|
||||
d = D(1) + D(2)
|
||||
err = C(1, 2) + D(1) # ERR
|
||||
ok = D(1) - C(1, 2) # OK
|
||||
assert D(1) > D(0)
|
||||
c = -d # OK
|
||||
e = E(1)
|
||||
|
|
|
|||
Loading…
Reference in New Issue