Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions rust/kcl-lib/src/execution/exec_ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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()],
}
}
Expand Down
3 changes: 2 additions & 1 deletion rust/kcl-lib/src/execution/fn_call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,8 @@ impl Node<CallExpressionKw> {

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| {
Expand Down
26 changes: 15 additions & 11 deletions rust/kcl-lib/src/execution/kcl_value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,8 @@ pub enum KclValue {
Function {
#[serde(serialize_with = "function_value_stub")]
#[ts(type = "null")]
value: Box<FunctionSource>,
// usize is the epoch at which the function was added to the value
value: Vec<(usize, FunctionSource)>,
#[serde(skip)]
meta: Vec<Metadata>,
},
Expand All @@ -111,7 +112,7 @@ pub enum KclValue {
},
}

fn function_value_stub<S>(_value: &FunctionSource, serializer: S) -> Result<S::Ok, S::Error>
fn function_value_stub<S>(_value: &Vec<(usize, FunctionSource)>, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand Down
39 changes: 33 additions & 6 deletions rust/kcl-lib/src/execution/memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -628,7 +628,28 @@
/// 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)

Check warning on line 634 in rust/kcl-lib/src/execution/memory.rs

View workflow job for this annotation

GitHub Actions / cargo fmt

Diff in /home/runner/work/modeling-app/modeling-app/rust/kcl-lib/src/execution/memory.rs
== 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],
Expand Down Expand Up @@ -979,13 +1000,19 @@
.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<T>(
&self,
key: &str,
f: impl FnOnce(&mut KclValue, usize) -> T,
epoch: usize,
owner: usize,
) -> Option<T> {
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<EnvironmentRef> {
Expand Down Expand Up @@ -1288,14 +1315,14 @@
mem.add("b".to_owned(), val(2), sr()).unwrap();

let sn2 = mem.snapshot();
mem.add(

Check warning on line 1318 in rust/kcl-lib/src/execution/memory.rs

View workflow job for this annotation

GitHub Actions / cargo fmt

Diff in /home/runner/work/modeling-app/modeling-app/rust/kcl-lib/src/execution/memory.rs
"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(),
Expand All @@ -1306,7 +1333,7 @@
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),
..
Expand Down
5 changes: 3 additions & 2 deletions rust/kcl-lib/src/lsp/kcl/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}
Expand Down
6 changes: 5 additions & 1 deletion rust/kcl-lib/src/std/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1167,7 +1167,11 @@ impl<'a> FromKclValue<'a> for Box<Solid> {

impl<'a> FromKclValue<'a> for FunctionSource {
fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
arg.as_function().cloned()
let f = arg.as_function()?;
if f.len() != 1 {
return None;
}
Some(f[0].clone())
}
}

Expand Down
Loading