From 6d65ee90e8bfb0cdbb63138acd5f0ee4fbafe19c Mon Sep 17 00:00:00 2001 From: ychenfo Date: Fri, 10 Dec 2021 16:40:46 +0800 Subject: [PATCH 1/7] nac3core/artiq: implement Kernel annotation --- nac3artiq/demo/min_artiq.py | 73 ++++++++++++++++++++++++++++--- nac3core/src/toplevel/composer.rs | 29 +++++++----- 2 files changed, 86 insertions(+), 16 deletions(-) diff --git a/nac3artiq/demo/min_artiq.py b/nac3artiq/demo/min_artiq.py index 9adf1667..ad6c3d9b 100644 --- a/nac3artiq/demo/min_artiq.py +++ b/nac3artiq/demo/min_artiq.py @@ -1,15 +1,15 @@ -from inspect import getfullargspec +from inspect import getfullargspec, isclass, getmro from functools import wraps from types import SimpleNamespace from numpy import int32, int64 -from typing import Generic, TypeVar +from typing import Generic, TypeVar, get_origin from math import floor, ceil import nac3artiq __all__ = [ - "KernelInvariant", "virtual", + "KernelInvariant", "Kernel", "virtual", "round64", "floor64", "ceil64", "extern", "kernel", "portable", "nac3", "ms", "us", "ns", @@ -24,11 +24,13 @@ T = TypeVar('T') class KernelInvariant(Generic[T]): pass +class Kernel(Generic[T]): + pass + # The virtual class must exist before nac3artiq.NAC3 is created. class virtual(Generic[T]): pass - def round64(x): return round(x) @@ -44,6 +46,7 @@ core_arguments = device_db.device_db["core"]["arguments"] compiler = nac3artiq.NAC3(core_arguments["target"]) allow_registration = True +allow_kernel_read = False # Delay NAC3 analysis until all referenced variables are supposed to exist on the CPython side. registered_functions = set() registered_classes = set() @@ -90,7 +93,65 @@ def nac3(cls): Decorates a class to be analyzed by NAC3. All classes containing kernels or portable methods must use this decorator. """ + + # python does not allow setting magic method on specific instances + # (https://docs.python.org/3/reference/datamodel.html#special-method-lookup). + # use this set to keep track of those custom class instances that are + # assigned to the `Kernel` fields of a class + cls.__nac3_kernel_only_instances__ = set() + + def apply_kernel_only_constraints(val): + kernel_only_set = getattr(type(val), '__nac3_kernel_only_instances__', None) + if kernel_only_set is None: + return + else: + for (_, attr_val) in val.__dict__.items(): + if not (attr_val == val): + apply_kernel_only_constraints(attr_val) + kernel_only_set.add(val) + + if not isclass(cls): + raise ValueError("nac3 annotation decorator should only be applied to classes") + if not cls.__setattr__ in {base.__setattr__ for base in cls.__bases__}: + raise ValueError("custom __setattr__ is not supported in kernel classes") + register_class(cls) + + immutable_fields = { + n for b in getmro(cls) + for (n, ty) in b.__dict__.get('__annotations__', {}).items() if get_origin(ty) == Kernel + } + def __setattr__(obj, key, value): + if obj in type(obj).__nac3_kernel_only_instances__: + raise TypeError("attempting to write to kernel only variable") + # should allow init to set value, if no attribute then allow to set attr, then + # recursively apply constraint to all the fields of that specific object, + # regardless of whether they are marked with `Kernel` or not + if key in immutable_fields: + if hasattr(obj, key): + raise TypeError("attempting to write to kernel only variable") + else: + apply_kernel_only_constraints(value) + object.__setattr__(obj, key, value) + + def __getattribute__(obj, key): + # need to use `object.__getattribute__` to get attr before checking + # the key in immutable_fields for `__init__`. + # since that in `__init__` when setting a instance variable like `self.a = 3` + # the sequence of internal magic call is still calling cls.__getattribute__(self, 'a') + # first, and if only "AttributeError" is raised, it will then call `__setattr__` + # if we raise `TypeError` too early, python will just halt at this `TypeError`. + attr = object.__getattribute__(obj, key) + if not allow_kernel_read: + if obj in type(obj).__nac3_kernel_only_instances__: + raise TypeError("attempting to read kernel only variable") + if key in immutable_fields: + raise TypeError("attempting to read kernel only variable") + return attr + + cls.__setattr__ = __setattr__ + cls.__getattribute__ = __getattribute__ + return cls @@ -142,6 +203,7 @@ class Core: self.ref_period = core_arguments["ref_period"] def run(self, method, *args, **kwargs): + global allow_kernel_read global allow_registration if allow_registration: compiler.analyze(registered_functions, registered_classes) @@ -153,8 +215,9 @@ class Core: else: obj = method name = "" - + allow_kernel_read = True compiler.compile_method_to_file(obj, name, args, "module.elf") + allow_kernel_read = False @kernel def reset(self): diff --git a/nac3core/src/toplevel/composer.rs b/nac3core/src/toplevel/composer.rs index 02b800da..d356faf6 100644 --- a/nac3core/src/toplevel/composer.rs +++ b/nac3core/src/toplevel/composer.rs @@ -1058,20 +1058,27 @@ impl TopLevelComposer { let dummy_field_type = unifier.get_fresh_var().0; // handle Kernel[T], KernelInvariant[T] - let (annotation, mutable) = { - let mut result = None; - if let ast::ExprKind::Subscript { value, slice, .. } = &annotation.as_ref().node { - if let ast::ExprKind::Name { id, .. } = &value.node { - result = if id == &"Kernel".into() { - Some((slice, true)) - } else if id == &"KernelInvariant".into() { - Some((slice, false)) - } else { - None + let (annotation, mutable) = match &annotation.node { + ast::ExprKind::Subscript { value, slice, .. } + if matches!(&value.node, ast::ExprKind::Name { id, .. } if id == &"Kernel".into()) => + { + match &slice.node { + ast::ExprKind::Subscript { value, .. } + if matches!(&value.node, ast::ExprKind::Name { id, .. } if id == &"list".into()) => + { + return Err(format!("list is not allowed to be `Kernel` at {}", value.location)) } + _ => (slice, true) } } - result.unwrap_or((annotation, true)) + ast::ExprKind::Subscript { value, slice, .. } + if matches!(&value.node, ast::ExprKind::Name { id, .. } if id == &"KernelInvariant".into()) => { + (slice, false) + } + _ => { + eprintln!("attributes not annotated with `Kernel` or `KernelInvariants` at {}", &annotation.location); + (annotation, true) + } }; class_fields_def.push((*attr, dummy_field_type, mutable)); -- 2.44.2 From d269e429d094b019380965bb56acb3f78acb43ef Mon Sep 17 00:00:00 2001 From: ychenfo Date: Fri, 10 Dec 2021 16:44:43 +0800 Subject: [PATCH 2/7] nac3artiq: add kernel only annotation demo --- nac3artiq/demo/kernel_only_demo.py | 73 ++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 nac3artiq/demo/kernel_only_demo.py diff --git a/nac3artiq/demo/kernel_only_demo.py b/nac3artiq/demo/kernel_only_demo.py new file mode 100644 index 00000000..d2f541b0 --- /dev/null +++ b/nac3artiq/demo/kernel_only_demo.py @@ -0,0 +1,73 @@ +from min_artiq import * +from numpy import int32 + +@nac3 +class Base: + c: Kernel[int32] + def __init__(self): + self.c = 4 + self.a = 3 + self.a = 5 + +@nac3 +class D: + da: KernelInvariant[int32] + def __init__(self): + self.da = 321 + +@nac3 +class C: + ca: KernelInvariant[int32] + cb: KernelInvariant[D] + def __init__(self, d: D): + self.ca = 123 + self.cb = d + +@nac3 +class A(Base): + core: KernelInvariant[Core] + led0: KernelInvariant[TTLOut] + led1: KernelInvariant[TTLOut] + d: Kernel[bool] + cc: Kernel[C] + + def __init__(self, c): + super().__init__() + self.core = Core() + self.led0 = TTLOut(self.core, 18) + self.led1 = TTLOut(self.core, 19) + self.b = 3 + self.d = False + self.cc = c + + @kernel + def run(self): + print_int32(self.cc.cb.da) + + +if __name__ == '__main__': + d = D() + print(d.da) + c = C(d) + print(d.da) + print(c.cb.da) + + a = A(c) + print(a.a) + print(a.b) + # print(c.ca) # fail + # print(c.cb.da) # fail + + a.run() + + # d = D() # redefine, ok + # c = C(d) # redefine, ok + + # print(a.c) # fail + # a.c = 2 # fail + # a.d = 1 # fail + # a.cc = 1 # fail + # c.ca = 1 # fail + # c.cb = 1 # fail + # c.cb.da = 1 # fail + # d.da = 1 # fail \ No newline at end of file -- 2.44.2 From 39220e835499ad60676a625ed96129adc407cab4 Mon Sep 17 00:00:00 2001 From: ychenfo Date: Wed, 15 Dec 2021 01:22:31 +0800 Subject: [PATCH 3/7] Revert "nac3core/artiq: implement Kernel annotation" and "nac3artiq: add kernel only annotation demo" This reverts commit 6d65ee90e8bfb0cdbb63138acd5f0ee4fbafe19c and d269e429d094b019380965bb56acb3f78acb43ef --- nac3artiq/demo/kernel_only_demo.py | 73 ------------------------------ nac3artiq/demo/min_artiq.py | 73 ++---------------------------- nac3core/src/toplevel/composer.rs | 29 +++++------- 3 files changed, 16 insertions(+), 159 deletions(-) delete mode 100644 nac3artiq/demo/kernel_only_demo.py diff --git a/nac3artiq/demo/kernel_only_demo.py b/nac3artiq/demo/kernel_only_demo.py deleted file mode 100644 index d2f541b0..00000000 --- a/nac3artiq/demo/kernel_only_demo.py +++ /dev/null @@ -1,73 +0,0 @@ -from min_artiq import * -from numpy import int32 - -@nac3 -class Base: - c: Kernel[int32] - def __init__(self): - self.c = 4 - self.a = 3 - self.a = 5 - -@nac3 -class D: - da: KernelInvariant[int32] - def __init__(self): - self.da = 321 - -@nac3 -class C: - ca: KernelInvariant[int32] - cb: KernelInvariant[D] - def __init__(self, d: D): - self.ca = 123 - self.cb = d - -@nac3 -class A(Base): - core: KernelInvariant[Core] - led0: KernelInvariant[TTLOut] - led1: KernelInvariant[TTLOut] - d: Kernel[bool] - cc: Kernel[C] - - def __init__(self, c): - super().__init__() - self.core = Core() - self.led0 = TTLOut(self.core, 18) - self.led1 = TTLOut(self.core, 19) - self.b = 3 - self.d = False - self.cc = c - - @kernel - def run(self): - print_int32(self.cc.cb.da) - - -if __name__ == '__main__': - d = D() - print(d.da) - c = C(d) - print(d.da) - print(c.cb.da) - - a = A(c) - print(a.a) - print(a.b) - # print(c.ca) # fail - # print(c.cb.da) # fail - - a.run() - - # d = D() # redefine, ok - # c = C(d) # redefine, ok - - # print(a.c) # fail - # a.c = 2 # fail - # a.d = 1 # fail - # a.cc = 1 # fail - # c.ca = 1 # fail - # c.cb = 1 # fail - # c.cb.da = 1 # fail - # d.da = 1 # fail \ No newline at end of file diff --git a/nac3artiq/demo/min_artiq.py b/nac3artiq/demo/min_artiq.py index ad6c3d9b..9adf1667 100644 --- a/nac3artiq/demo/min_artiq.py +++ b/nac3artiq/demo/min_artiq.py @@ -1,15 +1,15 @@ -from inspect import getfullargspec, isclass, getmro +from inspect import getfullargspec from functools import wraps from types import SimpleNamespace from numpy import int32, int64 -from typing import Generic, TypeVar, get_origin +from typing import Generic, TypeVar from math import floor, ceil import nac3artiq __all__ = [ - "KernelInvariant", "Kernel", "virtual", + "KernelInvariant", "virtual", "round64", "floor64", "ceil64", "extern", "kernel", "portable", "nac3", "ms", "us", "ns", @@ -24,13 +24,11 @@ T = TypeVar('T') class KernelInvariant(Generic[T]): pass -class Kernel(Generic[T]): - pass - # The virtual class must exist before nac3artiq.NAC3 is created. class virtual(Generic[T]): pass + def round64(x): return round(x) @@ -46,7 +44,6 @@ core_arguments = device_db.device_db["core"]["arguments"] compiler = nac3artiq.NAC3(core_arguments["target"]) allow_registration = True -allow_kernel_read = False # Delay NAC3 analysis until all referenced variables are supposed to exist on the CPython side. registered_functions = set() registered_classes = set() @@ -93,65 +90,7 @@ def nac3(cls): Decorates a class to be analyzed by NAC3. All classes containing kernels or portable methods must use this decorator. """ - - # python does not allow setting magic method on specific instances - # (https://docs.python.org/3/reference/datamodel.html#special-method-lookup). - # use this set to keep track of those custom class instances that are - # assigned to the `Kernel` fields of a class - cls.__nac3_kernel_only_instances__ = set() - - def apply_kernel_only_constraints(val): - kernel_only_set = getattr(type(val), '__nac3_kernel_only_instances__', None) - if kernel_only_set is None: - return - else: - for (_, attr_val) in val.__dict__.items(): - if not (attr_val == val): - apply_kernel_only_constraints(attr_val) - kernel_only_set.add(val) - - if not isclass(cls): - raise ValueError("nac3 annotation decorator should only be applied to classes") - if not cls.__setattr__ in {base.__setattr__ for base in cls.__bases__}: - raise ValueError("custom __setattr__ is not supported in kernel classes") - register_class(cls) - - immutable_fields = { - n for b in getmro(cls) - for (n, ty) in b.__dict__.get('__annotations__', {}).items() if get_origin(ty) == Kernel - } - def __setattr__(obj, key, value): - if obj in type(obj).__nac3_kernel_only_instances__: - raise TypeError("attempting to write to kernel only variable") - # should allow init to set value, if no attribute then allow to set attr, then - # recursively apply constraint to all the fields of that specific object, - # regardless of whether they are marked with `Kernel` or not - if key in immutable_fields: - if hasattr(obj, key): - raise TypeError("attempting to write to kernel only variable") - else: - apply_kernel_only_constraints(value) - object.__setattr__(obj, key, value) - - def __getattribute__(obj, key): - # need to use `object.__getattribute__` to get attr before checking - # the key in immutable_fields for `__init__`. - # since that in `__init__` when setting a instance variable like `self.a = 3` - # the sequence of internal magic call is still calling cls.__getattribute__(self, 'a') - # first, and if only "AttributeError" is raised, it will then call `__setattr__` - # if we raise `TypeError` too early, python will just halt at this `TypeError`. - attr = object.__getattribute__(obj, key) - if not allow_kernel_read: - if obj in type(obj).__nac3_kernel_only_instances__: - raise TypeError("attempting to read kernel only variable") - if key in immutable_fields: - raise TypeError("attempting to read kernel only variable") - return attr - - cls.__setattr__ = __setattr__ - cls.__getattribute__ = __getattribute__ - return cls @@ -203,7 +142,6 @@ class Core: self.ref_period = core_arguments["ref_period"] def run(self, method, *args, **kwargs): - global allow_kernel_read global allow_registration if allow_registration: compiler.analyze(registered_functions, registered_classes) @@ -215,9 +153,8 @@ class Core: else: obj = method name = "" - allow_kernel_read = True + compiler.compile_method_to_file(obj, name, args, "module.elf") - allow_kernel_read = False @kernel def reset(self): diff --git a/nac3core/src/toplevel/composer.rs b/nac3core/src/toplevel/composer.rs index d356faf6..02b800da 100644 --- a/nac3core/src/toplevel/composer.rs +++ b/nac3core/src/toplevel/composer.rs @@ -1058,27 +1058,20 @@ impl TopLevelComposer { let dummy_field_type = unifier.get_fresh_var().0; // handle Kernel[T], KernelInvariant[T] - let (annotation, mutable) = match &annotation.node { - ast::ExprKind::Subscript { value, slice, .. } - if matches!(&value.node, ast::ExprKind::Name { id, .. } if id == &"Kernel".into()) => - { - match &slice.node { - ast::ExprKind::Subscript { value, .. } - if matches!(&value.node, ast::ExprKind::Name { id, .. } if id == &"list".into()) => - { - return Err(format!("list is not allowed to be `Kernel` at {}", value.location)) + let (annotation, mutable) = { + let mut result = None; + if let ast::ExprKind::Subscript { value, slice, .. } = &annotation.as_ref().node { + if let ast::ExprKind::Name { id, .. } = &value.node { + result = if id == &"Kernel".into() { + Some((slice, true)) + } else if id == &"KernelInvariant".into() { + Some((slice, false)) + } else { + None } - _ => (slice, true) } } - ast::ExprKind::Subscript { value, slice, .. } - if matches!(&value.node, ast::ExprKind::Name { id, .. } if id == &"KernelInvariant".into()) => { - (slice, false) - } - _ => { - eprintln!("attributes not annotated with `Kernel` or `KernelInvariants` at {}", &annotation.location); - (annotation, true) - } + result.unwrap_or((annotation, true)) }; class_fields_def.push((*attr, dummy_field_type, mutable)); -- 2.44.2 From bd97f89514855c6b7a611b98f8704c68cd7350c1 Mon Sep 17 00:00:00 2001 From: ychenfo Date: Wed, 15 Dec 2021 02:28:31 +0800 Subject: [PATCH 4/7] nac3core/artiq/standalone: implement kernel annotation with core mode selection --- nac3artiq/demo/min_artiq.py | 5 +++- nac3artiq/src/lib.rs | 6 ++--- nac3core/src/toplevel/composer.rs | 45 +++++++++++++++++++++---------- nac3standalone/src/main.rs | 16 +++++------ 4 files changed, 46 insertions(+), 26 deletions(-) diff --git a/nac3artiq/demo/min_artiq.py b/nac3artiq/demo/min_artiq.py index 9adf1667..64f41c73 100644 --- a/nac3artiq/demo/min_artiq.py +++ b/nac3artiq/demo/min_artiq.py @@ -9,7 +9,7 @@ import nac3artiq __all__ = [ - "KernelInvariant", "virtual", + "Kernel", "KernelInvariant", "virtual", "round64", "floor64", "ceil64", "extern", "kernel", "portable", "nac3", "ms", "us", "ns", @@ -21,6 +21,9 @@ __all__ = [ T = TypeVar('T') +class Kernel(Generic[T]): + pass + class KernelInvariant(Generic[T]): pass diff --git a/nac3artiq/src/lib.rs b/nac3artiq/src/lib.rs index 405645d8..623b1220 100644 --- a/nac3artiq/src/lib.rs +++ b/nac3artiq/src/lib.rs @@ -22,7 +22,7 @@ use parking_lot::{Mutex, RwLock}; use nac3core::{ codegen::{concrete_type::ConcreteTypeStore, CodeGenTask, WithCall, WorkerRegistry}, symbol_resolver::SymbolResolver, - toplevel::{composer::TopLevelComposer, DefinitionId, GenCall, TopLevelDef}, + toplevel::{composer::{TopLevelComposer, CoreMode}, DefinitionId, GenCall, TopLevelDef}, typecheck::typedef::{FunSignature, FuncArg}, typecheck::{type_inferencer::PrimitiveStore, typedef::Type}, }; @@ -239,7 +239,7 @@ impl Nac3 { }))), ), ]; - let (_, builtins_def, builtins_ty) = TopLevelComposer::new(builtins.clone()); + let (_, builtins_def, builtins_ty) = TopLevelComposer::new(builtins.clone(), CoreMode::Artiq); let builtins_mod = PyModule::import(py, "builtins").unwrap(); let id_fn = builtins_mod.getattr("id").unwrap(); @@ -375,7 +375,7 @@ impl Nac3 { filename: &str, py: Python, ) -> PyResult<()> { - let (mut composer, _, _) = TopLevelComposer::new(self.builtins.clone()); + let (mut composer, _, _) = TopLevelComposer::new(self.builtins.clone(), CoreMode::Artiq); let mut id_to_def = HashMap::new(); let mut id_to_type = HashMap::new(); diff --git a/nac3core/src/toplevel/composer.rs b/nac3core/src/toplevel/composer.rs index 02b800da..3398adf8 100644 --- a/nac3core/src/toplevel/composer.rs +++ b/nac3core/src/toplevel/composer.rs @@ -9,6 +9,11 @@ use crate::{ use super::*; +pub enum CoreMode { + Artiq, + Standalone +} + type DefAst = (Arc>, Option>); pub struct TopLevelComposer { // list of top level definitions, same as top level context @@ -25,11 +30,13 @@ pub struct TopLevelComposer { pub method_class: HashMap, // number of built-in function and classes in the definition list, later skip pub builtin_num: usize, + // indicate the mode that we are using the core + pub mode: CoreMode, } impl Default for TopLevelComposer { fn default() -> Self { - Self::new(vec![]).0 + Self::new(vec![], CoreMode::Standalone).0 } } @@ -38,6 +45,7 @@ impl TopLevelComposer { /// resolver can later figure out primitive type definitions when passed a primitive type name pub fn new( builtins: Vec<(StrRef, FunSignature, Arc)>, + mode: CoreMode ) -> (Self, HashMap, HashMap) { let mut primitives = Self::make_primitives(); let (mut definition_ast_list, builtin_name_list) = builtins::get_builtins(&mut primitives); @@ -108,6 +116,7 @@ impl TopLevelComposer { keyword_list, defined_names, method_class, + mode }, builtin_id, builtin_ty, @@ -554,7 +563,7 @@ impl TopLevelComposer { unifier, primitives, &mut type_var_to_concrete_def, - &self.keyword_list, + (&self.keyword_list, &self.mode) )? } } @@ -827,8 +836,9 @@ impl TopLevelComposer { unifier: &mut Unifier, primitives: &PrimitiveStore, type_var_to_concrete_def: &mut HashMap, - keyword_list: &HashSet, + core_info: (&HashSet, &CoreMode), ) -> Result<(), String> { + let (keyword_list, core_mode) = core_info; let mut class_def = class_def.write(); let ( class_id, @@ -1059,19 +1069,26 @@ impl TopLevelComposer { // handle Kernel[T], KernelInvariant[T] let (annotation, mutable) = { - let mut result = None; - if let ast::ExprKind::Subscript { value, slice, .. } = &annotation.as_ref().node { - if let ast::ExprKind::Name { id, .. } = &value.node { - result = if id == &"Kernel".into() { - Some((slice, true)) - } else if id == &"KernelInvariant".into() { - Some((slice, false)) - } else { - None - } + match core_mode { + CoreMode::Artiq => match &annotation.as_ref().node { + ast::ExprKind::Subscript { value, slice, .. } if matches!( + &value.node, + ast::ExprKind::Name { id, .. } if id == &"Kernel".into() + ) => (slice, true), + ast::ExprKind::Subscript { value, slice, .. } if matches!( + &value.node, + ast::ExprKind::Name { id, .. } if id == &"KernelInvariant".into() + ) => (slice, false), + _ => continue // ignore fields annotated otherwise + }, + CoreMode::Standalone => match &annotation.as_ref().node { + ast::ExprKind::Subscript { value, slice, .. } if matches!( + &value.node, + ast::ExprKind::Name { id, .. } if id == &"Invariant".into() + ) => (slice, false), + _ => (annotation, true) } } - result.unwrap_or((annotation, true)) }; class_fields_def.push((*attr, dummy_field_type, mutable)); diff --git a/nac3standalone/src/main.rs b/nac3standalone/src/main.rs index 238511c2..abc8e821 100644 --- a/nac3standalone/src/main.rs +++ b/nac3standalone/src/main.rs @@ -3,13 +3,10 @@ use inkwell::{ targets::*, OptimizationLevel, }; -use nac3core::typecheck::{type_inferencer::PrimitiveStore, typedef::{Type, Unifier}}; -use nac3parser::{ast::{Expr, ExprKind, StmtKind}, parser}; +use std::{borrow::Borrow, collections::HashMap, env, fs, path::Path, sync::Arc, time::SystemTime}; use parking_lot::RwLock; -use std::{borrow::Borrow, env}; -use std::fs; -use std::{collections::HashMap, path::Path, sync::Arc, time::SystemTime}; +use nac3parser::{ast::{Expr, ExprKind, StmtKind}, parser}; use nac3core::{ codegen::{ concrete_type::ConcreteTypeStore, CodeGenTask, DefaultCodeGenerator, WithCall, @@ -17,11 +14,11 @@ use nac3core::{ }, symbol_resolver::SymbolResolver, toplevel::{ - composer::TopLevelComposer, + composer::{TopLevelComposer, CoreMode}, TopLevelDef, helper::parse_parameter_default_value, type_annotation::*, }, - typecheck::typedef::FunSignature, + typecheck::{type_inferencer::PrimitiveStore, typedef::{Type, Unifier, FunSignature}} }; mod basic_symbol_resolver; @@ -47,7 +44,10 @@ fn main() { }; let primitive: PrimitiveStore = TopLevelComposer::make_primitives().0; - let (mut composer, builtins_def, builtins_ty) = TopLevelComposer::new(vec![]); + let (mut composer, builtins_def, builtins_ty) = TopLevelComposer::new( + vec![], + CoreMode::Standalone + ); let internal_resolver: Arc = ResolverInternal { id_to_type: builtins_ty.into(), -- 2.44.2 From dba165d95c238156fd04a1790775b0b5113b0d29 Mon Sep 17 00:00:00 2001 From: ychenfo Date: Fri, 17 Dec 2021 04:44:16 +0800 Subject: [PATCH 5/7] nac3core/artiq/standalone: composer only config kernel annotation names --- nac3artiq/src/lib.rs | 12 +++++-- nac3core/src/toplevel/composer.rs | 55 ++++++++++++++----------------- nac3standalone/src/main.rs | 4 +-- 3 files changed, 35 insertions(+), 36 deletions(-) diff --git a/nac3artiq/src/lib.rs b/nac3artiq/src/lib.rs index 623b1220..de34180e 100644 --- a/nac3artiq/src/lib.rs +++ b/nac3artiq/src/lib.rs @@ -22,7 +22,7 @@ use parking_lot::{Mutex, RwLock}; use nac3core::{ codegen::{concrete_type::ConcreteTypeStore, CodeGenTask, WithCall, WorkerRegistry}, symbol_resolver::SymbolResolver, - toplevel::{composer::{TopLevelComposer, CoreMode}, DefinitionId, GenCall, TopLevelDef}, + toplevel::{composer::{TopLevelComposer, ComposerConfig}, DefinitionId, GenCall, TopLevelDef}, typecheck::typedef::{FunSignature, FuncArg}, typecheck::{type_inferencer::PrimitiveStore, typedef::Type}, }; @@ -239,7 +239,10 @@ impl Nac3 { }))), ), ]; - let (_, builtins_def, builtins_ty) = TopLevelComposer::new(builtins.clone(), CoreMode::Artiq); + let (_, builtins_def, builtins_ty) = TopLevelComposer::new(builtins.clone(), ComposerConfig { + kernel_ann: Some("Kernel"), + kernel_invariant_ann: "KernelInvariant" + }); let builtins_mod = PyModule::import(py, "builtins").unwrap(); let id_fn = builtins_mod.getattr("id").unwrap(); @@ -375,7 +378,10 @@ impl Nac3 { filename: &str, py: Python, ) -> PyResult<()> { - let (mut composer, _, _) = TopLevelComposer::new(self.builtins.clone(), CoreMode::Artiq); + let (mut composer, _, _) = TopLevelComposer::new(self.builtins.clone(), ComposerConfig { + kernel_ann: Some("Kernel"), + kernel_invariant_ann: "KernelInvariant" + }); let mut id_to_def = HashMap::new(); let mut id_to_type = HashMap::new(); diff --git a/nac3core/src/toplevel/composer.rs b/nac3core/src/toplevel/composer.rs index 3398adf8..6fe1dac7 100644 --- a/nac3core/src/toplevel/composer.rs +++ b/nac3core/src/toplevel/composer.rs @@ -9,9 +9,9 @@ use crate::{ use super::*; -pub enum CoreMode { - Artiq, - Standalone +pub struct ComposerConfig { + pub kernel_ann: Option<&'static str>, + pub kernel_invariant_ann: &'static str, } type DefAst = (Arc>, Option>); @@ -31,12 +31,15 @@ pub struct TopLevelComposer { // number of built-in function and classes in the definition list, later skip pub builtin_num: usize, // indicate the mode that we are using the core - pub mode: CoreMode, + pub core_config: ComposerConfig, } impl Default for TopLevelComposer { fn default() -> Self { - Self::new(vec![], CoreMode::Standalone).0 + Self::new(vec![], ComposerConfig { + kernel_ann: None, + kernel_invariant_ann: "Invariant" + }).0 } } @@ -45,7 +48,7 @@ impl TopLevelComposer { /// resolver can later figure out primitive type definitions when passed a primitive type name pub fn new( builtins: Vec<(StrRef, FunSignature, Arc)>, - mode: CoreMode + core_config: ComposerConfig ) -> (Self, HashMap, HashMap) { let mut primitives = Self::make_primitives(); let (mut definition_ast_list, builtin_name_list) = builtins::get_builtins(&mut primitives); @@ -116,7 +119,7 @@ impl TopLevelComposer { keyword_list, defined_names, method_class, - mode + core_config, }, builtin_id, builtin_ty, @@ -563,7 +566,7 @@ impl TopLevelComposer { unifier, primitives, &mut type_var_to_concrete_def, - (&self.keyword_list, &self.mode) + (&self.keyword_list, &self.core_config) )? } } @@ -836,9 +839,9 @@ impl TopLevelComposer { unifier: &mut Unifier, primitives: &PrimitiveStore, type_var_to_concrete_def: &mut HashMap, - core_info: (&HashSet, &CoreMode), + core_info: (&HashSet, &ComposerConfig), ) -> Result<(), String> { - let (keyword_list, core_mode) = core_info; + let (keyword_list, core_config) = core_info; let mut class_def = class_def.write(); let ( class_id, @@ -1068,27 +1071,17 @@ impl TopLevelComposer { let dummy_field_type = unifier.get_fresh_var().0; // handle Kernel[T], KernelInvariant[T] - let (annotation, mutable) = { - match core_mode { - CoreMode::Artiq => match &annotation.as_ref().node { - ast::ExprKind::Subscript { value, slice, .. } if matches!( - &value.node, - ast::ExprKind::Name { id, .. } if id == &"Kernel".into() - ) => (slice, true), - ast::ExprKind::Subscript { value, slice, .. } if matches!( - &value.node, - ast::ExprKind::Name { id, .. } if id == &"KernelInvariant".into() - ) => (slice, false), - _ => continue // ignore fields annotated otherwise - }, - CoreMode::Standalone => match &annotation.as_ref().node { - ast::ExprKind::Subscript { value, slice, .. } if matches!( - &value.node, - ast::ExprKind::Name { id, .. } if id == &"Invariant".into() - ) => (slice, false), - _ => (annotation, true) - } - } + let (annotation, mutable) = match &annotation.node { + ast::ExprKind::Subscript { value, slice, .. } if matches!( + &value.node, + ast::ExprKind::Name { id, .. } if id == &core_config.kernel_invariant_ann.into() + ) => (slice, false), + ast::ExprKind::Subscript { value, slice, .. } if matches!( + &value.node, + ast::ExprKind::Name { id, .. } if core_config.kernel_ann.map_or(false, |c| id == &c.into()) + ) => (slice, true), + _ if core_config.kernel_ann.is_none() => (annotation, true), + _ => continue // ignore fields annotated otherwise }; class_fields_def.push((*attr, dummy_field_type, mutable)); diff --git a/nac3standalone/src/main.rs b/nac3standalone/src/main.rs index abc8e821..accc8fe3 100644 --- a/nac3standalone/src/main.rs +++ b/nac3standalone/src/main.rs @@ -14,7 +14,7 @@ use nac3core::{ }, symbol_resolver::SymbolResolver, toplevel::{ - composer::{TopLevelComposer, CoreMode}, + composer::{TopLevelComposer, ComposerConfig}, TopLevelDef, helper::parse_parameter_default_value, type_annotation::*, }, @@ -46,7 +46,7 @@ fn main() { let primitive: PrimitiveStore = TopLevelComposer::make_primitives().0; let (mut composer, builtins_def, builtins_ty) = TopLevelComposer::new( vec![], - CoreMode::Standalone + ComposerConfig { kernel_ann: None, kernel_invariant_ann: "Invariant" } ); let internal_resolver: Arc = ResolverInternal { -- 2.44.2 From 5f24d63b0bb09bc210ca796d0379a988e60e2c58 Mon Sep 17 00:00:00 2001 From: ychenfo Date: Sat, 18 Dec 2021 01:46:30 +0800 Subject: [PATCH 6/7] nac3core: remove misleading comment --- nac3core/src/toplevel/composer.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/nac3core/src/toplevel/composer.rs b/nac3core/src/toplevel/composer.rs index 6fe1dac7..9f952575 100644 --- a/nac3core/src/toplevel/composer.rs +++ b/nac3core/src/toplevel/composer.rs @@ -30,7 +30,6 @@ pub struct TopLevelComposer { pub method_class: HashMap, // number of built-in function and classes in the definition list, later skip pub builtin_num: usize, - // indicate the mode that we are using the core pub core_config: ComposerConfig, } -- 2.44.2 From cbf83bcc8c3edca55237887300050e762920fbf7 Mon Sep 17 00:00:00 2001 From: ychenfo Date: Sun, 19 Dec 2021 02:55:38 +0800 Subject: [PATCH 7/7] nac3core/standalone: use default for ComposerConfig --- nac3core/src/toplevel/composer.rs | 14 ++++++++++---- nac3standalone/src/main.rs | 2 +- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/nac3core/src/toplevel/composer.rs b/nac3core/src/toplevel/composer.rs index 9f952575..4c633691 100644 --- a/nac3core/src/toplevel/composer.rs +++ b/nac3core/src/toplevel/composer.rs @@ -14,6 +14,15 @@ pub struct ComposerConfig { pub kernel_invariant_ann: &'static str, } +impl Default for ComposerConfig { + fn default() -> Self { + ComposerConfig { + kernel_ann: None, + kernel_invariant_ann: "Invariant" + } + } +} + type DefAst = (Arc>, Option>); pub struct TopLevelComposer { // list of top level definitions, same as top level context @@ -35,10 +44,7 @@ pub struct TopLevelComposer { impl Default for TopLevelComposer { fn default() -> Self { - Self::new(vec![], ComposerConfig { - kernel_ann: None, - kernel_invariant_ann: "Invariant" - }).0 + Self::new(vec![], Default::default()).0 } } diff --git a/nac3standalone/src/main.rs b/nac3standalone/src/main.rs index accc8fe3..8212b923 100644 --- a/nac3standalone/src/main.rs +++ b/nac3standalone/src/main.rs @@ -46,7 +46,7 @@ fn main() { let primitive: PrimitiveStore = TopLevelComposer::make_primitives().0; let (mut composer, builtins_def, builtins_ty) = TopLevelComposer::new( vec![], - ComposerConfig { kernel_ann: None, kernel_invariant_ann: "Invariant" } + Default::default() ); let internal_resolver: Arc = ResolverInternal { -- 2.44.2