diff --git a/nac3artiq/src/lib.rs b/nac3artiq/src/lib.rs index ffc0058b2..343c86e54 100644 --- a/nac3artiq/src/lib.rs +++ b/nac3artiq/src/lib.rs @@ -10,6 +10,7 @@ use inkwell::{ targets::*, OptimizationLevel, }; +use nac3core::toplevel::builtins::get_exn_constructor; use nac3core::typecheck::typedef::{TypeEnum, Unifier}; use nac3parser::{ ast::{self, ExprKind, Stmt, StmtKind, StrRef}, @@ -82,8 +83,6 @@ struct Nac3 { time_fns: &'static (dyn TimeFns + Sync), primitive: PrimitiveStore, builtins: Vec<(StrRef, FunSignature, Arc)>, - builtins_ty: HashMap, - builtins_def: HashMap, pyid_to_def: Arc>>, primitive_ids: PrimitivePythonId, working_directory: TempDir, @@ -260,6 +259,34 @@ impl Nac3 { } } +fn add_exceptions( + composer: &mut TopLevelComposer, + builtin_def: &mut HashMap, + builtin_ty: &mut HashMap, + error_names: &[&str] +) -> Vec { + let mut types = Vec::new(); + // note: this is only for builtin exceptions, i.e. the exception name is "0:{exn}" + for name in error_names { + let def_id = composer.definition_ast_list.len(); + let (exception_fn, exception_class, exception_cons, exception_type) = get_exn_constructor( + name, + // class id + def_id, + // constructor id + def_id + 1, + &mut composer.unifier, + &composer.primitives_ty + ); + composer.definition_ast_list.push((Arc::new(RwLock::new(exception_class)), None)); + composer.definition_ast_list.push((Arc::new(RwLock::new(exception_fn)), None)); + builtin_ty.insert((*name).into(), exception_cons); + builtin_def.insert((*name).into(), DefinitionId(def_id)); + types.push(exception_type); + } + types +} + #[pymethods] impl Nac3 { #[new] @@ -321,68 +348,42 @@ impl Nac3 { }))), ), ]; - 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(); let numpy_mod = PyModule::import(py, "numpy").unwrap(); let typing_mod = PyModule::import(py, "typing").unwrap(); let types_mod = PyModule::import(py, "types").unwrap(); + + let get_id = |x| id_fn.call1((x,)).unwrap().extract().unwrap(); + let get_attr_id = |obj: &PyModule, attr| id_fn.call1((obj.getattr(attr).unwrap(),)) + .unwrap().extract().unwrap(); let primitive_ids = PrimitivePythonId { - virtual_id: id_fn - .call1((builtins_mod - .getattr("globals") - .unwrap() - .call0() - .unwrap() - .get_item("virtual") - .unwrap(),)) - .unwrap() - .extract() - .unwrap(), + virtual_id: get_id( + builtins_mod + .getattr("globals") + .unwrap() + .call0() + .unwrap() + .get_item("virtual") + .unwrap( + )), generic_alias: ( - id_fn - .call1((typing_mod.getattr("_GenericAlias").unwrap(),)) - .unwrap() - .extract() - .unwrap(), - id_fn - .call1((types_mod.getattr("GenericAlias").unwrap(),)) - .unwrap() - .extract() - .unwrap(), + get_attr_id(typing_mod, "_GenericAlias"), + get_attr_id(types_mod, "GenericAlias"), ), - none: id_fn.call1((builtins_mod.getattr("None").unwrap(),)).unwrap().extract().unwrap(), - typevar: id_fn - .call1((typing_mod.getattr("TypeVar").unwrap(),)) - .unwrap() - .extract() - .unwrap(), - int: id_fn.call1((builtins_mod.getattr("int").unwrap(),)).unwrap().extract().unwrap(), - int32: id_fn.call1((numpy_mod.getattr("int32").unwrap(),)).unwrap().extract().unwrap(), - int64: id_fn.call1((numpy_mod.getattr("int64").unwrap(),)).unwrap().extract().unwrap(), - uint32: id_fn.call1((numpy_mod.getattr("uint32").unwrap(),)).unwrap().extract().unwrap(), - uint64: id_fn.call1((numpy_mod.getattr("uint64").unwrap(),)).unwrap().extract().unwrap(), - bool: id_fn.call1((builtins_mod.getattr("bool").unwrap(),)).unwrap().extract().unwrap(), - float: id_fn - .call1((builtins_mod.getattr("float").unwrap(),)) - .unwrap() - .extract() - .unwrap(), - list: id_fn.call1((builtins_mod.getattr("list").unwrap(),)).unwrap().extract().unwrap(), - tuple: id_fn - .call1((builtins_mod.getattr("tuple").unwrap(),)) - .unwrap() - .extract() - .unwrap(), - exception: id_fn - .call1((builtins_mod.getattr("Exception").unwrap(),)) - .unwrap() - .extract() - .unwrap(), + none: get_attr_id(builtins_mod, "None"), + typevar: get_attr_id(typing_mod, "TypeVar"), + int: get_attr_id(builtins_mod, "int"), + int32: get_attr_id(numpy_mod, "int32"), + int64: get_attr_id(numpy_mod, "int64"), + uint32: get_attr_id(numpy_mod, "uint32"), + uint64: get_attr_id(numpy_mod, "uint64"), + bool: get_attr_id(builtins_mod, "bool"), + float: get_attr_id(builtins_mod, "float"), + list: get_attr_id(builtins_mod, "list"), + tuple: get_attr_id(builtins_mod, "tuple"), + exception: get_attr_id(builtins_mod, "Exception"), }; let working_directory = tempfile::Builder::new().prefix("nac3-").tempdir().unwrap(); @@ -393,8 +394,6 @@ impl Nac3 { time_fns, primitive, builtins, - builtins_ty, - builtins_def, primitive_ids, top_levels: Default::default(), pyid_to_def: Default::default(), @@ -440,7 +439,7 @@ impl Nac3 { embedding_map: &PyAny, py: Python, ) -> PyResult<()> { - let (mut composer, _, _) = TopLevelComposer::new( + let (mut composer, mut builtins_def, mut builtins_ty) = TopLevelComposer::new( self.builtins.clone(), ComposerConfig { kernel_ann: Some("Kernel"), kernel_invariant_ann: "KernelInvariant" }, ); @@ -462,9 +461,16 @@ impl Nac3 { store_obj: store_obj.clone(), store_str, }; - let mut module_to_resolver_cache: HashMap = HashMap::new(); let pyid_to_type = Arc::new(RwLock::new(HashMap::::new())); + let exception_names = [ + "ValueError", + "RuntimeError" + ]; + add_exceptions(&mut composer, &mut builtins_def, &mut builtins_ty, &exception_names); + + let mut module_to_resolver_cache: HashMap = HashMap::new(); + let global_value_ids = Arc::new(RwLock::new(HashSet::::new())); let mut rpc_ids = vec![]; for (stmt, path, module) in self.top_levels.iter() { @@ -494,8 +500,8 @@ impl Nac3 { name_to_pyid.insert(key.into(), val); } let resolver = Arc::new(Resolver(Arc::new(InnerResolver { - id_to_type: self.builtins_ty.clone().into(), - id_to_def: self.builtins_def.clone().into(), + id_to_type: builtins_ty.clone().into(), + id_to_def: builtins_def.clone().into(), pyid_to_def: self.pyid_to_def.clone(), pyid_to_type: pyid_to_type.clone(), primitive_ids: self.primitive_ids.clone(), @@ -579,8 +585,8 @@ impl Nac3 { let mut synthesized = parse_program(&synthesized, "__nac3_synthesized_modinit__".to_string().into()).unwrap(); let resolver = Arc::new(Resolver(Arc::new(InnerResolver { - id_to_type: self.builtins_ty.clone().into(), - id_to_def: self.builtins_def.clone().into(), + id_to_type: builtins_ty.clone().into(), + id_to_def: builtins_def.clone().into(), pyid_to_def: self.pyid_to_def.clone(), pyid_to_type: pyid_to_type.clone(), primitive_ids: self.primitive_ids.clone(), diff --git a/nac3core/src/toplevel/builtins.rs b/nac3core/src/toplevel/builtins.rs index d045545f9..64a52ea02 100644 --- a/nac3core/src/toplevel/builtins.rs +++ b/nac3core/src/toplevel/builtins.rs @@ -9,7 +9,92 @@ use inkwell::{types::BasicType, FloatPredicate, IntPredicate}; type BuiltinInfo = (Vec<(Arc>, Option)>, &'static [&'static str]); +pub fn get_exn_constructor( + name: &str, + class_id: usize, + cons_id: usize, + unifier: &mut Unifier, + primitives: &PrimitiveStore +)-> (TopLevelDef, TopLevelDef, Type, Type) { + let int32 = primitives.int32; + let int64 = primitives.int64; + let string = primitives.str; + let exception_fields = vec![ + ("__name__".into(), int32, true), + ("__file__".into(), string, true), + ("__line__".into(), int32, true), + ("__col__".into(), int32, true), + ("__func__".into(), string, true), + ("__message__".into(), string, true), + ("__param0__".into(), int64, true), + ("__param1__".into(), int64, true), + ("__param2__".into(), int64, true), + ]; + let exn_cons_args = vec![ + FuncArg { + name: "msg".into(), + ty: string, + default_value: Some(SymbolValue::Str("".into())), + }, + FuncArg { name: "param0".into(), ty: int64, default_value: Some(SymbolValue::I64(0)) }, + FuncArg { name: "param1".into(), ty: int64, default_value: Some(SymbolValue::I64(0)) }, + FuncArg { name: "param2".into(), ty: int64, default_value: Some(SymbolValue::I64(0)) }, + ]; + let exn_type = unifier.add_ty(TypeEnum::TObj { + obj_id: DefinitionId(class_id), + fields: exception_fields.iter().map(|(a, b, c)| (*a, (*b, *c))).collect(), + params: Default::default(), + }); + let signature = unifier.add_ty(TypeEnum::TFunc(FunSignature { + args: exn_cons_args, + ret: exn_type, + vars: Default::default(), + })); + let fun_def = TopLevelDef::Function { + name: format!("{}.__init__", name), + simple_name: "__init__".into(), + signature, + var_id: Default::default(), + instance_to_symbol: Default::default(), + instance_to_stmt: Default::default(), + resolver: None, + codegen_callback: Some(Arc::new(GenCall::new(Box::new(exn_constructor)))), + loc: None, + }; + let class_def = TopLevelDef::Class { + name: name.into(), + object_id: DefinitionId(class_id), + type_vars: Default::default(), + fields: exception_fields, + methods: vec![("__init__".into(), signature, DefinitionId(cons_id))], + ancestors: vec![ + TypeAnnotation::CustomClass { id: DefinitionId(class_id), params: Default::default() }, + TypeAnnotation::CustomClass { id: DefinitionId(7), params: Default::default() }, + ], + constructor: Some(signature), + resolver: None, + loc: None, + }; + (fun_def, class_def, signature, exn_type) +} + pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo { + // please refer to the top_level_def_list below for the definition IDs + let (div_by_zero_fun, div_by_zero_class, _, _) = get_exn_constructor( + "DivisionByZeroError", + 12, + 10, + &mut primitives.1, + &primitives.0, + ); + let (index_err_fun, index_err_class, _, _) = get_exn_constructor( + "IndexError", + 13, + 11, + &mut primitives.1, + &primitives.0, + ); + let int32 = primitives.0.int32; let int64 = primitives.0.int64; let uint32 = primitives.0.uint32; @@ -24,7 +109,6 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo { None, ); let var_map: HashMap<_, _> = vec![(num_ty.1, num_ty.0)].into_iter().collect(); - let exception_fields = vec![ ("__name__".into(), int32, true), ("__file__".into(), string, true), @@ -36,36 +120,7 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo { ("__param1__".into(), int64, true), ("__param2__".into(), int64, true), ]; - let div_by_zero = primitives.1.add_ty(TypeEnum::TObj { - obj_id: DefinitionId(12), - fields: exception_fields.iter().map(|(a, b, c)| (*a, (*b, *c))).collect(), - params: Default::default(), - }); - let index_error = primitives.1.add_ty(TypeEnum::TObj { - obj_id: DefinitionId(13), - fields: exception_fields.iter().map(|(a, b, c)| (*a, (*b, *c))).collect(), - params: Default::default(), - }); - let exn_cons_args = vec![ - FuncArg { - name: "msg".into(), - ty: string, - default_value: Some(SymbolValue::Str("".into())), - }, - FuncArg { name: "param0".into(), ty: int64, default_value: Some(SymbolValue::I64(0)) }, - FuncArg { name: "param1".into(), ty: int64, default_value: Some(SymbolValue::I64(0)) }, - FuncArg { name: "param2".into(), ty: int64, default_value: Some(SymbolValue::I64(0)) }, - ]; - let div_by_zero_signature = primitives.1.add_ty(TypeEnum::TFunc(FunSignature { - args: exn_cons_args.clone(), - ret: div_by_zero, - vars: Default::default(), - })); - let index_error_signature = primitives.1.add_ty(TypeEnum::TFunc(FunSignature { - args: exn_cons_args, - ret: index_error, - vars: Default::default(), - })); + let top_level_def_list = vec![ Arc::new(RwLock::new(TopLevelComposer::make_top_level_class_def( 0, @@ -120,7 +175,7 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo { name: "Exception".into(), object_id: DefinitionId(7), type_vars: Default::default(), - fields: exception_fields.clone(), + fields: exception_fields, methods: Default::default(), ancestors: vec![], constructor: None, @@ -141,56 +196,10 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo { None, None, ))), - Arc::new(RwLock::new(TopLevelDef::Function { - name: "ZeroDivisionError.__init__".into(), - simple_name: "__init__".into(), - signature: div_by_zero_signature, - var_id: Default::default(), - instance_to_symbol: Default::default(), - instance_to_stmt: Default::default(), - resolver: None, - codegen_callback: Some(Arc::new(GenCall::new(Box::new(exn_constructor)))), - loc: None, - })), - Arc::new(RwLock::new(TopLevelDef::Function { - name: "IndexError.__init__".into(), - simple_name: "__init__".into(), - signature: index_error_signature, - var_id: Default::default(), - instance_to_symbol: Default::default(), - instance_to_stmt: Default::default(), - resolver: None, - codegen_callback: Some(Arc::new(GenCall::new(Box::new(exn_constructor)))), - loc: None, - })), - Arc::new(RwLock::new(TopLevelDef::Class { - name: "ZeroDivisionError".into(), - object_id: DefinitionId(12), - type_vars: Default::default(), - fields: exception_fields.clone(), - methods: vec![("__init__".into(), div_by_zero_signature, DefinitionId(8))], - ancestors: vec![ - TypeAnnotation::CustomClass { id: DefinitionId(10), params: Default::default() }, - TypeAnnotation::CustomClass { id: DefinitionId(7), params: Default::default() }, - ], - constructor: Some(div_by_zero_signature), - resolver: None, - loc: None, - })), - Arc::new(RwLock::new(TopLevelDef::Class { - name: "IndexError".into(), - object_id: DefinitionId(13), - type_vars: Default::default(), - fields: exception_fields, - methods: vec![("__init__".into(), index_error_signature, DefinitionId(9))], - ancestors: vec![ - TypeAnnotation::CustomClass { id: DefinitionId(11), params: Default::default() }, - TypeAnnotation::CustomClass { id: DefinitionId(7), params: Default::default() }, - ], - constructor: Some(index_error_signature), - resolver: None, - loc: None, - })), + Arc::new(RwLock::new(div_by_zero_fun)), + Arc::new(RwLock::new(index_err_fun)), + Arc::new(RwLock::new(div_by_zero_class)), + Arc::new(RwLock::new(index_err_class)), Arc::new(RwLock::new(TopLevelDef::Function { name: "int32".into(), simple_name: "int32".into(), diff --git a/nac3core/src/toplevel/composer.rs b/nac3core/src/toplevel/composer.rs index f65357233..f5897a2ed 100644 --- a/nac3core/src/toplevel/composer.rs +++ b/nac3core/src/toplevel/composer.rs @@ -461,6 +461,9 @@ impl TopLevelComposer { }; 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) { errors.insert(e); } @@ -557,6 +560,9 @@ impl TopLevelComposer { // first, only push direct parent into the list let mut errors = HashSet::new(); for (class_def, class_ast) in self.definition_ast_list.iter_mut().skip(self.builtin_num) { + if class_ast.is_none() { + continue; + } if let Err(e) = get_direct_parents(class_def, class_ast) { errors.insert(e); } @@ -587,7 +593,10 @@ impl TopLevelComposer { ); Ok(()) }; - for (class_def, _) in self.definition_ast_list.iter().skip(self.builtin_num) { + for (class_def, ast) in self.definition_ast_list.iter().skip(self.builtin_num) { + if ast.is_none() { + continue; + } if let Err(e) = get_all_ancestors(class_def) { errors.insert(e); } @@ -598,6 +607,9 @@ impl TopLevelComposer { // insert the ancestors to the def list for (class_def, class_ast) in self.definition_ast_list.iter_mut().skip(self.builtin_num) { + if class_ast.is_none() { + continue; + } let mut class_def = class_def.write(); let (class_ancestors, class_id, class_type_vars) = { if let TopLevelDef::Class { ancestors, object_id, type_vars, .. } = @@ -661,6 +673,9 @@ impl TopLevelComposer { let mut errors = HashSet::new(); for (class_def, class_ast) in def_ast_list.iter().skip(self.builtin_num) { + if class_ast.is_none() { + continue; + } if matches!(&*class_def.read(), TopLevelDef::Class { .. }) { if let Err(e) = Self::analyze_single_class_methods_fields( class_def.clone(), @@ -687,7 +702,10 @@ impl TopLevelComposer { loop { let mut finished = true; - for (class_def, _) in def_ast_list.iter().skip(self.builtin_num) { + for (class_def, class_ast) in def_ast_list.iter().skip(self.builtin_num) { + if class_ast.is_none() { + continue; + } let mut class_def = class_def.write(); if let TopLevelDef::Class { ancestors, .. } = class_def.deref() { // if the length of the ancestor is equal to the current depth @@ -950,6 +968,9 @@ impl TopLevelComposer { Ok(()) }; for (function_def, function_ast) in def_list.iter().skip(self.builtin_num) { + if function_ast.is_none() { + continue; + } if let Err(e) = analyze(function_def, function_ast) { errors.insert(e); } @@ -1553,6 +1574,9 @@ impl TopLevelComposer { Ok(()) }; for (i, (def, ast)) in definition_ast_list.iter().enumerate().skip(self.builtin_num) { + if ast.is_none() { + continue; + } if let Err(e) = analyze(i, def, ast) { errors.insert(e); } @@ -1849,6 +1873,9 @@ impl TopLevelComposer { Ok(()) }; for (id, (def, ast)) in self.definition_ast_list.iter().enumerate().skip(self.builtin_num) { + if ast.is_none() { + continue; + } if let Err(e) = analyze_2(id, def, ast) { errors.insert(e); }