core: add support for class attributes (issue-102) #425

Merged
sb10q merged 3 commits from issue-102 into master 2024-06-25 16:06:34 +08:00
2 changed files with 71 additions and 6 deletions
Showing only changes of commit ad1b4f1b9b - Show all commits

View File

@ -0,0 +1,40 @@
from min_artiq import *
from numpy import int32
@nac3
class Demo:
attr1: KernelInvariant[int32] = 2

Nit: Does Python use all caps in this way?

Nit: Does Python use all caps in this way?

I was using the example given in #102, but I see your point. I will update the file and while I am at it, refactor nac3core/composer to avoid code duplication

I was using the example given in #102, but I see your point. I will update the file and while I am at it, refactor nac3core/composer to avoid code duplication
attr2: int32 = 4
attr3: Kernel[int32]
@kernel
def __init__(self):
self.attr3 = 8
@nac3
class NAC3Devices:
core: KernelInvariant[Core]
attr4: KernelInvariant[int32] = 16
def __init__(self):
self.core = Core()
@kernel
def run(self):
Demo.attr1 # Supported
# Demo.attr2 # Field not accessible on Kernel
# Demo.attr3 # Only attributes can be accessed in this way
# Demo.attr1 = 2 # Attributes are immutable
self.attr4 # Attributes can be accessed within class
obj = Demo()
obj.attr1 # Attributes can be accessed by class objects
NAC3Devices.attr4 # Attributes accessible for classes without __init__
if __name__ == "__main__":
NAC3Devices().run()

View File

@ -627,12 +627,15 @@ impl InnerResolver {
let pyid_to_def = self.pyid_to_def.read(); let pyid_to_def = self.pyid_to_def.read();
let constructor_ty = pyid_to_def.get(&py_obj_id).and_then(|def_id| { let constructor_ty = pyid_to_def.get(&py_obj_id).and_then(|def_id| {
defs.iter().find_map(|def| { defs.iter().find_map(|def| {
if let TopLevelDef::Class { object_id, methods, constructor, .. } = &*def.read() { if let Some(rear_guard) = def.try_read() {
if object_id == def_id if let TopLevelDef::Class { object_id, methods, constructor, .. } = &*rear_guard
&& constructor.is_some()
&& methods.iter().any(|(s, _, _)| s == &"__init__".into())
{ {
return *constructor; if object_id == def_id
&& constructor.is_some()
&& methods.iter().any(|(s, _, _)| s == &"__init__".into())
{
return *constructor;
}
} }
} }
None None
@ -664,7 +667,29 @@ impl InnerResolver {
primitives, primitives,
)? { )? {
Ok(s) => s, Ok(s) => s,
Err(e) => return Ok(Err(e)), Err(e) => {
// Allow access to Class Attributes of Classes without having to initialize Objects
if self.pyid_to_def.read().contains_key(&py_obj_id) {
if let Some(def_id) = self.pyid_to_def.read().get(&py_obj_id).copied() {
let def = defs[def_id.0].read();
let TopLevelDef::Class { object_id, .. } = &*def else {
// only object is supported, functions are not supported
unreachable!("function type is not supported, should not be queried")
};
let ty = TypeEnum::TObj {
obj_id: *object_id,
params: VarMap::new(),
fields: HashMap::new(),
};
(unifier.add_ty(ty), true)
} else {
return Ok(Err(e));
}
} else {
return Ok(Err(e));
}
}
}; };
match (&*unifier.get_ty(extracted_ty), inst_check) { match (&*unifier.get_ty(extracted_ty), inst_check) {
// do the instantiation for these four types // do the instantiation for these four types