From 68b97347b12374aecf0527ed8fc971bb2d25dca1 Mon Sep 17 00:00:00 2001 From: David Mak Date: Tue, 28 Nov 2023 17:37:49 +0800 Subject: [PATCH] core: Infer builtins name list using builtin declaration list --- nac3core/src/toplevel/builtins.rs | 68 +-------------------- nac3core/src/toplevel/composer.rs | 24 ++++++-- nac3core/src/toplevel/type_annotation.rs | 2 +- nac3standalone/demo/src/type_annotations.py | 26 ++++++++ nac3standalone/src/main.rs | 24 ++++---- 5 files changed, 62 insertions(+), 82 deletions(-) create mode 100644 nac3standalone/demo/src/type_annotations.py diff --git a/nac3core/src/toplevel/builtins.rs b/nac3core/src/toplevel/builtins.rs index 0b28bea2..24bdc05b 100644 --- a/nac3core/src/toplevel/builtins.rs +++ b/nac3core/src/toplevel/builtins.rs @@ -22,7 +22,7 @@ use inkwell::{ IntPredicate }; -type BuiltinInfo = (Vec<(Arc>, Option)>, &'static [&'static str]); +type BuiltinInfo = Vec<(Arc>, Option)>; pub fn get_exn_constructor( name: &str, @@ -1906,68 +1906,6 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo { let ast_list: Vec>> = (0..top_level_def_list.len()).map(|_| None).collect(); - ( - izip!(top_level_def_list, ast_list).collect_vec(), - &[ - "int32", - "int64", - "uint32", - "uint64", - "float", - "round", - "round64", - "np_round", - "range", - "str", - "bool", - "floor", - "floor64", - "np_floor", - "ceil", - "ceil64", - "np_ceil", - "len", - "min", - "max", - "abs", - "np_isnan", - "np_isinf", - "np_sin", - "np_cos", - "np_exp", - "np_exp2", - "np_log", - "np_log10", - "np_log2", - "np_fabs", - "np_sqrt", - "np_rint", - "np_tan", - "np_arcsin", - "np_arccos", - "np_arctan", - "np_sinh", - "np_cosh", - "np_tanh", - "np_arcsinh", - "np_arccosh", - "np_arctanh", - "np_expm1", - "np_cbrt", - "sp_spec_erf", - "sp_spec_erfc", - "sp_spec_gamma", - "sp_spec_gammaln", - "sp_spec_j0", - "sp_spec_j1", - "np_arctan2", - "np_copysign", - "np_fmax", - "np_fmin", - "np_ldexp", - "np_hypot", - "np_nextafter", - "Some", - ], - ) + + izip!(top_level_def_list, ast_list).collect_vec() } diff --git a/nac3core/src/toplevel/composer.rs b/nac3core/src/toplevel/composer.rs index 16f508a7..45ace1e0 100644 --- a/nac3core/src/toplevel/composer.rs +++ b/nac3core/src/toplevel/composer.rs @@ -53,7 +53,7 @@ impl TopLevelComposer { 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); + let mut definition_ast_list = builtins::get_builtins(&mut primitives); let primitives_ty = primitives.0; let mut unifier = primitives.1; let mut keyword_list: HashSet = HashSet::from_iter(vec![ @@ -83,12 +83,26 @@ impl TopLevelComposer { let mut builtin_id: HashMap = Default::default(); let mut builtin_ty: HashMap = Default::default(); - for (id, name) in builtin_name_list.iter().rev().enumerate() { + let builtin_name_list = definition_ast_list.iter() + .map(|def_ast| match *def_ast.0.read() { + TopLevelDef::Class { name, .. } => name.to_string(), + TopLevelDef::Function { simple_name, .. } => simple_name.to_string(), + }) + .collect_vec(); + + for (id, name) in builtin_name_list.iter().enumerate() { let name = (**name).into(); - let id = definition_ast_list.len() - id - 1; let def = definition_ast_list[id].0.read(); - if let TopLevelDef::Function { simple_name, signature, .. } = &*def { - assert!(name == *simple_name); + if let TopLevelDef::Function { name: func_name, simple_name, signature, .. } = &*def { + assert_eq!(name, *simple_name, "Simple name of builtin function should match builtin name list"); + + // Do not add member functions into the list of builtin IDs; + // Here we assume that all builtin top-level functions have the same name and simple + // name, and all member functions have something prefixed to its name + if *func_name != simple_name.to_string() { + continue + } + builtin_ty.insert(name, *signature); builtin_id.insert(name, DefinitionId(id)); } else if let TopLevelDef::Class { name, constructor, object_id, .. } = &*def diff --git a/nac3core/src/toplevel/type_annotation.rs b/nac3core/src/toplevel/type_annotation.rs index 116a6b4c..92550904 100644 --- a/nac3core/src/toplevel/type_annotation.rs +++ b/nac3core/src/toplevel/type_annotation.rs @@ -127,7 +127,7 @@ pub fn parse_ast_to_type_annotation_kinds( slice: &ast::Expr, unifier: &mut Unifier, mut locked: HashMap>| { - if vec!["virtual".into(), "Generic".into(), "list".into(), "tuple".into()].contains(id) + if vec!["virtual".into(), "Generic".into(), "list".into(), "tuple".into(), "Option".into()].contains(id) { return Err(format!("keywords cannot be class name (at {})", expr.location)); } diff --git a/nac3standalone/demo/src/type_annotations.py b/nac3standalone/demo/src/type_annotations.py new file mode 100644 index 00000000..2ff14a30 --- /dev/null +++ b/nac3standalone/demo/src/type_annotations.py @@ -0,0 +1,26 @@ +def run() -> int32: + # Numeric Primitives + b: bool = False + i32: int32 = 0 + i64: int64 = int64(0) + u32: uint32 = uint32(0) + u64: uint64 = uint64(0) + f64: float = 0.0 + + # String + s: str = "" + + # List + l_i32: list[int32] = [] + l_f64: list[float] = [] + l_str: list[str] = [] + + # Option + o_some: Option[int32] = Some(0) + o_none: Option[int32] = none + + # Tuple + t_i32_i32: tuple[int32, int32] = (0, 0) + t_i32_f64: tuple[int32, float] = (0, 0.0) + + return 0 \ No newline at end of file diff --git a/nac3standalone/src/main.rs b/nac3standalone/src/main.rs index f2387fef..a6dc749d 100644 --- a/nac3standalone/src/main.rs +++ b/nac3standalone/src/main.rs @@ -74,8 +74,15 @@ fn handle_typevar_definition( unifier: &mut Unifier, primitives: &PrimitiveStore, ) -> Result { - if let ExprKind::Call { func, args, .. } = &var.node { - if matches!(&func.node, ExprKind::Name { id, .. } if id == &"TypeVar".into()) { + let ExprKind::Call { func, args, .. } = &var.node else { + return Err(format!( + "expression {:?} cannot be handled as a generic parameter in global scope", + var + )) + }; + + match &func.node { + ExprKind::Name { id, .. } if id == &"TypeVar".into() => { let constraints = args .iter() .skip(1) @@ -94,15 +101,10 @@ fn handle_typevar_definition( }) .collect::, _>>()?; Ok(unifier.get_fresh_var_with_range(&constraints, None, None).0) - } else { - Err(format!( - "expression {:?} cannot be handled as a TypeVar in global scope", - var - )) } - } else { - Err(format!( - "expression {:?} cannot be handled as a TypeVar in global scope", + + _ => Err(format!( + "expression {:?} cannot be handled as a generic parameter in global scope", var )) } @@ -135,7 +137,7 @@ fn handle_assignment_pattern( internal_resolver.add_module_global(*id, val); Ok(()) } else { - Err(format!("fails to evaluate this expression `{:?}` as a constant or TypeVar at {}", + Err(format!("fails to evaluate this expression `{:?}` as a constant or generic parameter at {}", targets[0].node, targets[0].location, ))