forked from M-Labs/nac3
nac3core: top level fix duplicate def, start adding tests
This commit is contained in:
parent
7bbd608492
commit
98d032b72a
|
@ -22,6 +22,8 @@ pub struct DefinitionId(pub usize);
|
||||||
mod type_annotation;
|
mod type_annotation;
|
||||||
use type_annotation::*;
|
use type_annotation::*;
|
||||||
mod helper;
|
mod helper;
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct FunInstance {
|
pub struct FunInstance {
|
||||||
|
@ -88,6 +90,10 @@ pub struct TopLevelComposer {
|
||||||
pub primitives_ty: PrimitiveStore,
|
pub primitives_ty: PrimitiveStore,
|
||||||
// keyword list to prevent same user-defined name
|
// keyword list to prevent same user-defined name
|
||||||
pub keyword_list: HashSet<String>,
|
pub keyword_list: HashSet<String>,
|
||||||
|
// to prevent duplicate definition
|
||||||
|
pub defined_class_name: HashSet<String>,
|
||||||
|
pub defined_class_method_name: HashSet<String>,
|
||||||
|
pub defined_function_name: HashSet<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for TopLevelComposer {
|
impl Default for TopLevelComposer {
|
||||||
|
@ -130,13 +136,16 @@ impl TopLevelComposer {
|
||||||
"none".into(),
|
"none".into(),
|
||||||
"None".into(),
|
"None".into(),
|
||||||
]),
|
]),
|
||||||
|
defined_class_method_name: Default::default(),
|
||||||
|
defined_class_name: Default::default(),
|
||||||
|
defined_function_name: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn make_top_level_context(self) -> TopLevelContext {
|
pub fn make_top_level_context(self) -> TopLevelContext {
|
||||||
TopLevelContext {
|
TopLevelContext {
|
||||||
definitions: RwLock::new(
|
definitions: RwLock::new(
|
||||||
self.definition_ast_list.into_iter().map(|(x, ..)| x).collect::<Vec<_>>(),
|
self.definition_ast_list.into_iter().map(|(x, ..)| x).collect_vec(),
|
||||||
)
|
)
|
||||||
.into(),
|
.into(),
|
||||||
// FIXME: all the big unifier or?
|
// FIXME: all the big unifier or?
|
||||||
|
@ -148,16 +157,16 @@ impl TopLevelComposer {
|
||||||
self.definition_ast_list.iter().map(|(def, ..)| def.clone()).collect_vec()
|
self.definition_ast_list.iter().map(|(def, ..)| def.clone()).collect_vec()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// step 0, register, just remeber the names of top level classes/function
|
/// register, just remeber the names of top level classes/function
|
||||||
/// and check duplicate class/method/function definition
|
/// and check duplicate class/method/function definition
|
||||||
pub fn register_top_level(
|
pub fn register_top_level(
|
||||||
&mut self,
|
&mut self,
|
||||||
ast: ast::Stmt<()>,
|
ast: ast::Stmt<()>,
|
||||||
resolver: Option<Arc<Box<dyn SymbolResolver + Send + Sync>>>,
|
resolver: Option<Arc<Box<dyn SymbolResolver + Send + Sync>>>,
|
||||||
) -> Result<(String, DefinitionId), String> {
|
) -> Result<(String, DefinitionId), String> {
|
||||||
let mut defined_class_name: HashSet<String> = HashSet::new();
|
let defined_class_name = &mut self.defined_class_name;
|
||||||
let mut defined_class_method_name: HashSet<String> = HashSet::new();
|
let defined_class_method_name = &mut self.defined_class_method_name;
|
||||||
let mut defined_function_name: HashSet<String> = HashSet::new();
|
let defined_function_name = &mut self.defined_function_name;
|
||||||
match &ast.node {
|
match &ast.node {
|
||||||
ast::StmtKind::ClassDef { name, body, .. } => {
|
ast::StmtKind::ClassDef { name, body, .. } => {
|
||||||
if self.keyword_list.contains(name) {
|
if self.keyword_list.contains(name) {
|
||||||
|
@ -294,6 +303,14 @@ impl TopLevelComposer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn start_analysis(&mut self) -> Result<(), String> {
|
||||||
|
self.analyze_top_level_class_type_var()?;
|
||||||
|
self.analyze_top_level_class_bases()?;
|
||||||
|
self.analyze_top_level_class_fields_methods()?;
|
||||||
|
self.analyze_top_level_function()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
/// step 1, analyze the type vars associated with top level class
|
/// step 1, analyze the type vars associated with top level class
|
||||||
fn analyze_top_level_class_type_var(&mut self) -> Result<(), String> {
|
fn analyze_top_level_class_type_var(&mut self) -> Result<(), String> {
|
||||||
let def_list = &self.definition_ast_list;
|
let def_list = &self.definition_ast_list;
|
||||||
|
|
|
@ -0,0 +1,71 @@
|
||||||
|
use crate::{
|
||||||
|
location::Location,
|
||||||
|
symbol_resolver::{SymbolResolver, SymbolValue},
|
||||||
|
toplevel::DefinitionId,
|
||||||
|
typecheck::{
|
||||||
|
type_inferencer::PrimitiveStore,
|
||||||
|
typedef::{Type, Unifier},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
use indoc::indoc;
|
||||||
|
use rustpython_parser::{ast::fold::Fold, parser::parse_program};
|
||||||
|
use std::collections::{HashMap, HashSet};
|
||||||
|
use test_case::test_case;
|
||||||
|
|
||||||
|
use super::TopLevelComposer;
|
||||||
|
|
||||||
|
struct Resolver {
|
||||||
|
id_to_type: HashMap<String, Type>,
|
||||||
|
id_to_def: HashMap<String, DefinitionId>,
|
||||||
|
class_names: HashMap<String, Type>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SymbolResolver for Resolver {
|
||||||
|
fn get_symbol_type(&self, _: &mut Unifier, _: &PrimitiveStore, str: &str) -> Option<Type> {
|
||||||
|
self.id_to_type.get(str).cloned()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_symbol_value(&self, _: &str) -> Option<SymbolValue> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_symbol_location(&self, _: &str) -> Option<Location> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_identifier_def(&self, id: &str) -> Option<DefinitionId> {
|
||||||
|
self.id_to_def.get(id).cloned()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test_case(
|
||||||
|
vec![
|
||||||
|
indoc! {"
|
||||||
|
def fun(a: int) -> int:
|
||||||
|
return a
|
||||||
|
"},
|
||||||
|
indoc! {"
|
||||||
|
class A:
|
||||||
|
def __init__(self):
|
||||||
|
self.a: int = 3
|
||||||
|
"},
|
||||||
|
indoc! {"
|
||||||
|
class B:
|
||||||
|
def __init__(self):
|
||||||
|
self.b: float = 4.3
|
||||||
|
|
||||||
|
def fun(self):
|
||||||
|
self.b = self.b + 3.0
|
||||||
|
"}
|
||||||
|
]
|
||||||
|
)]
|
||||||
|
fn test_simple_register(source: Vec<&str>) {
|
||||||
|
let mut composer = TopLevelComposer::new();
|
||||||
|
|
||||||
|
for s in source {
|
||||||
|
let ast = parse_program(s).unwrap();
|
||||||
|
let ast = ast[0].clone();
|
||||||
|
|
||||||
|
composer.register_top_level(ast, None).unwrap();
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue