mirror of https://github.com/mtshiba/pylyzer
feat: support `@property`
This commit is contained in:
parent
accd453a12
commit
dedfa8443b
|
|
@ -150,9 +150,9 @@ checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
|
|||
|
||||
[[package]]
|
||||
name = "els"
|
||||
version = "0.1.63-nightly.0"
|
||||
version = "0.1.63-nightly.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "99d2ae54e13d256ec9a09554249ccc498c31022836c76bc5dc1b11b072f0a753"
|
||||
checksum = "499bf0ea920c33a3b8f905450435135a8fbefc6c06c3b53f2b5c0e66d25367b5"
|
||||
dependencies = [
|
||||
"erg_common",
|
||||
"erg_compiler",
|
||||
|
|
@ -166,9 +166,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "erg_common"
|
||||
version = "0.6.51-nightly.0"
|
||||
version = "0.6.51-nightly.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "abc654d256215d0d1b2ccb5d1e80c9188148dd59714d0a642f5738bf0271197a"
|
||||
checksum = "1d112c6737def3a5ee868510f4ce9ef9be64b2a0bdf8899b24576a1e8521d401"
|
||||
dependencies = [
|
||||
"backtrace-on-stack-overflow",
|
||||
"erg_proc_macros",
|
||||
|
|
@ -179,9 +179,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "erg_compiler"
|
||||
version = "0.6.51-nightly.0"
|
||||
version = "0.6.51-nightly.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "223b817462901cfef987f38c21a18f9637f7f796dbe58a3b51a1e09489fd25be"
|
||||
checksum = "32d241b882842c86c6c3e2aa54c4c8121fdbedd8a15a7b563cf5f7c1c5c0c0bb"
|
||||
dependencies = [
|
||||
"erg_common",
|
||||
"erg_parser",
|
||||
|
|
@ -189,9 +189,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "erg_parser"
|
||||
version = "0.6.51-nightly.0"
|
||||
version = "0.6.51-nightly.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13d9eaf0b3076b05cb7290be98de5c1cbd73ab7a72b090f67d5911e03d062501"
|
||||
checksum = "91efa61b1495ee680394b6f9d98d84535dc8445329f0310734a3e40671a0061a"
|
||||
dependencies = [
|
||||
"erg_common",
|
||||
"erg_proc_macros",
|
||||
|
|
@ -200,9 +200,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "erg_proc_macros"
|
||||
version = "0.6.51-nightly.0"
|
||||
version = "0.6.51-nightly.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e3d2e883cddea276b76add108da8d16276d9d6962a0079561515e701121a3e1a"
|
||||
checksum = "bd78027648c82db68efed1a1789bd84ce09f07ea7630085c9015c4ed6b1a192d"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
|
|
|
|||
|
|
@ -24,9 +24,9 @@ edition = "2021"
|
|||
repository = "https://github.com/mtshiba/pylyzer"
|
||||
|
||||
[workspace.dependencies]
|
||||
erg_common = { version = "0.6.51-nightly.0", features = ["py_compat", "els"] }
|
||||
erg_compiler = { version = "0.6.51-nightly.0", features = ["py_compat", "els"] }
|
||||
els = { version = "0.1.63-nightly.0", features = ["py_compat"] }
|
||||
erg_common = { version = "0.6.51-nightly.1", features = ["py_compat", "els"] }
|
||||
erg_compiler = { version = "0.6.51-nightly.1", features = ["py_compat", "els"] }
|
||||
els = { version = "0.1.63-nightly.1", features = ["py_compat"] }
|
||||
# rustpython-parser = { version = "0.3.0", features = ["all-nodes-with-ranges", "location"] }
|
||||
# rustpython-ast = { version = "0.3.0", features = ["all-nodes-with-ranges", "location"] }
|
||||
rustpython-parser = { git = "https://github.com/RustPython/Parser", version = "0.4.0", features = ["all-nodes-with-ranges", "location"] }
|
||||
|
|
|
|||
|
|
@ -2261,10 +2261,12 @@ impl ASTConverter {
|
|||
&mut self,
|
||||
body: Vec<py_ast::Stmt>,
|
||||
inherit: bool,
|
||||
class_name: Expr,
|
||||
) -> (Option<Expr>, ClassAttrs) {
|
||||
let mut base_type = None;
|
||||
let mut attrs = vec![];
|
||||
let mut init_is_defined = false;
|
||||
let mut call_params_len = None;
|
||||
for stmt in body {
|
||||
match self.convert_statement(stmt, true) {
|
||||
Expr::Def(mut def) => {
|
||||
|
|
@ -2274,12 +2276,55 @@ impl ASTConverter {
|
|||
.insert(Decorator(Expr::static_local("Override")));
|
||||
}
|
||||
}
|
||||
if def
|
||||
if def.sig.decorators().is_some_and(|decos| {
|
||||
decos.iter().any(|deco| {
|
||||
deco.expr()
|
||||
.get_name()
|
||||
.is_some_and(|name| name == "property")
|
||||
})
|
||||
}) {
|
||||
// class Foo:
|
||||
// @property
|
||||
// def foo(self): ...
|
||||
// ↓
|
||||
// class Foo:
|
||||
// def foo_(self): ...
|
||||
// foo = Foo(*[]).foo_()
|
||||
let mut args = Args::empty();
|
||||
if call_params_len.as_ref().is_some_and(|&len| len >= 1) {
|
||||
args.set_var_args(PosArg::new(Expr::List(List::Normal(
|
||||
NormalList::new(
|
||||
Token::dummy(TokenKind::LSqBr, "["),
|
||||
Token::dummy(TokenKind::RSqBr, "]"),
|
||||
Args::empty(),
|
||||
),
|
||||
))));
|
||||
}
|
||||
let instance = class_name.clone().call(args);
|
||||
let name = def.sig.ident().unwrap().clone();
|
||||
def.sig
|
||||
.ident_mut()
|
||||
.unwrap()
|
||||
.name
|
||||
.rename(format!("{} ", name.inspect()).into());
|
||||
let escaped = def.sig.ident().unwrap().clone();
|
||||
let call = Expr::Call(instance).method_call_expr(escaped, Args::empty());
|
||||
let t_spec = def.sig.t_spec_op_mut().cloned();
|
||||
let sig =
|
||||
Signature::Var(VarSignature::new(VarPattern::Ident(name), t_spec));
|
||||
let var_def =
|
||||
Def::new(sig, DefBody::new(EQUAL, Block::new(vec![call]), DefId(0)));
|
||||
attrs.push(ClassAttr::Def(def));
|
||||
attrs.push(ClassAttr::Def(var_def));
|
||||
} else if def
|
||||
.sig
|
||||
.ident()
|
||||
.is_some_and(|id| &id.inspect()[..] == "__init__")
|
||||
{
|
||||
if let Some(call_def) = self.extract_init(&mut base_type, def) {
|
||||
if let Some(params) = call_def.sig.params() {
|
||||
call_params_len = Some(params.len());
|
||||
}
|
||||
attrs.insert(0, ClassAttr::Def(call_def));
|
||||
init_is_defined = true;
|
||||
}
|
||||
|
|
@ -2355,7 +2400,7 @@ impl ASTConverter {
|
|||
TypeSpec::mono(ident.clone())
|
||||
};
|
||||
let class_as_expr = Expr::Accessor(Accessor::Ident(ident));
|
||||
let (base_type, attrs) = self.extract_method(body, inherit);
|
||||
let (base_type, attrs) = self.extract_method(body, inherit, class_as_expr.clone());
|
||||
self.block_id_counter += 1;
|
||||
let methods = Methods::new(
|
||||
DefId(self.block_id_counter),
|
||||
|
|
|
|||
|
|
@ -0,0 +1,11 @@
|
|||
class Foo:
|
||||
x: int
|
||||
def __init__(self, x):
|
||||
self.x = x
|
||||
|
||||
@property
|
||||
def foo(self):
|
||||
return self.x
|
||||
|
||||
f = Foo(1)
|
||||
print(f.foo + "a") # ERR
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
class Foo:
|
||||
x: int
|
||||
def __init__(self, x):
|
||||
self.x = x
|
||||
|
||||
@property
|
||||
def foo(self):
|
||||
return self.x
|
||||
|
||||
f = Foo(1)
|
||||
assert f.foo + 1 == 2
|
||||
|
|
@ -128,6 +128,16 @@ fn exec_projection() -> Result<(), String> {
|
|||
expect("tests/projection.py", 0, 5)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn exec_property() -> Result<(), String> {
|
||||
expect("tests/property.py", 0, 0)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn exec_property_err() -> Result<(), String> {
|
||||
expect("tests/err/property.py", 0, 1)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn exec_pyi() -> Result<(), String> {
|
||||
expect("tests/pyi.py", 0, 5)
|
||||
|
|
|
|||
Loading…
Reference in New Issue