From c7b6b048fb0e4a3b186584a61a35b06b21d10f5d Mon Sep 17 00:00:00 2001 From: ychenfo Date: Thu, 11 Nov 2021 22:43:09 +0800 Subject: [PATCH 1/7] nac3core: default constant parameter support --- nac3core/src/toplevel/composer.rs | 52 ++++++++++++++++++++++++++----- nac3core/src/toplevel/helper.rs | 50 +++++++++++++++++++++++++++++ 2 files changed, 95 insertions(+), 7 deletions(-) diff --git a/nac3core/src/toplevel/composer.rs b/nac3core/src/toplevel/composer.rs index bf9f156..152094d 100644 --- a/nac3core/src/toplevel/composer.rs +++ b/nac3core/src/toplevel/composer.rs @@ -1065,10 +1065,23 @@ impl TopLevelComposer { and names thould not be the same as the keywords" .into()); } - - args.args + + let mut arg_with_defualt: Vec<(&ast::Located>, Option<&ast::Expr>)> = args + .args .iter() - .map(|x| -> Result { + .rev() + .zip(args + .defaults + .iter() + .rev() + .map(|x| -> Option<&ast::Expr> { Some(x) }) + .chain(std::iter::repeat(None)) + ).collect_vec(); + arg_with_defualt.reverse(); + + arg_with_defualt + .iter() + .map(|(x, default)| -> Result { let annotation = x .node .annotation @@ -1120,7 +1133,12 @@ impl TopLevelComposer { Ok(FuncArg { name: x.node.arg, ty, - default_value: Default::default(), + default_value: default.map(|default| { + match Self::parse_parameter_default_value(default) { + Ok(res) => res, + Err(err) => panic!("{}", err), + } + }), }) }) .collect::, _>>()? @@ -1272,7 +1290,20 @@ impl TopLevelComposer { } let mut result = Vec::new(); - for x in &args.args { + + let mut arg_with_defualt: Vec<(&ast::Located>, Option<&ast::Expr>)> = args + .args + .iter() + .rev() + .zip(args + .defaults + .iter() + .rev() + .map(|x| -> Option<&ast::Expr> { Some(x) }) + .chain(std::iter::repeat(None)) + ).collect_vec(); + arg_with_defualt.reverse(); + for (x, default) in arg_with_defualt { let name = x.node.arg; if name != zelf { let type_ann = { @@ -1317,8 +1348,15 @@ impl TopLevelComposer { let dummy_func_arg = FuncArg { name, ty: unifier.get_fresh_var().0, - // TODO: default value? - default_value: None, + default_value: default.map(|default| { + if name == "self".into() { + panic!("`self` parameter cannot take default value at {}", x.location) + } + match Self::parse_parameter_default_value(default) { + Ok(res) => res, + Err(err) => panic!("{}", err), + } + }) }; // push the dummy type and the type annotation // into the list for later unification diff --git a/nac3core/src/toplevel/helper.rs b/nac3core/src/toplevel/helper.rs index 35da97c..836a739 100644 --- a/nac3core/src/toplevel/helper.rs +++ b/nac3core/src/toplevel/helper.rs @@ -1,3 +1,8 @@ +use std::convert::TryInto; + +use nac3parser::ast::{Constant, Location}; +use crate::symbol_resolver::SymbolValue; + use super::*; impl TopLevelDef { @@ -341,4 +346,49 @@ impl TopLevelComposer { } Ok(result) } + + pub fn parse_parameter_default_value(default: &ast::Expr) -> Result { + fn handle_constant(val: &Constant, loc: &Location) -> Result { + match val { + Constant::Int(v) => { + if let Ok(v) = v.try_into() { + Ok(SymbolValue::I32(v)) + } else { + Ok(SymbolValue::I64(v.try_into().unwrap())) + } + } + Constant::Float(v) => Ok(SymbolValue::Double(*v)), + Constant::Bool(v) => Ok(SymbolValue::Bool(*v)), + Constant::Tuple(tuple) => Ok(SymbolValue::Tuple( + tuple.iter().map(|x| handle_constant(x, loc)).collect::, _>>()? + )), + _ => unimplemented!("this constant is not supported now at {}", loc), + } + } + match &default.node { + ast::ExprKind::Constant { value, .. } => handle_constant(value, &default.location), + ast::ExprKind::Call { func, args, .. } if { + match &func.node { + ast::ExprKind::Name { id, .. } => *id == "int64".into(), + _ => false, + } + } => { + if args.len() == 1 { + match &args[0].node { + ast::ExprKind::Constant { value: Constant::Int(v), .. } => + Ok(SymbolValue::I64(v.try_into().unwrap())), + _ => panic!("only allow constant integer here at {}", default.location) + } + } else { + panic!("only allow constant integer here at {}", default.location) + } + } + ast::ExprKind::Tuple { elts, .. } => Ok(SymbolValue::Tuple(elts + .iter() + .map(|x| Self::parse_parameter_default_value(x)) + .collect::, _>>()? + )), + _ => unimplemented!("only constant default is supported now at {}", default.location), + } + } } -- 2.44.1 From 6b059fa2883cf00932ad14322ebc588a7eb5088f Mon Sep 17 00:00:00 2001 From: ychenfo Date: Sat, 13 Nov 2021 16:23:38 +0800 Subject: [PATCH 2/7] nac3core: default parameter fix typo and error handling --- nac3core/src/toplevel/composer.rs | 39 +++++++++++++++---------------- nac3core/src/toplevel/helper.rs | 6 ++--- 2 files changed, 22 insertions(+), 23 deletions(-) diff --git a/nac3core/src/toplevel/composer.rs b/nac3core/src/toplevel/composer.rs index 152094d..1cb1680 100644 --- a/nac3core/src/toplevel/composer.rs +++ b/nac3core/src/toplevel/composer.rs @@ -1066,7 +1066,7 @@ impl TopLevelComposer { .into()); } - let mut arg_with_defualt: Vec<(&ast::Located>, Option<&ast::Expr>)> = args + let arg_with_default: Vec<(&ast::Located>, Option<&ast::Expr>)> = args .args .iter() .rev() @@ -1077,10 +1077,10 @@ impl TopLevelComposer { .map(|x| -> Option<&ast::Expr> { Some(x) }) .chain(std::iter::repeat(None)) ).collect_vec(); - arg_with_defualt.reverse(); - arg_with_defualt + arg_with_default .iter() + .rev() .map(|(x, default)| -> Result { let annotation = x .node @@ -1133,12 +1133,11 @@ impl TopLevelComposer { Ok(FuncArg { name: x.node.arg, ty, - default_value: default.map(|default| { - match Self::parse_parameter_default_value(default) { - Ok(res) => res, - Err(err) => panic!("{}", err), - } - }), + default_value: match default { + None => None, + Some(default) => + Some(Self::parse_parameter_default_value(default)?) + } }) }) .collect::, _>>()? @@ -1291,7 +1290,7 @@ impl TopLevelComposer { let mut result = Vec::new(); - let mut arg_with_defualt: Vec<(&ast::Located>, Option<&ast::Expr>)> = args + let arg_with_default: Vec<(&ast::Located>, Option<&ast::Expr>)> = args .args .iter() .rev() @@ -1302,8 +1301,8 @@ impl TopLevelComposer { .map(|x| -> Option<&ast::Expr> { Some(x) }) .chain(std::iter::repeat(None)) ).collect_vec(); - arg_with_defualt.reverse(); - for (x, default) in arg_with_defualt { + + for (x, default) in arg_with_default.into_iter().rev() { let name = x.node.arg; if name != zelf { let type_ann = { @@ -1348,15 +1347,15 @@ impl TopLevelComposer { let dummy_func_arg = FuncArg { name, ty: unifier.get_fresh_var().0, - default_value: default.map(|default| { - if name == "self".into() { - panic!("`self` parameter cannot take default value at {}", x.location) + default_value: match default { + None => None, + Some(default) => { + if name == "self".into() { + return Err(format!("`self` parameter cannot take default value at {}", x.location)); + } + Some(Self::parse_parameter_default_value(default)?) } - match Self::parse_parameter_default_value(default) { - Ok(res) => res, - Err(err) => panic!("{}", err), - } - }) + } }; // push the dummy type and the type annotation // into the list for later unification diff --git a/nac3core/src/toplevel/helper.rs b/nac3core/src/toplevel/helper.rs index 836a739..e479618 100644 --- a/nac3core/src/toplevel/helper.rs +++ b/nac3core/src/toplevel/helper.rs @@ -362,7 +362,7 @@ impl TopLevelComposer { Constant::Tuple(tuple) => Ok(SymbolValue::Tuple( tuple.iter().map(|x| handle_constant(x, loc)).collect::, _>>()? )), - _ => unimplemented!("this constant is not supported now at {}", loc), + _ => unimplemented!("this constant is not supported at {}", loc), } } match &default.node { @@ -377,10 +377,10 @@ impl TopLevelComposer { match &args[0].node { ast::ExprKind::Constant { value: Constant::Int(v), .. } => Ok(SymbolValue::I64(v.try_into().unwrap())), - _ => panic!("only allow constant integer here at {}", default.location) + _ => Err(format!("only allow constant integer here at {}", default.location)) } } else { - panic!("only allow constant integer here at {}", default.location) + Err(format!("only allow constant integer here at {}", default.location)) } } ast::ExprKind::Tuple { elts, .. } => Ok(SymbolValue::Tuple(elts -- 2.44.1 From e75ec356870bb8feedcac97dc3294ebe25d4de87 Mon Sep 17 00:00:00 2001 From: ychenfo Date: Sat, 20 Nov 2021 04:59:40 +0800 Subject: [PATCH 3/7] nac3ore: default parameter of type int64 should be specified explicitly --- nac3core/src/toplevel/helper.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/nac3core/src/toplevel/helper.rs b/nac3core/src/toplevel/helper.rs index e479618..397a10d 100644 --- a/nac3core/src/toplevel/helper.rs +++ b/nac3core/src/toplevel/helper.rs @@ -354,7 +354,10 @@ impl TopLevelComposer { if let Ok(v) = v.try_into() { Ok(SymbolValue::I32(v)) } else { - Ok(SymbolValue::I64(v.try_into().unwrap())) + Err(format!( + "int64 default parameter should be specified explicitly by `int64()` at {}", + loc + )) } } Constant::Float(v) => Ok(SymbolValue::Double(*v)), -- 2.44.1 From 6397e42e74b947490ee692639a3640d772dae25e Mon Sep 17 00:00:00 2001 From: ychenfo Date: Sun, 21 Nov 2021 21:31:10 +0800 Subject: [PATCH 4/7] default paramter support simple global modules --- nac3artiq/src/symbol_resolver.rs | 81 +++++++++++++- nac3core/src/codegen/test.rs | 4 + nac3core/src/symbol_resolver.rs | 1 + nac3core/src/toplevel/composer.rs | 4 +- nac3core/src/toplevel/helper.rs | 105 ++++++++++-------- nac3core/src/toplevel/mod.rs | 2 +- nac3core/src/toplevel/test.rs | 4 + .../src/typecheck/type_inferencer/test.rs | 4 + nac3standalone/src/basic_symbol_resolver.rs | 23 +++- nac3standalone/src/main.rs | 15 ++- 10 files changed, 188 insertions(+), 55 deletions(-) diff --git a/nac3artiq/src/symbol_resolver.rs b/nac3artiq/src/symbol_resolver.rs index e420bd8..1652509 100644 --- a/nac3artiq/src/symbol_resolver.rs +++ b/nac3artiq/src/symbol_resolver.rs @@ -2,7 +2,7 @@ use inkwell::{types::BasicType, values::BasicValueEnum, AddressSpace}; use nac3core::{ codegen::CodeGenContext, location::Location, - symbol_resolver::SymbolResolver, + symbol_resolver::{SymbolResolver, SymbolValue}, toplevel::{DefinitionId, TopLevelDef}, typecheck::{ type_inferencer::PrimitiveStore, @@ -14,7 +14,7 @@ use pyo3::{ types::{PyList, PyModule, PyTuple}, PyAny, PyObject, PyResult, Python, }; -use nac3parser::ast::StrRef; +use nac3parser::ast::{self, StrRef}; use std::{ cell::RefCell, collections::{HashMap, HashSet}, @@ -399,9 +399,86 @@ impl Resolver { } } } + + fn get_default_param_obj_value(&self, obj: &PyAny, helper: &PythonHelper) -> PyResult> { + let ty_id: u64 = helper + .id_fn + .call1((helper.type_fn.call1((obj,))?,))? + .extract()?; + Ok( + if ty_id == self.primitive_ids.int || ty_id == self.primitive_ids.int32 { + let val: i32 = obj.extract()?; + Ok(SymbolValue::I32(val)) + } else if ty_id == self.primitive_ids.int64 { + let val: i64 = obj.extract()?; + Ok(SymbolValue::I64(val)) + } else if ty_id == self.primitive_ids.bool { + let val: bool = obj.extract()?; + Ok(SymbolValue::Bool(val)) + } else if ty_id == self.primitive_ids.float { + let val: f64 = obj.extract()?; + Ok(SymbolValue::Double(val)) + } else if ty_id == self.primitive_ids.tuple { + let elements: &PyTuple = obj.cast_as()?; + let elements: Result, String>, _> = elements + .iter() + .map(|elem| { + self.get_default_param_obj_value( + elem, + helper + ) + }) + .collect(); + let elements = match elements? { + Ok(el) => el, + Err(err) => return Ok(Err(err)) + }; + Ok(SymbolValue::Tuple(elements)) + } else { + Err("only primitives values and tuple can be default parameter value".into()) + } + ) + } } impl SymbolResolver for Resolver { + fn get_default_param_value( + &self, + expr: &ast::Expr + ) -> Option { + match &expr.node { + ast::ExprKind::Name { id, .. } => { + Python::with_gil( + |py| -> PyResult> { + let obj: &PyAny = self.module.extract(py)?; + let members: &PyList = PyModule::import(py, "inspect")? + .getattr("getmembers")? + .call1((obj,))? + .cast_as()?; + let mut sym_value = None; + for member in members.iter() { + let key: &str = member.get_item(0)?.extract()?; + let val = member.get_item(1)?; + if key == id.to_string() { + let builtins = PyModule::import(py, "builtins")?; + let helper = PythonHelper { + id_fn: builtins.getattr("id").unwrap(), + len_fn: builtins.getattr("len").unwrap(), + type_fn: builtins.getattr("type").unwrap(), + }; + sym_value = Some(self.get_default_param_obj_value(val, &helper).unwrap().unwrap()); + break; + } + } + Ok(sym_value) + } + ) + .unwrap() + } + _ => unimplemented!("other type of expr not supported at {}", expr.location) + } + } + fn get_symbol_type( &self, unifier: &mut Unifier, diff --git a/nac3core/src/codegen/test.rs b/nac3core/src/codegen/test.rs index ce958ff..f9e2810 100644 --- a/nac3core/src/codegen/test.rs +++ b/nac3core/src/codegen/test.rs @@ -37,6 +37,10 @@ impl Resolver { } impl SymbolResolver for Resolver { + fn get_default_param_value(&self, _: &nac3parser::ast::Expr) -> Option { + unimplemented!() + } + fn get_symbol_type( &self, _: &mut Unifier, diff --git a/nac3core/src/symbol_resolver.rs b/nac3core/src/symbol_resolver.rs index 161d78a..e8d594d 100644 --- a/nac3core/src/symbol_resolver.rs +++ b/nac3core/src/symbol_resolver.rs @@ -44,6 +44,7 @@ pub trait SymbolResolver { ctx: &mut CodeGenContext<'ctx, 'a>, ) -> Option>; fn get_symbol_location(&self, str: StrRef) -> Option; + fn get_default_param_value(&self, expr: &nac3parser::ast::Expr) -> Option; // handle function call etc. } diff --git a/nac3core/src/toplevel/composer.rs b/nac3core/src/toplevel/composer.rs index 1cb1680..232e0c4 100644 --- a/nac3core/src/toplevel/composer.rs +++ b/nac3core/src/toplevel/composer.rs @@ -1136,7 +1136,7 @@ impl TopLevelComposer { default_value: match default { None => None, Some(default) => - Some(Self::parse_parameter_default_value(default)?) + Some(Self::parse_parameter_default_value(default, resolver)?) } }) }) @@ -1353,7 +1353,7 @@ impl TopLevelComposer { if name == "self".into() { return Err(format!("`self` parameter cannot take default value at {}", x.location)); } - Some(Self::parse_parameter_default_value(default)?) + Some(Self::parse_parameter_default_value(default, class_resolver)?) } } }; diff --git a/nac3core/src/toplevel/helper.rs b/nac3core/src/toplevel/helper.rs index 397a10d..6d46d9d 100644 --- a/nac3core/src/toplevel/helper.rs +++ b/nac3core/src/toplevel/helper.rs @@ -347,51 +347,64 @@ impl TopLevelComposer { Ok(result) } - pub fn parse_parameter_default_value(default: &ast::Expr) -> Result { - fn handle_constant(val: &Constant, loc: &Location) -> Result { - match val { - Constant::Int(v) => { - if let Ok(v) = v.try_into() { - Ok(SymbolValue::I32(v)) - } else { - Err(format!( - "int64 default parameter should be specified explicitly by `int64()` at {}", - loc - )) - } - } - Constant::Float(v) => Ok(SymbolValue::Double(*v)), - Constant::Bool(v) => Ok(SymbolValue::Bool(*v)), - Constant::Tuple(tuple) => Ok(SymbolValue::Tuple( - tuple.iter().map(|x| handle_constant(x, loc)).collect::, _>>()? - )), - _ => unimplemented!("this constant is not supported at {}", loc), - } - } - match &default.node { - ast::ExprKind::Constant { value, .. } => handle_constant(value, &default.location), - ast::ExprKind::Call { func, args, .. } if { - match &func.node { - ast::ExprKind::Name { id, .. } => *id == "int64".into(), - _ => false, - } - } => { - if args.len() == 1 { - match &args[0].node { - ast::ExprKind::Constant { value: Constant::Int(v), .. } => - Ok(SymbolValue::I64(v.try_into().unwrap())), - _ => Err(format!("only allow constant integer here at {}", default.location)) - } - } else { - Err(format!("only allow constant integer here at {}", default.location)) - } - } - ast::ExprKind::Tuple { elts, .. } => Ok(SymbolValue::Tuple(elts - .iter() - .map(|x| Self::parse_parameter_default_value(x)) - .collect::, _>>()? - )), - _ => unimplemented!("only constant default is supported now at {}", default.location), - } + pub fn parse_parameter_default_value(default: &ast::Expr, resolver: &(dyn SymbolResolver + Send + Sync)) -> Result { + parse_parameter_default_value(default, resolver) + } +} + +pub fn parse_parameter_default_value(default: &ast::Expr, resolver: &(dyn SymbolResolver + Send + Sync)) -> Result { + fn handle_constant(val: &Constant, loc: &Location) -> Result { + match val { + Constant::Int(v) => { + if let Ok(v) = v.try_into() { + Ok(SymbolValue::I32(v)) + } else { + Err(format!( + "int64 default parameter should be specified explicitly by `int64()` at {}", + loc + )) + } + } + Constant::Float(v) => Ok(SymbolValue::Double(*v)), + Constant::Bool(v) => Ok(SymbolValue::Bool(*v)), + Constant::Tuple(tuple) => Ok(SymbolValue::Tuple( + tuple.iter().map(|x| handle_constant(x, loc)).collect::, _>>()? + )), + _ => unimplemented!("this constant is not supported at {}", loc), + } + } + match &default.node { + ast::ExprKind::Constant { value, .. } => handle_constant(value, &default.location), + ast::ExprKind::Call { func, args, .. } if { + match &func.node { + ast::ExprKind::Name { id, .. } => *id == "int64".into(), + _ => false, + } + } => { + if args.len() == 1 { + match &args[0].node { + ast::ExprKind::Constant { value: Constant::Int(v), .. } => + Ok(SymbolValue::I64(v.try_into().unwrap())), + _ => Err(format!("only allow constant integer here at {}", default.location)) + } + } else { + Err(format!("only allow constant integer here at {}", default.location)) + } + } + ast::ExprKind::Tuple { elts, .. } => Ok(SymbolValue::Tuple(elts + .iter() + .map(|x| parse_parameter_default_value(x, resolver)) + .collect::, _>>()? + )), + ast::ExprKind::Name { id, .. } => { + resolver.get_default_param_value(default).ok_or_else( + || format!( + "this module global `{}` cannot be used as a default parameter at {} (should be primitive type or tuple)", + id, + default.location + ) + ) + } + _ => unimplemented!("only constant default is supported now at {}", default.location), } } diff --git a/nac3core/src/toplevel/mod.rs b/nac3core/src/toplevel/mod.rs index c96a7ca..f6fc15b 100644 --- a/nac3core/src/toplevel/mod.rs +++ b/nac3core/src/toplevel/mod.rs @@ -23,7 +23,7 @@ use inkwell::values::BasicValueEnum; pub struct DefinitionId(pub usize); pub mod composer; -mod helper; +pub mod helper; mod type_annotation; use composer::*; use type_annotation::*; diff --git a/nac3core/src/toplevel/test.rs b/nac3core/src/toplevel/test.rs index e279547..0f4fd83 100644 --- a/nac3core/src/toplevel/test.rs +++ b/nac3core/src/toplevel/test.rs @@ -35,6 +35,10 @@ impl ResolverInternal { struct Resolver(Arc); impl SymbolResolver for Resolver { + fn get_default_param_value(&self, _: &nac3parser::ast::Expr) -> Option { + unimplemented!() + } + fn get_symbol_type( &self, _: &mut Unifier, diff --git a/nac3core/src/typecheck/type_inferencer/test.rs b/nac3core/src/typecheck/type_inferencer/test.rs index d3aa09f..da51aa9 100644 --- a/nac3core/src/typecheck/type_inferencer/test.rs +++ b/nac3core/src/typecheck/type_inferencer/test.rs @@ -19,6 +19,10 @@ struct Resolver { } impl SymbolResolver for Resolver { + fn get_default_param_value(&self, _: &nac3parser::ast::Expr) -> Option { + unimplemented!() + } + fn get_symbol_type( &self, _: &mut Unifier, diff --git a/nac3standalone/src/basic_symbol_resolver.rs b/nac3standalone/src/basic_symbol_resolver.rs index 82c1ac3..31b3713 100644 --- a/nac3standalone/src/basic_symbol_resolver.rs +++ b/nac3standalone/src/basic_symbol_resolver.rs @@ -2,21 +2,22 @@ use inkwell::values::BasicValueEnum; use nac3core::{ codegen::CodeGenContext, location::Location, - symbol_resolver::SymbolResolver, - toplevel::{DefinitionId, TopLevelDef}, + symbol_resolver::{SymbolResolver, SymbolValue}, + toplevel::{DefinitionId, TopLevelDef, helper::parse_parameter_default_value}, typecheck::{ type_inferencer::PrimitiveStore, typedef::{Type, Unifier}, }, }; use parking_lot::{Mutex, RwLock}; -use nac3parser::ast::StrRef; +use nac3parser::ast::{self, StrRef}; use std::{collections::HashMap, sync::Arc}; pub struct ResolverInternal { pub id_to_type: Mutex>, pub id_to_def: Mutex>, pub class_names: Mutex>, + pub module_globals: Mutex>, } impl ResolverInternal { @@ -27,11 +28,27 @@ impl ResolverInternal { pub fn add_id_type(&self, id: StrRef, ty: Type) { self.id_to_type.lock().insert(id, ty); } + + pub fn add_module_global(&self, id: StrRef, expr: &ast::Expr) { + self.module_globals.lock().insert(id, expr.clone()); + } } pub struct Resolver(pub Arc); impl SymbolResolver for Resolver { + fn get_default_param_value(&self, expr: &ast::Expr) -> Option { + match &expr.node { + ast::ExprKind::Name { id, .. } => { + let expr = self.0.module_globals.lock().get(id).cloned(); + expr.map(|x| { + parse_parameter_default_value(&x, self).unwrap() + }) + } + _ => unimplemented!("other type of expr not supported at {}", expr.location) + } + } + fn get_symbol_type( &self, _: &mut Unifier, diff --git a/nac3standalone/src/main.rs b/nac3standalone/src/main.rs index 5b4e31d..33fc0e6 100644 --- a/nac3standalone/src/main.rs +++ b/nac3standalone/src/main.rs @@ -4,7 +4,7 @@ use inkwell::{ OptimizationLevel, }; use nac3core::typecheck::type_inferencer::PrimitiveStore; -use nac3parser::parser; +use nac3parser::{ast::{ExprKind, StmtKind}, parser}; use std::env; use std::fs; use std::{collections::HashMap, path::Path, sync::Arc, time::SystemTime}; @@ -48,6 +48,7 @@ fn main() { id_to_type: builtins_ty.into(), id_to_def: builtins_def.into(), class_names: Default::default(), + module_globals: Default::default(), } .into(); let resolver = @@ -66,6 +67,18 @@ fn main() { ); for stmt in parser_result.into_iter() { + // handle module globals + if let StmtKind::Assign { targets, value, .. } = &stmt.node { + if targets.len() == 1 { + if let ExprKind::Name { id, .. } = &targets[0].node { + internal_resolver.add_module_global(*id, value); + } + } else { + unimplemented!("only single assign supported now") + } + continue; + } + let (name, def_id, ty) = composer .register_top_level(stmt, Some(resolver.clone()), "__main__".into()) .unwrap(); -- 2.44.1 From ee7c1eb11d048ee2c9560e24ec3d69a6c2354b04 Mon Sep 17 00:00:00 2001 From: ychenfo Date: Sun, 21 Nov 2021 22:05:12 +0800 Subject: [PATCH 5/7] nac3core: change default parameter integer out of range err msg --- nac3core/src/toplevel/helper.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nac3core/src/toplevel/helper.rs b/nac3core/src/toplevel/helper.rs index 6d46d9d..d7ce477 100644 --- a/nac3core/src/toplevel/helper.rs +++ b/nac3core/src/toplevel/helper.rs @@ -360,7 +360,7 @@ pub fn parse_parameter_default_value(default: &ast::Expr, resolver: &(dyn Symbol Ok(SymbolValue::I32(v)) } else { Err(format!( - "int64 default parameter should be specified explicitly by `int64()` at {}", + "integer value out of range at {}", loc )) } -- 2.44.1 From 99c103b35b46ab683caea676f6a6f11362f674f9 Mon Sep 17 00:00:00 2001 From: ychenfo Date: Tue, 23 Nov 2021 00:25:37 +0800 Subject: [PATCH 6/7] nac3standalone: better support for global assignment --- nac3core/src/toplevel/helper.rs | 2 +- nac3standalone/src/basic_symbol_resolver.rs | 13 ++--- nac3standalone/src/main.rs | 61 ++++++++++++++++++--- 3 files changed, 58 insertions(+), 18 deletions(-) diff --git a/nac3core/src/toplevel/helper.rs b/nac3core/src/toplevel/helper.rs index d7ce477..2dcb359 100644 --- a/nac3core/src/toplevel/helper.rs +++ b/nac3core/src/toplevel/helper.rs @@ -399,7 +399,7 @@ pub fn parse_parameter_default_value(default: &ast::Expr, resolver: &(dyn Symbol ast::ExprKind::Name { id, .. } => { resolver.get_default_param_value(default).ok_or_else( || format!( - "this module global `{}` cannot be used as a default parameter at {} (should be primitive type or tuple)", + "`{}` cannot be used as a default parameter at {} (not primitive type or tuple / not defined?)", id, default.location ) diff --git a/nac3standalone/src/basic_symbol_resolver.rs b/nac3standalone/src/basic_symbol_resolver.rs index 31b3713..9983d50 100644 --- a/nac3standalone/src/basic_symbol_resolver.rs +++ b/nac3standalone/src/basic_symbol_resolver.rs @@ -3,7 +3,7 @@ use nac3core::{ codegen::CodeGenContext, location::Location, symbol_resolver::{SymbolResolver, SymbolValue}, - toplevel::{DefinitionId, TopLevelDef, helper::parse_parameter_default_value}, + toplevel::{DefinitionId, TopLevelDef}, typecheck::{ type_inferencer::PrimitiveStore, typedef::{Type, Unifier}, @@ -17,7 +17,7 @@ pub struct ResolverInternal { pub id_to_type: Mutex>, pub id_to_def: Mutex>, pub class_names: Mutex>, - pub module_globals: Mutex>, + pub module_globals: Mutex>, } impl ResolverInternal { @@ -29,8 +29,8 @@ impl ResolverInternal { self.id_to_type.lock().insert(id, ty); } - pub fn add_module_global(&self, id: StrRef, expr: &ast::Expr) { - self.module_globals.lock().insert(id, expr.clone()); + pub fn add_module_global(&self, id: StrRef, val: SymbolValue) { + self.module_globals.lock().insert(id, val); } } @@ -40,10 +40,7 @@ impl SymbolResolver for Resolver { fn get_default_param_value(&self, expr: &ast::Expr) -> Option { match &expr.node { ast::ExprKind::Name { id, .. } => { - let expr = self.0.module_globals.lock().get(id).cloned(); - expr.map(|x| { - parse_parameter_default_value(&x, self).unwrap() - }) + self.0.module_globals.lock().get(id).cloned() } _ => unimplemented!("other type of expr not supported at {}", expr.location) } diff --git a/nac3standalone/src/main.rs b/nac3standalone/src/main.rs index 33fc0e6..71e2933 100644 --- a/nac3standalone/src/main.rs +++ b/nac3standalone/src/main.rs @@ -4,8 +4,8 @@ use inkwell::{ OptimizationLevel, }; use nac3core::typecheck::type_inferencer::PrimitiveStore; -use nac3parser::{ast::{ExprKind, StmtKind}, parser}; -use std::env; +use nac3parser::{ast::{Expr, ExprKind, StmtKind}, parser}; +use std::{borrow::Borrow, env}; use std::fs; use std::{collections::HashMap, path::Path, sync::Arc, time::SystemTime}; @@ -15,7 +15,7 @@ use nac3core::{ WorkerRegistry, }, symbol_resolver::SymbolResolver, - toplevel::{composer::TopLevelComposer, TopLevelDef}, + toplevel::{composer::TopLevelComposer, TopLevelDef, helper::parse_parameter_default_value}, typecheck::typedef::FunSignature, }; @@ -67,14 +67,57 @@ fn main() { ); for stmt in parser_result.into_iter() { - // handle module globals if let StmtKind::Assign { targets, value, .. } = &stmt.node { - if targets.len() == 1 { - if let ExprKind::Name { id, .. } = &targets[0].node { - internal_resolver.add_module_global(*id, value); + fn handle_assignment_pattern( + targets: &[Expr], + value: &Expr, + resolver: &(dyn SymbolResolver + Send + Sync), + internal_resolver: &ResolverInternal, + ) -> Result<(), String> { + if targets.len() == 1 { + match &targets[0].node { + ExprKind::Name { id, .. } => { + let val = parse_parameter_default_value(value.borrow(), resolver)?; + internal_resolver.add_module_global(*id, val); + Ok(()) + } + ExprKind::List { elts, .. } + | ExprKind::Tuple { elts, .. } => { + handle_assignment_pattern(elts, value, resolver, internal_resolver)?; + Ok(()) + } + _ => unreachable!("cannot be assigned") + } + } else { + match &value.node { + ExprKind::List { elts, .. } + | ExprKind::Tuple { elts, .. } => { + if elts.len() != targets.len() { + Err(format!( + "number of elements to unpack does not match (expect {}, found {}) at {}", + targets.len(), + elts.len(), + value.location + )) + } else { + for (tar, val) in targets.iter().zip(elts) { + handle_assignment_pattern( + std::slice::from_ref(tar), + val, + resolver, + internal_resolver + )?; + } + Ok(()) + } + }, + _ => Err(format!("unpack of this expression is not supported at {}", value.location)) + } } - } else { - unimplemented!("only single assign supported now") + } + if let Err(err) = handle_assignment_pattern(targets, value, resolver.as_ref(), internal_resolver.as_ref()) { + eprintln!("{}", err); + return; } continue; } -- 2.44.1 From 03cdca606de86419825dd8499793788f6a1bd7c3 Mon Sep 17 00:00:00 2001 From: ychenfo Date: Tue, 23 Nov 2021 01:02:42 +0800 Subject: [PATCH 7/7] nac3core: check type for default parameter --- nac3core/src/toplevel/composer.rs | 19 +++++++++-- nac3core/src/toplevel/helper.rs | 56 +++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+), 3 deletions(-) diff --git a/nac3core/src/toplevel/composer.rs b/nac3core/src/toplevel/composer.rs index 232e0c4..677542b 100644 --- a/nac3core/src/toplevel/composer.rs +++ b/nac3core/src/toplevel/composer.rs @@ -1135,8 +1135,16 @@ impl TopLevelComposer { ty, default_value: match default { None => None, - Some(default) => - Some(Self::parse_parameter_default_value(default, resolver)?) + Some(default) => Some({ + let v = Self::parse_parameter_default_value(default, resolver)?; + Self::check_default_param_type( + &v, + &type_annotation, + primitives_store, + unifier + ).map_err(|err| format!("{} at {}", err, x.location))?; + v + }) } }) }) @@ -1353,7 +1361,12 @@ impl TopLevelComposer { if name == "self".into() { return Err(format!("`self` parameter cannot take default value at {}", x.location)); } - Some(Self::parse_parameter_default_value(default, class_resolver)?) + Some({ + let v = Self::parse_parameter_default_value(default, class_resolver)?; + Self::check_default_param_type(&v, &type_ann, primitives, unifier) + .map_err(|err| format!("{} at {}", err, x.location))?; + v + }) } } }; diff --git a/nac3core/src/toplevel/helper.rs b/nac3core/src/toplevel/helper.rs index 2dcb359..5c8b85e 100644 --- a/nac3core/src/toplevel/helper.rs +++ b/nac3core/src/toplevel/helper.rs @@ -350,6 +350,62 @@ impl TopLevelComposer { pub fn parse_parameter_default_value(default: &ast::Expr, resolver: &(dyn SymbolResolver + Send + Sync)) -> Result { parse_parameter_default_value(default, resolver) } + + pub fn check_default_param_type(val: &SymbolValue, ty: &TypeAnnotation, primitive: &PrimitiveStore, unifier: &mut Unifier) -> Result<(), String> { + let res = match val { + SymbolValue::Bool(..) => { + if matches!(ty, TypeAnnotation::Primitive(t) if *t == primitive.bool) { + None + } else { + Some("bool".to_string()) + } + } + SymbolValue::Double(..) => { + if matches!(ty, TypeAnnotation::Primitive(t) if *t == primitive.float) { + None + } else { + Some("float".to_string()) + } + } + SymbolValue::I32(..) => { + if matches!(ty, TypeAnnotation::Primitive(t) if *t == primitive.int32) { + None + } else { + Some("int32".to_string()) + } + } + SymbolValue::I64(..) => { + if matches!(ty, TypeAnnotation::Primitive(t) if *t == primitive.int64) { + None + } else { + Some("int64".to_string()) + } + } + SymbolValue::Tuple(elts) => { + if let TypeAnnotation::Tuple(elts_ty) = ty { + for (e, t) in elts.iter().zip(elts_ty.iter()) { + Self::check_default_param_type(e, t, primitive, unifier)? + } + if elts.len() != elts_ty.len() { + Some(format!("tuple of length {}", elts.len())) + } else { + None + } + } else { + Some("tuple".to_string()) + } + } + }; + if let Some(found) = res { + Err(format!( + "incompatible default parameter type, expect {}, found {}", + ty.stringify(unifier), + found + )) + } else { + Ok(()) + } + } } pub fn parse_parameter_default_value(default: &ast::Expr, resolver: &(dyn SymbolResolver + Send + Sync)) -> Result { -- 2.44.1