diff --git a/Cargo.lock b/Cargo.lock
index c85aee3..652763d 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -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",
diff --git a/Cargo.toml b/Cargo.toml
index 6474449..f14d6a3 100644
--- a/Cargo.toml
+++ b/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"]
diff --git a/README.md b/README.md
index d679d01..d012ab7 100644
--- a/README.md
+++ b/README.md
@@ -4,7 +4,7 @@
-`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
diff --git a/crates/py2erg/convert.rs b/crates/py2erg/convert.rs
index 7e4cd63..78bf1ce 100644
--- a/crates/py2erg/convert.rs
+++ b/crates/py2erg/convert.rs
@@ -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>) -> (Option, ClassAttrs) {
+ fn extract_method(
+ &mut self,
+ body: Vec>,
+ inherit: bool,
+ ) -> (Option, 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>,
+ inherit: bool,
) -> (Option, Vec) {
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,34 +1235,48 @@ impl ASTConverter {
.into_iter()
.map(|deco| self.convert_expr(deco))
.collect::>();
- let _bases = bases
+ let mut bases = bases
.into_iter()
.map(|base| self.convert_expr(base))
.collect::>();
+ 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 pos_args = if let Some(base) = base_type {
- vec![PosArg::new(base)]
+ 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 {
- 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();
Expr::ClassDef(classdef)
}
diff --git a/tests/class.py b/tests/class.py
index c73515a..0ec9174 100644
--- a/tests/class.py
+++ b/tests/class.py
@@ -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)