forked from M-Labs/nac3
partially parsed class methods nad fields
This commit is contained in:
parent
eb814dd8c3
commit
79ce13722a
|
@ -5,6 +5,7 @@ use super::typecheck::type_inferencer::PrimitiveStore;
|
||||||
use super::typecheck::typedef::{SharedUnifier, Type, TypeEnum, Unifier};
|
use super::typecheck::typedef::{SharedUnifier, Type, TypeEnum, Unifier};
|
||||||
use crate::symbol_resolver::SymbolResolver;
|
use crate::symbol_resolver::SymbolResolver;
|
||||||
use crate::typecheck::typedef::{FunSignature, FuncArg};
|
use crate::typecheck::typedef::{FunSignature, FuncArg};
|
||||||
|
use itertools::chain;
|
||||||
use parking_lot::{Mutex, RwLock};
|
use parking_lot::{Mutex, RwLock};
|
||||||
use rustpython_parser::ast::{self, Stmt};
|
use rustpython_parser::ast::{self, Stmt};
|
||||||
|
|
||||||
|
@ -163,6 +164,7 @@ impl TopLevelComposer {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// already include the definition_id of itself inside the ancestors vector
|
/// already include the definition_id of itself inside the ancestors vector
|
||||||
|
/// when first regitering, the type_vars, fields, methods, ancestors are invalid
|
||||||
pub fn make_top_level_class_def(
|
pub fn make_top_level_class_def(
|
||||||
index: usize,
|
index: usize,
|
||||||
resolver: Option<Arc<Mutex<dyn SymbolResolver + Send + Sync>>>,
|
resolver: Option<Arc<Mutex<dyn SymbolResolver + Send + Sync>>>,
|
||||||
|
@ -177,6 +179,7 @@ impl TopLevelComposer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// when first registering, the type is a invalid value
|
||||||
pub fn make_top_level_function_def(
|
pub fn make_top_level_function_def(
|
||||||
name: String,
|
name: String,
|
||||||
ty: Type,
|
ty: Type,
|
||||||
|
@ -463,7 +466,7 @@ impl TopLevelComposer {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// step 3, class_fields
|
/// step 3, class fields and methods
|
||||||
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_list = self.definition_list.write();
|
let mut def_list = self.definition_list.write();
|
||||||
let ast_list = self.ast_list.read();
|
let ast_list = self.ast_list.read();
|
||||||
|
@ -472,17 +475,62 @@ impl TopLevelComposer {
|
||||||
let mut to_be_analyzed_class = self.to_be_analyzed_class.write();
|
let mut to_be_analyzed_class = self.to_be_analyzed_class.write();
|
||||||
|
|
||||||
while !to_be_analyzed_class.is_empty() {
|
while !to_be_analyzed_class.is_empty() {
|
||||||
let ind = to_be_analyzed_class.remove(0).0;
|
let class_ind = to_be_analyzed_class.remove(0).0;
|
||||||
let (class_def, class_ast) = (
|
let (class_name, class_body) = {
|
||||||
&mut def_list[ind], &ast_list[ind]
|
let class_ast = &ast_list[class_ind];
|
||||||
);
|
if let Some(
|
||||||
|
ast::Located { node:
|
||||||
|
ast::StmtKind::ClassDef {
|
||||||
|
name,
|
||||||
|
body,
|
||||||
|
..
|
||||||
|
},
|
||||||
|
..
|
||||||
|
}
|
||||||
|
) = class_ast {
|
||||||
|
(name, body)
|
||||||
|
} else { unreachable!("should be class def ast") }
|
||||||
|
};
|
||||||
|
|
||||||
|
let class_methods_parsing_result: Vec<(String, Type, DefinitionId)> = Default::default();
|
||||||
|
let class_fields_parsing_result: Vec<(String, Type)> = Default::default();
|
||||||
|
for b in class_body {
|
||||||
|
if let ast::StmtKind::FunctionDef {
|
||||||
|
args: method_args_ast,
|
||||||
|
body: method_body_ast,
|
||||||
|
name: method_name,
|
||||||
|
returns: method_returns_ast,
|
||||||
|
..
|
||||||
|
} = &b.node {
|
||||||
|
let (class_def, method_def) = {
|
||||||
|
// unwrap should not fail
|
||||||
|
let method_ind = class_method_to_def_id
|
||||||
|
.get(&Self::name_mangling(
|
||||||
|
class_name.into(),
|
||||||
|
method_name)
|
||||||
|
).unwrap().0;
|
||||||
|
|
||||||
|
// split the def_list to two parts to get the
|
||||||
|
// mutable reference to both the method and the class
|
||||||
|
assert_ne!(method_ind, class_ind);
|
||||||
|
let min_ind = (if method_ind > class_ind { class_ind } else { method_ind }) + 1;
|
||||||
|
let (head_slice,
|
||||||
|
tail_slice
|
||||||
|
) = def_list.split_at_mut(min_ind);
|
||||||
|
let (new_method_ind, new_class_ind) = (
|
||||||
|
if method_ind >= min_ind { method_ind - min_ind } else { method_ind },
|
||||||
|
if class_ind >= min_ind { class_ind - min_ind } else { class_ind }
|
||||||
|
);
|
||||||
|
if new_class_ind == class_ind {
|
||||||
|
(&mut head_slice[new_class_ind], &mut tail_slice[new_method_ind])
|
||||||
|
} else {
|
||||||
|
(&mut tail_slice[new_class_ind], &mut head_slice[new_method_ind])
|
||||||
|
}
|
||||||
|
};
|
||||||
let (
|
let (
|
||||||
class_name,
|
|
||||||
class_fields,
|
class_fields,
|
||||||
class_methods,
|
class_methods,
|
||||||
class_resolver,
|
class_resolver
|
||||||
class_body
|
|
||||||
) = {
|
) = {
|
||||||
if let TopLevelDef::Class {
|
if let TopLevelDef::Class {
|
||||||
resolver,
|
resolver,
|
||||||
|
@ -490,50 +538,91 @@ impl TopLevelComposer {
|
||||||
methods,
|
methods,
|
||||||
..
|
..
|
||||||
} = class_def.get_mut() {
|
} = class_def.get_mut() {
|
||||||
if let Some(ast::Located {node: ast::StmtKind::ClassDef {
|
(fields, methods, resolver)
|
||||||
name,
|
} else { unreachable!("must be class def here") }
|
||||||
body,
|
|
||||||
..
|
|
||||||
}, .. }) = class_ast {
|
|
||||||
(name, fields, methods, resolver, body)
|
|
||||||
} else { unreachable!("must be both class") }
|
|
||||||
} else {
|
|
||||||
to_be_analyzed_class.push(DefinitionId(ind));
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
for b in class_body {
|
|
||||||
if let ast::StmtKind::FunctionDef {
|
|
||||||
args: func_args,
|
|
||||||
body: func_body,
|
|
||||||
name: func_name,
|
|
||||||
returns: func_returns,
|
|
||||||
..
|
|
||||||
} = &b.node {
|
|
||||||
// unwrap should not fail
|
|
||||||
let method_def_id =
|
|
||||||
class_method_to_def_id
|
|
||||||
.get(&Self::name_mangling(
|
|
||||||
class_name.into(),
|
|
||||||
func_name)
|
|
||||||
).unwrap();
|
|
||||||
let method_def = def_list[method_def_id.0].write();
|
|
||||||
let method_ty = method_def.get_function_type()?;
|
|
||||||
let method_signature = unifier.get_ty(method_ty);
|
|
||||||
|
|
||||||
if let TypeEnum::TFunc(sig) = method_signature.as_ref() {
|
let arg_tys = method_args_ast
|
||||||
let mut sig = &mut *sig.borrow_mut();
|
.args
|
||||||
|
.iter()
|
||||||
|
.map(|x| -> Result<Type, String> {
|
||||||
|
let annotation = x
|
||||||
|
.node
|
||||||
|
.annotation
|
||||||
|
.as_ref()
|
||||||
|
.ok_or_else(|| "type annotation for function parameter is needed".to_string())?
|
||||||
|
.as_ref();
|
||||||
|
|
||||||
|
let ty = class_resolver
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.lock()
|
||||||
|
.parse_type_annotation(
|
||||||
|
&self.to_top_level_context(),
|
||||||
|
unifier.borrow_mut(),
|
||||||
|
&self.primitives,
|
||||||
|
annotation
|
||||||
|
)?;
|
||||||
|
Ok(ty)
|
||||||
|
})
|
||||||
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
|
let ret_ty = method_returns_ast
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|x| {
|
||||||
|
Some(
|
||||||
|
class_resolver
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.lock()
|
||||||
|
.parse_type_annotation(
|
||||||
|
&self.to_top_level_context(),
|
||||||
|
unifier.borrow_mut(),
|
||||||
|
&self.primitives,
|
||||||
|
x.as_ref()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}).unwrap()?;
|
||||||
|
|
||||||
|
let all_tys_ok = {
|
||||||
|
let ret_ty_iter = vec![ret_ty];
|
||||||
|
let ret_ty_iter = ret_ty_iter.iter();
|
||||||
|
let mut all_tys = chain!(arg_tys.iter(), ret_ty_iter);
|
||||||
|
all_tys.all(|x| {
|
||||||
|
let type_enum = unifier.get_ty(*x);
|
||||||
|
match type_enum.as_ref() {
|
||||||
|
TypeEnum::TObj {obj_id, ..} => {
|
||||||
|
!to_be_analyzed_class.contains(obj_id)
|
||||||
|
},
|
||||||
|
TypeEnum::TVirtual { ty } => {
|
||||||
|
if let TypeEnum::TObj {obj_id, ..} = unifier.get_ty(*ty).as_ref() {
|
||||||
|
!to_be_analyzed_class.contains(obj_id)
|
||||||
} else { unreachable!() }
|
} else { unreachable!() }
|
||||||
|
},
|
||||||
|
_ => unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
if all_tys_ok {
|
||||||
|
// TODO: put related value to the `class_methods_parsing_result`
|
||||||
|
unimplemented!()
|
||||||
|
} else {
|
||||||
|
to_be_analyzed_class.push(DefinitionId(class_ind));
|
||||||
|
// TODO: go to the next WHILE loop
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// what should we do with `class A: a = 3`?
|
// what should we do with `class A: a = 3`?
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: now it should be confirmed that every
|
||||||
|
// methods and fields of the class can be correctly typed, put the results
|
||||||
|
// into the actual def_list and the unifier
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn analyze_top_level_inheritance(&mut self) -> Result<(), String> {
|
fn analyze_top_level_inheritance(&mut self) -> Result<(), String> {
|
||||||
|
|
Loading…
Reference in New Issue