Skip to content

Commit

Permalink
feat: support @property
Browse files Browse the repository at this point in the history
  • Loading branch information
mtshiba committed Jan 1, 2025
1 parent accd453 commit dedfa84
Show file tree
Hide file tree
Showing 6 changed files with 92 additions and 15 deletions.
20 changes: 10 additions & 10 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"] }
Expand Down
49 changes: 47 additions & 2 deletions crates/py2erg/convert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) => {
Expand All @@ -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;
}
Expand Down Expand Up @@ -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),
Expand Down
11 changes: 11 additions & 0 deletions tests/err/property.py
Original file line number Diff line number Diff line change
@@ -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
11 changes: 11 additions & 0 deletions tests/property.py
Original file line number Diff line number Diff line change
@@ -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
10 changes: 10 additions & 0 deletions tests/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down

0 comments on commit dedfa84

Please sign in to comment.