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