forked from M-Labs/nac3
start to handle base inheritance methods, fields
This commit is contained in:
parent
6279dbb589
commit
9cb07e6f04
|
@ -10,7 +10,7 @@ use itertools::Itertools;
|
||||||
use parking_lot::{Mutex, RwLock};
|
use parking_lot::{Mutex, RwLock};
|
||||||
use rustpython_parser::ast::{self, Stmt};
|
use rustpython_parser::ast::{self, Stmt};
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
|
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)]
|
||||||
pub struct DefinitionId(pub usize);
|
pub struct DefinitionId(pub usize);
|
||||||
|
|
||||||
pub enum TopLevelDef {
|
pub enum TopLevelDef {
|
||||||
|
@ -462,9 +462,9 @@ impl TopLevelComposer {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// step 3, class fields and methods
|
/// step 3, class fields and methods
|
||||||
// FIXME: need analyze base classes here
|
// FIXME: analyze base classes here
|
||||||
// FIXME: how to deal with self type
|
// FIXME: deal with self type
|
||||||
// FIXME: how to prevent cycles
|
// NOTE: prevent cycles only roughly done
|
||||||
fn analyze_top_level_class_fields_methods(&mut self) -> Result<(), String> {
|
fn analyze_top_level_class_fields_methods(&mut self) -> Result<(), String> {
|
||||||
let mut def_ast_list = self.definition_ast_list.write();
|
let mut def_ast_list = self.definition_ast_list.write();
|
||||||
let converted_top_level = &self.to_top_level_context();
|
let converted_top_level = &self.to_top_level_context();
|
||||||
|
@ -472,20 +472,27 @@ impl TopLevelComposer {
|
||||||
let to_be_analyzed_class = &mut self.to_be_analyzed_class;
|
let to_be_analyzed_class = &mut self.to_be_analyzed_class;
|
||||||
let unifier = &mut self.unifier;
|
let unifier = &mut self.unifier;
|
||||||
|
|
||||||
|
// NOTE: roughly prevent infinite loop
|
||||||
|
let mut max_iter = to_be_analyzed_class.len() * 4;
|
||||||
'class: loop {
|
'class: loop {
|
||||||
if to_be_analyzed_class.is_empty() {
|
if to_be_analyzed_class.is_empty() && { max_iter -= 1; max_iter > 0 } {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
let class_ind = to_be_analyzed_class.remove(0).0;
|
let class_ind = to_be_analyzed_class.remove(0).0;
|
||||||
let (class_name, class_body, class_resolver) = {
|
let (class_name,
|
||||||
|
class_body_ast,
|
||||||
|
class_bases_ast,
|
||||||
|
class_resolver,
|
||||||
|
class_ancestors
|
||||||
|
) = {
|
||||||
let (class_def, class_ast) = &mut def_ast_list[class_ind];
|
let (class_def, class_ast) = &mut def_ast_list[class_ind];
|
||||||
if let Some(ast::Located {
|
if let Some(ast::Located {
|
||||||
node: ast::StmtKind::ClassDef { name, body, .. }, ..
|
node: ast::StmtKind::ClassDef { name, body, bases, .. }, ..
|
||||||
}) = class_ast.as_ref()
|
}) = class_ast.as_ref()
|
||||||
{
|
{
|
||||||
if let TopLevelDef::Class { resolver, .. } = class_def.write().deref() {
|
if let TopLevelDef::Class { resolver, ancestors, .. } = class_def.write().deref() {
|
||||||
(name, body, resolver.as_ref().unwrap().clone())
|
(name, body, bases, resolver.as_ref().unwrap().clone(), ancestors.clone())
|
||||||
} else {
|
} else {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
|
@ -494,11 +501,35 @@ impl TopLevelComposer {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let all_base_class_analyzed = {
|
||||||
|
let not_yet_analyzed = to_be_analyzed_class.clone().into_iter().collect::<HashSet<_>>();
|
||||||
|
let base = class_ancestors.clone().into_iter().collect::<HashSet<_>>();
|
||||||
|
let intersection = not_yet_analyzed.intersection(&base).collect_vec();
|
||||||
|
intersection.is_empty()
|
||||||
|
};
|
||||||
|
if !all_base_class_analyzed {
|
||||||
|
to_be_analyzed_class.push(DefinitionId(class_ind));
|
||||||
|
continue 'class;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the bases type, can directly do this since it
|
||||||
|
// already pass the check in the previous stages
|
||||||
|
let class_bases_ty = class_bases_ast
|
||||||
|
.iter()
|
||||||
|
.filter_map(|x| {
|
||||||
|
class_resolver.as_ref().lock().parse_type_annotation(
|
||||||
|
converted_top_level,
|
||||||
|
unifier.borrow_mut(),
|
||||||
|
primitives,
|
||||||
|
x).ok()
|
||||||
|
})
|
||||||
|
.collect_vec();
|
||||||
|
|
||||||
// need these vectors to check re-defining methods, class fields
|
// need these vectors to check re-defining methods, class fields
|
||||||
// and store the parsed result in case some method cannot be typed for now
|
// and store the parsed result in case some method cannot be typed for now
|
||||||
let mut class_methods_parsing_result: Vec<(String, Type, DefinitionId)> = vec![];
|
let mut class_methods_parsing_result: Vec<(String, Type, DefinitionId)> = vec![];
|
||||||
let mut class_fields_parsing_result: Vec<(String, Type)> = vec![];
|
let mut class_fields_parsing_result: Vec<(String, Type)> = vec![];
|
||||||
for b in class_body {
|
for b in class_body_ast {
|
||||||
if let ast::StmtKind::FunctionDef {
|
if let ast::StmtKind::FunctionDef {
|
||||||
args: method_args_ast,
|
args: method_args_ast,
|
||||||
body: method_body_ast,
|
body: method_body_ast,
|
||||||
|
|
Loading…
Reference in New Issue