nac3artiq: support more builtin errors

escape-analysis
pca006132 2022-03-16 23:42:08 +08:00
parent 8fd868a673
commit e126fef012
3 changed files with 189 additions and 147 deletions

View File

@ -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<GenCall>)>,
builtins_ty: HashMap<StrRef, Type>,
builtins_def: HashMap<StrRef, DefinitionId>,
pyid_to_def: Arc<RwLock<HashMap<u64, DefinitionId>>>,
primitive_ids: PrimitivePythonId,
working_directory: TempDir,
@ -260,6 +259,34 @@ impl Nac3 {
}
}
fn add_exceptions(
composer: &mut TopLevelComposer,
builtin_def: &mut HashMap<StrRef, DefinitionId>,
builtin_ty: &mut HashMap<StrRef, Type>,
error_names: &[&str]
) -> Vec<Type> {
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<u64, _> = HashMap::new();
let pyid_to_type = Arc::new(RwLock::new(HashMap::<u64, Type>::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<u64, _> = HashMap::new();
let global_value_ids = Arc::new(RwLock::new(HashSet::<u64>::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(),

View File

@ -9,7 +9,92 @@ use inkwell::{types::BasicType, FloatPredicate, IntPredicate};
type BuiltinInfo = (Vec<(Arc<RwLock<TopLevelDef>>, Option<Stmt>)>, &'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(),

View File

@ -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);
}