diff --git a/rust/kcl-lib/src/execution/exec_ast.rs b/rust/kcl-lib/src/execution/exec_ast.rs index fcbea5f0189..420dfee771f 100644 --- a/rust/kcl-lib/src/execution/exec_ast.rs +++ b/rust/kcl-lib/src/execution/exec_ast.rs @@ -753,7 +753,7 @@ impl ExecutorContext { if let ModulePath::Std { value: std_path } = &exec_state.mod_local.path { let (func, props) = crate::std::std_fn(std_path, statement_kind.expect_name()); KclValue::Function { - value: Box::new(FunctionSource::rust(func, function_expression.clone(), props, attrs)), + value: vec![FunctionSource::rust(func, function_expression.clone(), props, attrs)], meta: vec![metadata.to_owned()], } } else { @@ -767,11 +767,11 @@ impl ExecutorContext { // over variables. Variables defined lexically later shouldn't // be available to the function body. KclValue::Function { - value: Box::new(FunctionSource::kcl( + value: vec![FunctionSource::kcl( function_expression.clone(), exec_state.mut_stack().snapshot(), matches!(&exec_state.mod_local.path, ModulePath::Std { .. }), - )), + )], meta: vec![metadata.to_owned()], } } diff --git a/rust/kcl-lib/src/execution/fn_call.rs b/rust/kcl-lib/src/execution/fn_call.rs index 687579d1a4d..45cc4be2915 100644 --- a/rust/kcl-lib/src/execution/fn_call.rs +++ b/rust/kcl-lib/src/execution/fn_call.rs @@ -174,7 +174,8 @@ impl Node { let args = Args::new(fn_args, unlabeled, callsite, exec_state, ctx.clone()); - let return_value = fn_src + // TODO check functions + let return_value = fn_src[0] .call_kw(Some(fn_name.to_string()), exec_state, ctx, args, callsite) .await .map_err(|e| { diff --git a/rust/kcl-lib/src/execution/kcl_value.rs b/rust/kcl-lib/src/execution/kcl_value.rs index 1c0a9555ad8..373c97dc137 100644 --- a/rust/kcl-lib/src/execution/kcl_value.rs +++ b/rust/kcl-lib/src/execution/kcl_value.rs @@ -87,7 +87,8 @@ pub enum KclValue { Function { #[serde(serialize_with = "function_value_stub")] #[ts(type = "null")] - value: Box, + // usize is the epoch at which the function was added to the value + value: Vec<(usize, FunctionSource)>, #[serde(skip)] meta: Vec, }, @@ -111,7 +112,7 @@ pub enum KclValue { }, } -fn function_value_stub(_value: &FunctionSource, serializer: S) -> Result +fn function_value_stub(_value: &Vec<(usize, FunctionSource)>, serializer: S) -> Result where S: serde::Serializer, { @@ -474,13 +475,16 @@ impl KclValue { pub(crate) fn map_env_ref(&self, old_env: usize, new_env: usize) -> Self { let mut result = self.clone(); - if let KclValue::Function { ref mut value, .. } = result - && let FunctionSource { - body: FunctionBody::Kcl(memory), - .. - } = &mut **value - { - memory.replace_env(old_env, new_env); + if let KclValue::Function { ref mut value, .. } = result { + for value in value { + if let FunctionSource { + body: FunctionBody::Kcl(memory), + .. + } = &mut value.1 + { + memory.replace_env(old_env, new_env); + } + } } result @@ -702,8 +706,8 @@ impl KclValue { } } - /// If this value is of type function, return it. - pub fn as_function(&self) -> Option<&FunctionSource> { + /// If this value is of type function, return the function definitions. + pub fn as_function(&self) -> Option<&[FunctionSource]> { match self { KclValue::Function { value, .. } => Some(value), _ => None, diff --git a/rust/kcl-lib/src/execution/memory.rs b/rust/kcl-lib/src/execution/memory.rs index 5a7913099c2..68652e9ceff 100644 --- a/rust/kcl-lib/src/execution/memory.rs +++ b/rust/kcl-lib/src/execution/memory.rs @@ -628,7 +628,28 @@ impl Stack { /// Add a value to the program memory (in the current scope). The value must not already exist. pub fn add(&mut self, key: String, value: KclValue, source_range: SourceRange) -> Result<(), KclError> { let env = self.memory.get_env(self.current_env.index()); + if env.contains_key(&key) { + if let KclValue::Function { value: new_fn, .. } = value { + if Some(true) + == env.update( + &key, + move |value, epoch| { + match value { + KclValue::Function { value, ..} => { + value.extend(new_fn.into_iter().map(|f| (epoch, f.1))); + true + } + _ => false, + } + }, + self.memory.epoch.load(Ordering::Relaxed), + self.id, + ) + { + return Ok(()); + } + } return Err(KclError::new_value_already_defined(KclErrorDetails::new( format!("Cannot redefine `{key}`"), vec![source_range], @@ -979,13 +1000,19 @@ mod env { .ok_or(self.parent) } - pub(super) fn update(&self, key: &str, f: impl Fn(&mut KclValue, usize), epoch: usize, owner: usize) { + pub(super) fn update( + &self, + key: &str, + f: impl FnOnce(&mut KclValue, usize) -> T, + epoch: usize, + owner: usize, + ) -> Option { let Some((_, value)) = self.get_mut_bindings(owner).get_mut(key) else { debug_assert!(false, "Missing memory entry for {key}"); - return; + return None; }; - f(value, epoch); + Some(f(value, epoch)) } pub(super) fn parent(&self) -> Option { @@ -1291,11 +1318,11 @@ mod test { mem.add( "f".to_owned(), KclValue::Function { - value: Box::new(FunctionSource::kcl( + value: vec![(0, FunctionSource::kcl( crate::parsing::ast::types::FunctionExpression::dummy(), sn2, false, - )), + ))], meta: Vec::new(), }, sr(), @@ -1306,7 +1333,7 @@ mod test { assert_get(mem, "a", 1); assert_get(mem, "b", 2); match mem.get("f", SourceRange::default()).unwrap() { - KclValue::Function { value, .. } => match &**value { + KclValue::Function { value, .. } if value.len() == 1 => match &value[0].1 { FunctionSource { body: crate::execution::kcl_value::FunctionBody::Kcl(memory), .. diff --git a/rust/kcl-lib/src/lsp/kcl/mod.rs b/rust/kcl-lib/src/lsp/kcl/mod.rs index a8543d1677a..a30fe3f4a32 100644 --- a/rust/kcl-lib/src/lsp/kcl/mod.rs +++ b/rust/kcl-lib/src/lsp/kcl/mod.rs @@ -1044,9 +1044,10 @@ impl LanguageServer for Backend { let (sig, docs) = if let Some(Some(result)) = with_cached_var(&name, |value| { match value { // User-defined function - KclValue::Function { value, .. } if !value.is_std => { + KclValue::Function { value, .. } if !value[0].1.is_std => { + let sigs: Vec<_> = value.iter().map(|v| v.1.ast.signature()).collect(); // TODO get docs from comments - Some((value.ast.signature(), "")) + Some((sigs.join("\n---\n"), "")) } _ => None, } diff --git a/rust/kcl-lib/src/std/args.rs b/rust/kcl-lib/src/std/args.rs index 410ca8dced1..df0db8fcdfc 100644 --- a/rust/kcl-lib/src/std/args.rs +++ b/rust/kcl-lib/src/std/args.rs @@ -1167,7 +1167,11 @@ impl<'a> FromKclValue<'a> for Box { impl<'a> FromKclValue<'a> for FunctionSource { fn from_kcl_val(arg: &'a KclValue) -> Option { - arg.as_function().cloned() + let f = arg.as_function()?; + if f.len() != 1 { + return None; + } + Some(f[0].clone()) } }