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;
|
||||
use type_annotation::*;
|
||||
mod helper;
|
||||
#[cfg(test)]
|
||||
mod test;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct FunInstance {
|
||||
@ -88,6 +90,10 @@ pub struct TopLevelComposer {
|
||||
pub primitives_ty: PrimitiveStore,
|
||||
// keyword list to prevent same user-defined name
|
||||
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 {
|
||||
@ -130,13 +136,16 @@ impl TopLevelComposer {
|
||||
"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 {
|
||||
TopLevelContext {
|
||||
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(),
|
||||
// FIXME: all the big unifier or?
|
||||
@ -148,16 +157,16 @@ impl TopLevelComposer {
|
||||
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
|
||||
pub fn register_top_level(
|
||||
&mut self,
|
||||
ast: ast::Stmt<()>,
|
||||
resolver: Option<Arc<Box<dyn SymbolResolver + Send + Sync>>>,
|
||||
) -> Result<(String, DefinitionId), String> {
|
||||
let mut defined_class_name: HashSet<String> = HashSet::new();
|
||||
let mut defined_class_method_name: HashSet<String> = HashSet::new();
|
||||
let mut defined_function_name: HashSet<String> = HashSet::new();
|
||||
let defined_class_name = &mut self.defined_class_name;
|
||||
let defined_class_method_name = &mut self.defined_class_method_name;
|
||||
let defined_function_name = &mut self.defined_function_name;
|
||||
match &ast.node {
|
||||
ast::StmtKind::ClassDef { name, body, .. } => {
|
||||
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
|
||||
fn analyze_top_level_class_type_var(&mut self) -> Result<(), String> {
|
||||
let def_list = &self.definition_ast_list;
|
||||
|
71
nac3core/src/toplevel/test.rs
Normal file
71
nac3core/src/toplevel/test.rs
Normal file
@ -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
Block a user