diff --git a/flake.nix b/flake.nix index 07cea776..7987b259 100644 --- a/flake.nix +++ b/flake.nix @@ -180,7 +180,9 @@ clippy pre-commit rustfmt + rust-analyzer ]; + RUST_SRC_PATH = "${pkgs.rust.packages.stable.rustPlatform.rustLibSrc}"; shellHook = '' export DEMO_LINALG_STUB=${packages.x86_64-linux.demo-linalg-stub}/lib/liblinalg.a diff --git a/nac3artiq/demo/dataset_db.mdb b/nac3artiq/demo/dataset_db.mdb new file mode 100644 index 00000000..5511ad47 Binary files /dev/null and b/nac3artiq/demo/dataset_db.mdb differ diff --git a/nac3artiq/demo/dataset_db.mdb-lock b/nac3artiq/demo/dataset_db.mdb-lock new file mode 100644 index 00000000..82238114 Binary files /dev/null and b/nac3artiq/demo/dataset_db.mdb-lock differ diff --git a/nac3artiq/demo/demo.py b/nac3artiq/demo/demo.py index aa135757..8e4251b6 100644 --- a/nac3artiq/demo/demo.py +++ b/nac3artiq/demo/demo.py @@ -1,26 +1,87 @@ from min_artiq import * +from numpy import int32 +# @nac3 +# class A: +# a: int32 +# core: KernelInvariant[Core] + +# def __init__(self, a: int32): +# self.core = Core() +# self.a = a + +# @kernel +# def output_all_fields(self): +# #print(self.a) +# pass + +# @kernel +# def set_a(self, a: int32): +# self.a = a + +# @nac3 +# class B(A): +# b: int32 + +# def __init__(self, b: int32): +# # A.__init__(self, b + 1) +# self.core = Core() +# self.a = b +# self.b = b +# self.set_b(b) + +# @kernel +# def output_parent_fields(self): +# # A.output_all_fields(self) +# pass + +# @kernel +# def output_all_fields(self): +# # A.output_all_fields(self) +# pass +# #print(self.b) + +# @kernel +# def set_b(self, b: int32): +# self.b = b + @nac3 -class Demo: +class C: + c: Kernel[int32] + a: Kernel[int32] + b: Kernel[int32] core: KernelInvariant[Core] - led0: KernelInvariant[TTLOut] - led1: KernelInvariant[TTLOut] - def __init__(self): + def __init__(self, c: int32): + # B.__init__(self, c + 1) self.core = Core() - self.led0 = TTLOut(self.core, 18) - self.led1 = TTLOut(self.core, 19) + self.a = c + self.b = c + self.c = c + + @kernel + def output_parent_fields(self): + # B.output_all_fields(self) + pass @kernel - def run(self): - self.core.reset() - while True: - with parallel: - self.led0.pulse(100.*ms) - self.led1.pulse(100.*ms) - self.core.delay(100.*ms) + def output_all_fields(self): + # B.output_all_fields(self) + #print(self.c) + pass + @kernel + def set_c(self, c: int32): + self.c = c + + @kernel + def run(self): + self.output_all_fields() + # self.set_a(1) + # self.set_b(2) + self.set_c(3) + self.output_all_fields() if __name__ == "__main__": - Demo().run() + C(10).run() diff --git a/nac3artiq/demo/module.elf b/nac3artiq/demo/module.elf new file mode 100644 index 00000000..41377d06 Binary files /dev/null and b/nac3artiq/demo/module.elf differ diff --git a/nac3core/src/toplevel/composer.rs b/nac3core/src/toplevel/composer.rs index 2f0f7e87..1750ec0b 100644 --- a/nac3core/src/toplevel/composer.rs +++ b/nac3core/src/toplevel/composer.rs @@ -5,7 +5,7 @@ use crate::{ codegen::{expr::get_subst_key, stmt::exn_constructor}, symbol_resolver::SymbolValue, typecheck::{ - type_inferencer::{FunctionData, Inferencer}, + type_inferencer::{report_error, FunctionData, Inferencer}, typedef::{TypeVar, VarMap}, }, }; @@ -389,7 +389,26 @@ impl TopLevelComposer { } pub fn start_analysis(&mut self, inference: bool) -> Result<(), HashSet> { - self.analyze_top_level_class_type_var()?; + let unifier = self.unifier.borrow_mut(); + let primitives_store = &self.primitives_ty; + let temp_def_list = self.extract_def_list(); + + // Separate class definitions + let def_list = &self.definition_ast_list; + let class_def_list = def_list + .iter() + .skip(self.builtin_num) + .filter(|def| def.1.is_some() && matches!(&*def.0.read(), TopLevelDef::Class { .. })) + .collect::>(); + + // Step 1. Analyze type variables within class definitions + Self::analyze_top_level_class_type_var( + class_def_list, + temp_def_list.clone(), + unifier, + primitives_store, + )?; + self.analyze_top_level_class_bases()?; self.analyze_top_level_class_fields_methods()?; self.analyze_top_level_function()?; @@ -399,116 +418,117 @@ impl TopLevelComposer { Ok(()) } - /// step 1, analyze the type vars associated with top level class - fn analyze_top_level_class_type_var(&mut self) -> Result<(), HashSet> { - let def_list = &self.definition_ast_list; - let temp_def_list = self.extract_def_list(); - let unifier = self.unifier.borrow_mut(); - let primitives_store = &self.primitives_ty; - - let mut analyze = |class_def: &Arc>, class_ast: &Option| { - // only deal with class def here - let mut class_def = class_def.write(); - let (class_bases_ast, class_def_type_vars, class_resolver) = { - if let TopLevelDef::Class { type_vars, resolver, .. } = &mut *class_def { - let Some(ast::Located { node: ast::StmtKind::ClassDef { bases, .. }, .. }) = - class_ast - else { - unreachable!() - }; - - (bases, type_vars, resolver) - } else { - return Ok(()); - } + fn analyze_bases( + class_def: &Arc>, + class_ast: &Option, + temp_def_list: &Vec>>, + unifier: &mut Unifier, + primitives_store: &PrimitiveStore, + ) -> Result<(), HashSet> { + let mut class_def = class_def.write(); + let (class_def_id, class_ancestors, class_bases_ast, class_type_vars, class_resolver) = { + let TopLevelDef::Class { object_id, ancestors, type_vars, resolver, .. } = + &mut *class_def + else { + unreachable!() }; - let class_resolver = class_resolver.as_ref().unwrap(); - let class_resolver = &**class_resolver; + let Some(ast::Located { node: ast::StmtKind::ClassDef { bases, .. }, .. }) = class_ast + else { + unreachable!() + }; + (object_id, ancestors, bases, type_vars, resolver.as_ref().unwrap().as_ref()) + }; - let mut is_generic = false; - for b in class_bases_ast { - match &b.node { - // analyze typevars bounded to the class, - // only support things like `class A(Generic[T, V])`, - // things like `class A(Generic[T, V, ImportedModule.T])` is not supported - // i.e. only simple names are allowed in the subscript - // should update the TopLevelDef::Class.typevars and the TypeEnum::TObj.params - ast::ExprKind::Subscript { value, slice, .. } - if { - matches!( - &value.node, - ast::ExprKind::Name { id, .. } if id == &"Generic".into() - ) - } => - { - if is_generic { - return Err(HashSet::from([format!( - "only single Generic[...] is allowed (at {})", - b.location - )])); - } - is_generic = true; + let mut is_generic = false; + let mut has_base = false; + // Check class bases for typevars + for b in class_bases_ast { + match &b.node { + // analyze typevars bounded to the class, + // only support things like `class A(Generic[T, V])`, + // things like `class A(Generic[T, V, ImportedModule.T])` is not supported + // i.e. only simple names are allowed in the subscript + // should update the TopLevelDef::Class.typevars and the TypeEnum::TObj.params + ast::ExprKind::Subscript { value, slice, .. } if matches!(&value.node, ast::ExprKind::Name { id, .. } if id == &"Generic".into()) => + { + if is_generic { + return report_error("only single Generic[...] is allowed", b.location); + } + is_generic = true; - let type_var_list: Vec<&ast::Expr<()>>; - // if `class A(Generic[T, V, G])` - if let ast::ExprKind::Tuple { elts, .. } = &slice.node { - type_var_list = elts.iter().collect_vec(); - // `class A(Generic[T])` - } else { - type_var_list = vec![&**slice]; - } - - // parse the type vars - let type_vars = type_var_list - .into_iter() - .map(|e| { - class_resolver.parse_type_annotation( - &temp_def_list, - unifier, - primitives_store, - e, - ) - }) - .collect::, _>>()?; - - // check if all are unique type vars - let all_unique_type_var = { - let mut occurred_type_var_id: HashSet = HashSet::new(); - type_vars.iter().all(|x| { - let ty = unifier.get_ty(*x); - if let TypeEnum::TVar { id, .. } = ty.as_ref() { - occurred_type_var_id.insert(*id) - } else { - false - } - }) - }; - if !all_unique_type_var { - return Err(HashSet::from([format!( - "duplicate type variable occurs (at {})", - slice.location - )])); - } - - // add to TopLevelDef - class_def_type_vars.extend(type_vars); + let type_var_list: Vec<&ast::Expr<()>>; + // if `class A(Generic[T, V, G])` + if let ast::ExprKind::Tuple { elts, .. } = &slice.node { + type_var_list = elts.iter().collect_vec(); + // `class A(Generic[T])` + } else { + type_var_list = vec![&**slice]; } - // if others, do nothing in this function - _ => continue, + let type_vars = type_var_list + .into_iter() + .map(|e| { + class_resolver.parse_type_annotation( + &temp_def_list, + unifier, + primitives_store, + e, + ) + }) + .collect::, _>>()?; + + class_type_vars.extend(type_vars); } + ast::ExprKind::Subscript { .. } => { + if has_base { + return report_error("a class definition can only have at most one base class declaration and one generic declaration", b.location); + } + has_base = true; + + // the function parse_ast_to make sure that no type var occurred in + // bast_ty if it is a CustomClassKind + let base_ty = parse_ast_to_type_annotation_kinds( + class_resolver, + &temp_def_list, + unifier, + &primitives_store, + b, + vec![(*class_def_id, class_type_vars.clone())] + .into_iter() + .collect::>(), + )?; + + if let TypeAnnotation::CustomClass { .. } = &base_ty { + class_ancestors.push(base_ty); + } else { + return report_error( + "class base declaration can only be custom class", + b.location, + ); + } + } + // TODO: Report Error here + _ => unreachable!(), } - Ok(()) - }; + } + + Ok(()) + } + + /// step 1, analyze the type vars associated with top level class + fn analyze_top_level_class_type_var( + def_list: Vec<&DefAst>, + temp_def_list: Vec>>, + unifier: &mut Unifier, + primitives_store: &PrimitiveStore, + ) -> Result<(), HashSet> { let mut errors = HashSet::new(); - for (class_def, class_ast) in def_list.iter().skip(self.builtin_num) { - if class_ast.is_none() { - continue; - } - if let Err(e) = analyze(class_def, class_ast) { + for (class_def, class_ast) in def_list.iter() { + if let Err(e) = Self::analyze_bases(class_def, class_ast, &temp_def_list, unifier, primitives_store) { errors.extend(e); } } + if !errors.is_empty() { return Err(errors); } diff --git a/nac3core/src/typecheck/type_inferencer/mod.rs b/nac3core/src/typecheck/type_inferencer/mod.rs index 0408cf1c..394dcbfd 100644 --- a/nac3core/src/typecheck/type_inferencer/mod.rs +++ b/nac3core/src/typecheck/type_inferencer/mod.rs @@ -112,7 +112,7 @@ impl Fold<()> for NaiveFolder { } } -fn report_error(msg: &str, location: Location) -> Result { +pub fn report_error(msg: &str, location: Location) -> Result { Err(HashSet::from([format!("{msg} at {location}")])) } diff --git a/pyo3/nac3artiq.so b/pyo3/nac3artiq.so new file mode 100755 index 00000000..e73ca32b Binary files /dev/null and b/pyo3/nac3artiq.so differ