mirror of https://github.com/mtshiba/pylyzer
support `Class.__call__`
This commit is contained in:
parent
be2bb81d81
commit
a350da5142
|
|
@ -227,7 +227,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "erg_common"
|
name = "erg_common"
|
||||||
version = "0.6.0-beta.2"
|
version = "0.6.0-beta.2"
|
||||||
source = "git+https://github.com/erg-lang/erg?branch=main#d4f8f17e4182bb3f22a3f98a2ca579000bd61a22"
|
source = "git+https://github.com/erg-lang/erg?branch=main#e7d82ecf4ac1b4338e56e44acbc287e28210499c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"hermit-abi",
|
"hermit-abi",
|
||||||
"libc",
|
"libc",
|
||||||
|
|
@ -237,7 +237,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "erg_compiler"
|
name = "erg_compiler"
|
||||||
version = "0.6.0-beta.2"
|
version = "0.6.0-beta.2"
|
||||||
source = "git+https://github.com/erg-lang/erg?branch=main#d4f8f17e4182bb3f22a3f98a2ca579000bd61a22"
|
source = "git+https://github.com/erg-lang/erg?branch=main#e7d82ecf4ac1b4338e56e44acbc287e28210499c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"erg_common",
|
"erg_common",
|
||||||
"erg_parser",
|
"erg_parser",
|
||||||
|
|
@ -246,7 +246,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "erg_parser"
|
name = "erg_parser"
|
||||||
version = "0.6.0-beta.2"
|
version = "0.6.0-beta.2"
|
||||||
source = "git+https://github.com/erg-lang/erg?branch=main#d4f8f17e4182bb3f22a3f98a2ca579000bd61a22"
|
source = "git+https://github.com/erg-lang/erg?branch=main#e7d82ecf4ac1b4338e56e44acbc287e28210499c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"erg_common",
|
"erg_common",
|
||||||
"unicode-xid 0.2.4",
|
"unicode-xid 0.2.4",
|
||||||
|
|
|
||||||
14
README.md
14
README.md
|
|
@ -50,10 +50,24 @@ This language is a transpiled language that targets Python, and has a static typ
|
||||||
|
|
||||||
pylyzer converts Python ASTs to Erg ASTs and passes them to Erg's type checker. It then displays the results with appropriate modifications.
|
pylyzer converts Python ASTs to Erg ASTs and passes them to Erg's type checker. It then displays the results with appropriate modifications.
|
||||||
|
|
||||||
|
## Limitation
|
||||||
|
|
||||||
|
* pylyzer's type inspector only assumes (potentially) statically typed code, so you cannot use `exec`, etc.
|
||||||
|
|
||||||
|
* Type checking of compound types such as Union types is not supported yet (will be implemented soon).
|
||||||
|
|
||||||
## TODOs
|
## TODOs
|
||||||
|
|
||||||
* [x] type checking
|
* [x] type checking
|
||||||
|
* [x] variable
|
||||||
|
* [x] operator
|
||||||
|
* [x] function/method
|
||||||
|
* [x] class
|
||||||
* [x] type inferring
|
* [x] type inferring
|
||||||
|
* [x] variable
|
||||||
|
* [x] operator
|
||||||
|
* [x] function/method
|
||||||
|
* [x] class
|
||||||
* [x] builtin modules resolving (partially)
|
* [x] builtin modules resolving (partially)
|
||||||
* [x] local scripts resolving
|
* [x] local scripts resolving
|
||||||
* [ ] local packages resolving
|
* [ ] local packages resolving
|
||||||
|
|
|
||||||
|
|
@ -382,12 +382,13 @@ impl ASTConverter {
|
||||||
// self.x = x
|
// self.x = x
|
||||||
// self.y = y
|
// self.y = y
|
||||||
// ↓
|
// ↓
|
||||||
// {x: Int, y: Int}, .new(x: Int, y: Int) -> Self
|
// {x: Int, y: Int}, .__call__(x: Int, y: Int): Self = .unreachable()
|
||||||
fn extract_init(&self, def: Def) -> Expr {
|
fn extract_init(&self, def: Def) -> (Expr, Def) {
|
||||||
let l_brace = Token::new(TokenKind::LBrace, "{", def.ln_begin().unwrap(), def.col_begin().unwrap());
|
let l_brace = Token::new(TokenKind::LBrace, "{", def.ln_begin().unwrap(), def.col_begin().unwrap());
|
||||||
let r_brace = Token::new(TokenKind::RBrace, "}", def.ln_end().unwrap(), def.col_end().unwrap());
|
let r_brace = Token::new(TokenKind::RBrace, "}", def.ln_end().unwrap(), def.col_end().unwrap());
|
||||||
let Signature::Subr(sig) = def.sig else { unreachable!() };
|
let Signature::Subr(sig) = def.sig else { unreachable!() };
|
||||||
let mut fields = vec![];
|
let mut fields = vec![];
|
||||||
|
let mut params = vec![];
|
||||||
for chunk in def.body.block {
|
for chunk in def.body.block {
|
||||||
#[allow(clippy::single_match)]
|
#[allow(clippy::single_match)]
|
||||||
match chunk {
|
match chunk {
|
||||||
|
|
@ -401,8 +402,11 @@ impl ASTConverter {
|
||||||
} else {
|
} else {
|
||||||
"Never".to_string()
|
"Never".to_string()
|
||||||
};
|
};
|
||||||
let typ = Identifier::public_with_line(DOT, typ_name.into(), attr.obj.ln_begin().unwrap());
|
let typ_ident = Identifier::public_with_line(DOT, typ_name.into(), attr.obj.ln_begin().unwrap());
|
||||||
let typ = Expr::Accessor(Accessor::Ident(typ));
|
let typ_spec = TypeSpec::PreDeclTy(PreDeclTypeSpec::Simple(SimpleTypeSpec::new(typ_ident.clone(), ConstArgs::empty())));
|
||||||
|
let typ_spec = TypeSpecWithOp::new(COLON, typ_spec);
|
||||||
|
params.push(NonDefaultParamSignature::new(ParamPattern::VarName(attr.ident.name.clone()), Some(typ_spec)));
|
||||||
|
let typ = Expr::Accessor(Accessor::Ident(typ_ident));
|
||||||
let sig = Signature::Var(VarSignature::new(VarPattern::Ident(attr.ident), None));
|
let sig = Signature::Var(VarSignature::new(VarPattern::Ident(attr.ident), None));
|
||||||
let body = DefBody::new(EQUAL, Block::new(vec![typ]), DefId(0));
|
let body = DefBody::new(EQUAL, Block::new(vec![typ]), DefId(0));
|
||||||
let field_type_def = Def::new(sig, body);
|
let field_type_def = Def::new(sig, body);
|
||||||
|
|
@ -412,7 +416,17 @@ impl ASTConverter {
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Expr::Record(Record::Normal(NormalRecord::new(l_brace, r_brace, RecordAttrs::new(fields))))
|
let record = Record::Normal(NormalRecord::new(l_brace, r_brace, RecordAttrs::new(fields)));
|
||||||
|
let call_ident = Identifier::new(Some(DOT), VarName::from_static("__call__"));
|
||||||
|
let params = Params::new(params, None, vec![], None);
|
||||||
|
let class_ident = Identifier::public_with_line(DOT, self.namespace.last().unwrap().into(), sig.ln_begin().unwrap());
|
||||||
|
let class_spec = TypeSpec::PreDeclTy(PreDeclTypeSpec::Simple(SimpleTypeSpec::new(class_ident, ConstArgs::empty())));
|
||||||
|
let sig = Signature::Subr(SubrSignature::new(HashSet::new(), call_ident, TypeBoundSpecs::empty(), params, Some(class_spec)));
|
||||||
|
let unreachable_acc = Identifier::new(Some(DOT), VarName::from_static("exit"));
|
||||||
|
let body = Expr::Accessor(Accessor::Ident(unreachable_acc)).call_expr(Args::empty());
|
||||||
|
let body = DefBody::new(EQUAL, Block::new(vec![body]), DefId(0));
|
||||||
|
let def = Def::new(sig, body);
|
||||||
|
(Expr::Record(record), def)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn extract_method(&mut self, body: Vec<Located<StatementType>>) -> (Expr, ClassAttrs) {
|
fn extract_method(&mut self, body: Vec<Located<StatementType>>) -> (Expr, ClassAttrs) {
|
||||||
|
|
@ -423,7 +437,9 @@ impl ASTConverter {
|
||||||
match chunk {
|
match chunk {
|
||||||
Expr::Def(def) => {
|
Expr::Def(def) => {
|
||||||
if def.is_subr() && &def.sig.ident().unwrap().inspect()[..] == "__init__" {
|
if def.is_subr() && &def.sig.ident().unwrap().inspect()[..] == "__init__" {
|
||||||
base_type = self.extract_init(def);
|
let (base_t, call_def) = self.extract_init(def);
|
||||||
|
base_type = base_t;
|
||||||
|
attrs.push(ClassAttr::Def(call_def));
|
||||||
} else {
|
} else {
|
||||||
attrs.push(ClassAttr::Def(def));
|
attrs.push(ClassAttr::Def(def));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
class C:
|
||||||
|
def __init__(x: int):
|
||||||
|
self.x = x
|
||||||
|
def method(self):
|
||||||
|
return self.x
|
||||||
|
|
||||||
|
a = C(1).method() # OK
|
||||||
|
_: int = a + 1
|
||||||
|
b = C("a").method() # ERR
|
||||||
Loading…
Reference in New Issue