diff --git a/nac3core/src/toplevel/helper.rs b/nac3core/src/toplevel/helper.rs index d7ce477f..2dcb3590 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 31b3713b..9983d507 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 33fc0e6f..71e29335 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; }