forked from M-Labs/nac3
Refactor Toplevel composer
This commit is contained in:
parent
c5ae0e7c36
commit
28e34e9444
@ -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
|
||||
|
BIN
nac3artiq/demo/dataset_db.mdb
Normal file
BIN
nac3artiq/demo/dataset_db.mdb
Normal file
Binary file not shown.
BIN
nac3artiq/demo/dataset_db.mdb-lock
Normal file
BIN
nac3artiq/demo/dataset_db.mdb-lock
Normal file
Binary file not shown.
@ -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()
|
||||
|
BIN
nac3artiq/demo/module.elf
Normal file
BIN
nac3artiq/demo/module.elf
Normal file
Binary file not shown.
@ -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<String>> {
|
||||
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::<Vec<_>>();
|
||||
|
||||
// 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<String>> {
|
||||
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<RwLock<TopLevelDef>>, class_ast: &Option<Stmt>| {
|
||||
// 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<RwLock<TopLevelDef>>,
|
||||
class_ast: &Option<Stmt>,
|
||||
temp_def_list: &Vec<Arc<RwLock<TopLevelDef>>>,
|
||||
unifier: &mut Unifier,
|
||||
primitives_store: &PrimitiveStore,
|
||||
) -> Result<(), HashSet<String>> {
|
||||
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::<Result<Vec<_>, _>>()?;
|
||||
|
||||
// check if all are unique type vars
|
||||
let all_unique_type_var = {
|
||||
let mut occurred_type_var_id: HashSet<TypeVarId> = 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::<Result<Vec<_>, _>>()?;
|
||||
|
||||
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::<HashMap<_, _>>(),
|
||||
)?;
|
||||
|
||||
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<Arc<RwLock<TopLevelDef>>>,
|
||||
unifier: &mut Unifier,
|
||||
primitives_store: &PrimitiveStore,
|
||||
) -> Result<(), HashSet<String>> {
|
||||
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);
|
||||
}
|
||||
|
@ -112,7 +112,7 @@ impl Fold<()> for NaiveFolder {
|
||||
}
|
||||
}
|
||||
|
||||
fn report_error<T>(msg: &str, location: Location) -> Result<T, InferenceError> {
|
||||
pub fn report_error<T>(msg: &str, location: Location) -> Result<T, InferenceError> {
|
||||
Err(HashSet::from([format!("{msg} at {location}")]))
|
||||
}
|
||||
|
||||
|
BIN
pyo3/nac3artiq.so
Executable file
BIN
pyo3/nac3artiq.so
Executable file
Binary file not shown.
Loading…
Reference in New Issue
Block a user