Aadityavardhan Narayan: Progress toward support

for static class attributes
This commit is contained in:
aadityavardhan 2022-08-21 07:57:59 +05:30
parent b514f91441
commit f73f784cc0
133 changed files with 101 additions and 7 deletions

6
.gitignore vendored Normal file → Executable file
View File

@ -1,3 +1,9 @@
__pycache__ __pycache__
/target /target
windows/msys2 windows/msys2
nac3standalone/demo/src/test.py
nac3standalone/demo/{
interpreted.log
nac3standalone/demo/module.o
nac3standalone/demo/demo
nac3standalone/demo/run.log

0
Cargo.lock generated Normal file → Executable file
View File

0
Cargo.toml Normal file → Executable file
View File

0
README.md Normal file → Executable file
View File

0
flake.lock Normal file → Executable file
View File

0
flake.nix Normal file → Executable file
View File

0
nac3.svg Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

0
nac3artiq/Cargo.toml Normal file → Executable file
View File

0
nac3artiq/demo/demo.py Normal file → Executable file
View File

0
nac3artiq/demo/device_db.py Normal file → Executable file
View File

0
nac3artiq/demo/embedding_map.py Normal file → Executable file
View File

0
nac3artiq/demo/min_artiq.py Normal file → Executable file
View File

0
nac3artiq/src/codegen.rs Normal file → Executable file
View File

0
nac3artiq/src/kernel.ld Normal file → Executable file
View File

0
nac3artiq/src/lib.rs Normal file → Executable file
View File

0
nac3artiq/src/symbol_resolver.rs Normal file → Executable file
View File

0
nac3artiq/src/timeline.rs Normal file → Executable file
View File

0
nac3ast/Cargo.toml Normal file → Executable file
View File

0
nac3ast/Python.asdl Normal file → Executable file
View File

0
nac3ast/asdl.py Normal file → Executable file
View File

0
nac3ast/src/ast_gen.rs Normal file → Executable file
View File

0
nac3ast/src/constant.rs Normal file → Executable file
View File

0
nac3ast/src/fold_helpers.rs Normal file → Executable file
View File

0
nac3ast/src/impls.rs Normal file → Executable file
View File

0
nac3ast/src/lib.rs Normal file → Executable file
View File

0
nac3ast/src/location.rs Normal file → Executable file
View File

0
nac3core/Cargo.toml Normal file → Executable file
View File

0
nac3core/build.rs Normal file → Executable file
View File

0
nac3core/src/codegen/concrete_type.rs Normal file → Executable file
View File

0
nac3core/src/codegen/expr.rs Normal file → Executable file
View File

0
nac3core/src/codegen/generator.rs Normal file → Executable file
View File

0
nac3core/src/codegen/irrt/irrt.c Normal file → Executable file
View File

0
nac3core/src/codegen/irrt/mod.rs Normal file → Executable file
View File

0
nac3core/src/codegen/mod.rs Normal file → Executable file
View File

0
nac3core/src/codegen/stmt.rs Normal file → Executable file
View File

0
nac3core/src/codegen/test.rs Normal file → Executable file
View File

0
nac3core/src/lib.rs Normal file → Executable file
View File

0
nac3core/src/symbol_resolver.rs Normal file → Executable file
View File

6
nac3core/src/toplevel/builtins.rs Normal file → Executable file
View File

@ -74,6 +74,8 @@ pub fn get_exn_constructor(
constructor: Some(signature), constructor: Some(signature),
resolver: None, resolver: None,
loc: None, loc: None,
// Make TopLevelDef::Class initlializer compatible
static_fields: Default::default(),
}; };
(fun_def, class_def, signature, exn_type) (fun_def, class_def, signature, exn_type)
} }
@ -175,6 +177,8 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo {
type_vars: Default::default(), type_vars: Default::default(),
fields: exception_fields, fields: exception_fields,
methods: Default::default(), methods: Default::default(),
// Make TopLevelDef::Class initlializer compatible
static_fields: Default::default(),
ancestors: vec![], ancestors: vec![],
constructor: None, constructor: None,
resolver: None, resolver: None,
@ -200,6 +204,8 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo {
object_id: DefinitionId(10), object_id: DefinitionId(10),
type_vars: vec![option_ty_var], type_vars: vec![option_ty_var],
fields: vec![], fields: vec![],
// Make TopLevelDef::Class initlializer compatible
static_fields: vec![],
methods: vec![ methods: vec![
("is_some".into(), is_some_ty.0, DefinitionId(11)), ("is_some".into(), is_some_ty.0, DefinitionId(11)),
("is_none".into(), is_some_ty.0, DefinitionId(12)), ("is_none".into(), is_some_ty.0, DefinitionId(12)),

91
nac3core/src/toplevel/composer.rs Normal file → Executable file
View File

@ -1040,6 +1040,7 @@ impl TopLevelComposer {
class_body_ast, class_body_ast,
_class_ancestor_def, _class_ancestor_def,
class_fields_def, class_fields_def,
class_static_fields_def, // Introduce static class attribute list into the function
class_methods_def, class_methods_def,
class_type_vars_def, class_type_vars_def,
class_resolver, class_resolver,
@ -1047,6 +1048,7 @@ impl TopLevelComposer {
object_id, object_id,
ancestors, ancestors,
fields, fields,
static_fields,
methods, methods,
resolver, resolver,
type_vars, type_vars,
@ -1054,7 +1056,7 @@ impl TopLevelComposer {
} = &mut *class_def } = &mut *class_def
{ {
if let ast::StmtKind::ClassDef { name, bases, body, .. } = &class_ast { if let ast::StmtKind::ClassDef { name, bases, body, .. } = &class_ast {
(*object_id, *name, bases, body, ancestors, fields, methods, type_vars, resolver) (*object_id, *name, bases, body, ancestors, fields, static_fields, methods, type_vars, resolver)
} else { } else {
unreachable!("here must be class def ast"); unreachable!("here must be class def ast");
} }
@ -1268,7 +1270,8 @@ impl TopLevelComposer {
.unify(method_dummy_ty, method_type) .unify(method_dummy_ty, method_type)
.map_err(|e| e.to_display(unifier).to_string())?; .map_err(|e| e.to_display(unifier).to_string())?;
} }
ast::StmtKind::AnnAssign { target, annotation, value: None, .. } => { // Reset value from none since fields in the form "ATTR_0: int32 = 10" need to be initialised
ast::StmtKind::AnnAssign { target, annotation, value, .. } => {
if let ast::ExprKind::Name { id: attr, .. } = &target.node { if let ast::ExprKind::Name { id: attr, .. } = &target.node {
if defined_fields.insert(attr.to_string()) { if defined_fields.insert(attr.to_string()) {
let dummy_field_type = unifier.get_dummy_var().0; let dummy_field_type = unifier.get_dummy_var().0;
@ -1294,6 +1297,10 @@ impl TopLevelComposer {
_ if core_config.kernel_ann.is_none() => (annotation, true), _ if core_config.kernel_ann.is_none() => (annotation, true),
_ => continue, // ignore fields annotated otherwise _ => continue, // ignore fields annotated otherwise
}; };
// If the value node is provided, then it must be a static class attribute
if let Option::Some(..) = &value{
class_static_fields_def.push((*attr, dummy_field_type, mutable));
}
class_fields_def.push((*attr, dummy_field_type, mutable)); class_fields_def.push((*attr, dummy_field_type, mutable));
let parsed_annotation = parse_ast_to_type_annotation_kinds( let parsed_annotation = parse_ast_to_type_annotation_kinds(
@ -1335,7 +1342,76 @@ impl TopLevelComposer {
)); ));
} }
} }
ast::StmtKind::Assign { .. } => {}, // we don't class attributes
// Add assign branch since fields in the form "ATTR_0 = 5" in the class body qualify as static class attributes
// However, type checking and expression folding needs to be performed in order to correctly
// Infer the type of target
ast::StmtKind::Assign { targets, value, .. } => {
// let ctx = Arc::new(self.make_top_level_context());
// let mut identifiers = {
// let mut result: HashSet<_> = HashSet::new();
// if self_type.is_some() {
// result.insert("self".into());
// }
// result.extend(inst_args.iter().map(|x| x.name));
// result
// };
// let mut calls: HashMap<CodeLocation, CallId> = HashMap::new();
// let mut inferencer = Inferencer {
// top_level: ctx.as_ref(),
// defined_identifiers: identifiers.clone(),
// function_data: &mut FunctionData {
// resolver: class_resolver.as_ref().unwrap().clone(),
// return_type: if unifier.unioned(inst_ret, primitives_ty.none) {
// None
// } else {
// Some(inst_ret)
// },
// // NOTE: allowed type vars
// bound_variables: no_range_vars.clone(),
// },
// unifier,
// variable_mapping: {
// let mut result: HashMap<StrRef, Type> = HashMap::new();
// if let Some(self_ty) = self_type {
// result.insert("self".into(), self_ty);
// }
// result.extend(inst_args.iter().map(|x| (x.name, x.ty)));
// result
// },
// primitives: primitives_ty,
// virtual_checks: &mut Vec::new(),
// calls: &mut calls,
// in_handler: false,
// };
for target in targets {
if let ast::ExprKind::Name { id: attr, .. } = &target.node {
if defined_fields.insert(attr.to_string()) {
let dummy_field_type = unifier.get_dummy_var().0;
class_static_fields_def.push((*attr, dummy_field_type, true));
class_fields_def.push((*attr, dummy_field_type, true));
// let value = inferencer.fold_expr(*value)?;
// let value_ty = value.custom.unwrap();
} else {
return Err(format!(
"same class fields `{}` defined twice (at {})",
attr, target.location
));
}
} else {
return Err(format!(
"unsupported statement type in class definition body (at {})",
target.location
));
}
}
},
ast::StmtKind::Pass { .. } => {} ast::StmtKind::Pass { .. } => {}
ast::StmtKind::Expr { value: _, .. } => {} // typically a docstring; ignoring all expressions matches CPython behavior ast::StmtKind::Expr { value: _, .. } => {} // typically a docstring; ignoring all expressions matches CPython behavior
_ => { _ => {
@ -1516,6 +1592,7 @@ impl TopLevelComposer {
ancestors, ancestors,
methods, methods,
fields, fields,
static_fields, // Introduce static fields for (un)initialization check
type_vars, type_vars,
name: class_name, name: class_name,
object_id, object_id,
@ -1618,11 +1695,13 @@ impl TopLevelComposer {
unreachable!("must be init function here") unreachable!("must be init function here")
} }
let all_inited = Self::get_all_assigned_field(body.as_slice())?; let all_inited = Self::get_all_assigned_field(body.as_slice())?;
for (f, _, _) in fields { // If a field is uninitialized but also a static class attribute, don't
if !all_inited.contains(f) { // throw an error due to uninitialization
for f in fields {
if !all_inited.contains(&f.0) && !static_fields.contains(&f) {
return Err(format!( return Err(format!(
"fields `{}` of class `{}` not fully initialized in the initializer (at {})", "fields `{}` of class `{}` not fully initialized in the initializer (at {})",
f, &f.0,
class_name, class_name,
body[0].location, body[0].location,
)); ));

1
nac3core/src/toplevel/helper.rs Normal file → Executable file
View File

@ -162,6 +162,7 @@ impl TopLevelComposer {
object_id: DefinitionId(index), object_id: DefinitionId(index),
type_vars: Default::default(), type_vars: Default::default(),
fields: Default::default(), fields: Default::default(),
static_fields: Default::default(), // Initialize for constructor
methods: Default::default(), methods: Default::default(),
ancestors: Default::default(), ancestors: Default::default(),
constructor, constructor,

2
nac3core/src/toplevel/mod.rs Normal file → Executable file
View File

@ -92,6 +92,8 @@ pub enum TopLevelDef {
// name, type, is mutable // name, type, is mutable
fields: Vec<(StrRef, Type, bool)>, fields: Vec<(StrRef, Type, bool)>,
// class methods, pointing to the corresponding function definition. // class methods, pointing to the corresponding function definition.
static_fields: Vec<(StrRef, Type, bool)>,
// list of static data members
methods: Vec<(StrRef, Type, DefinitionId)>, methods: Vec<(StrRef, Type, DefinitionId)>,
// ancestor classes, including itself. // ancestor classes, including itself.
ancestors: Vec<TypeAnnotation>, ancestors: Vec<TypeAnnotation>,

0
nac3core/src/toplevel/test.rs Normal file → Executable file
View File

0
nac3core/src/toplevel/type_annotation.rs Normal file → Executable file
View File

0
nac3core/src/typecheck/function_check.rs Normal file → Executable file
View File

0
nac3core/src/typecheck/magic_methods.rs Normal file → Executable file
View File

0
nac3core/src/typecheck/mod.rs Normal file → Executable file
View File

0
nac3core/src/typecheck/type_error.rs Normal file → Executable file
View File

0
nac3core/src/typecheck/type_inferencer/mod.rs Normal file → Executable file
View File

0
nac3core/src/typecheck/type_inferencer/test.rs Normal file → Executable file
View File

2
nac3core/src/typecheck/typedef/mod.rs Normal file → Executable file
View File

@ -513,7 +513,7 @@ impl Unifier {
fn unify_impl(&mut self, a: Type, b: Type, swapped: bool) -> Result<(), TypeError> { fn unify_impl(&mut self, a: Type, b: Type, swapped: bool) -> Result<(), TypeError> {
use TypeEnum::*; use TypeEnum::*;
if !swapped { if !swapped {
let rep_a = self.unification_table.get_representative(a); let rep_a = self.unification_table.get_representative(a);
let rep_b = self.unification_table.get_representative(b); let rep_b = self.unification_table.get_representative(b);

0
nac3core/src/typecheck/typedef/test.rs Normal file → Executable file
View File

0
nac3core/src/typecheck/unification_table.rs Normal file → Executable file
View File

0
nac3ld/Cargo.toml Normal file → Executable file
View File

0
nac3ld/src/dwarf.rs Normal file → Executable file
View File

0
nac3ld/src/elf.rs Normal file → Executable file
View File

0
nac3ld/src/lib.rs Normal file → Executable file
View File

0
nac3parser/Cargo.toml Normal file → Executable file
View File

0
nac3parser/README.md Normal file → Executable file
View File

0
nac3parser/build.rs Normal file → Executable file
View File

0
nac3parser/src/config_comment_helper.rs Normal file → Executable file
View File

0
nac3parser/src/error.rs Normal file → Executable file
View File

0
nac3parser/src/fstring.rs Normal file → Executable file
View File

0
nac3parser/src/function.rs Normal file → Executable file
View File

0
nac3parser/src/lexer.rs Normal file → Executable file
View File

0
nac3parser/src/lib.rs Normal file → Executable file
View File

0
nac3parser/src/mode.rs Normal file → Executable file
View File

0
nac3parser/src/parser.rs Normal file → Executable file
View File

0
nac3parser/src/python.lalrpop Normal file → Executable file
View File

View File

View File

View File

View File

View File

View File

View File

Some files were not shown because too many files have changed in this diff Show More