Skip to content

Commit 7f62a8b

Browse files
committed
Accept idents as KW args, fixup pipe as input for KW calls
Signed-off-by: Nick Cameron <[email protected]>
1 parent f407762 commit 7f62a8b

File tree

7 files changed

+54
-44
lines changed

7 files changed

+54
-44
lines changed

rust/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ insta = { opt-level = 3 }
2626
[profile.test]
2727
debug = "line-tables-only"
2828

29+
[workspace.features]
30+
artifact-graph = []
31+
2932
[workspace.dependencies]
3033
async-trait = "0.1.88"
3134
anyhow = { version = "1" }

rust/kcl-lib/e2e/executor/main.rs

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2038,17 +2038,6 @@ async fn kcl_test_ensure_nothing_left_in_batch_multi_file() {
20382038

20392039
ctx.close().await;
20402040
}
2041-
#[tokio::test(flavor = "multi_thread")]
2042-
async fn kcl_test_default_param_for_unlabeled() {
2043-
let code = r#"fn myExtrude(@sk, len) {
2044-
return extrude(sk, length = len)
2045-
}
2046-
2047-
sketch001 = startSketchOn(XY)
2048-
|> circle(center = [0, 0], radius = 93.75)
2049-
|> myExtrude(len = 40)"#;
2050-
let _ = execute_and_snapshot(code, None).await.unwrap();
2051-
}
20522041

20532042
#[tokio::test(flavor = "multi_thread")]
20542043
async fn kcl_test_better_type_names() {

rust/kcl-lib/src/execution/exec_ast.rs

Lines changed: 12 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ use crate::{
2525
},
2626
source_range::SourceRange,
2727
std::{
28-
args::{Arg, KwArgs, TyF64},
28+
args::{Arg, Args, KwArgs, TyF64},
2929
FunctionKind,
3030
},
3131
CompilationError,
@@ -1921,7 +1921,7 @@ fn assign_args_to_params(
19211921
fn type_check_params_kw(
19221922
fn_name: Option<&str>,
19231923
function_expression: NodeRef<'_, FunctionExpression>,
1924-
args: &mut crate::std::args::KwArgs,
1924+
args: &mut KwArgs,
19251925
exec_state: &mut ExecState,
19261926
) -> Result<(), KclError> {
19271927
for (label, arg) in &mut args.labeled {
@@ -2009,18 +2009,18 @@ fn type_check_params_kw(
20092009
fn assign_args_to_params_kw(
20102010
fn_name: Option<&str>,
20112011
function_expression: NodeRef<'_, FunctionExpression>,
2012-
mut args: crate::std::args::KwArgs,
2012+
mut args: Args,
20132013
exec_state: &mut ExecState,
20142014
) -> Result<(), KclError> {
2015-
type_check_params_kw(fn_name, function_expression, &mut args, exec_state)?;
2015+
type_check_params_kw(fn_name, function_expression, &mut args.kw_args, exec_state)?;
20162016

20172017
// Add the arguments to the memory. A new call frame should have already
20182018
// been created.
20192019
let source_ranges = vec![function_expression.into()];
20202020

20212021
for param in function_expression.params.iter() {
20222022
if param.labeled {
2023-
let arg = args.labeled.get(&param.identifier.name);
2023+
let arg = args.kw_args.labeled.get(&param.identifier.name);
20242024
let arg_val = match arg {
20252025
Some(arg) => arg.value.clone(),
20262026
None => match param.default_value {
@@ -2040,17 +2040,11 @@ fn assign_args_to_params_kw(
20402040
.mut_stack()
20412041
.add(param.identifier.name.clone(), arg_val, (&param.identifier).into())?;
20422042
} else {
2043-
// TODO: Get the actual source range.
2044-
// Part of https://github.com/KittyCAD/modeling-app/issues/6613
2045-
let pipe_value_source_range = Default::default();
2046-
let default_unlabeled = exec_state
2047-
.mod_local
2048-
.pipe_value
2049-
.clone()
2050-
.map(|val| Arg::new(val, pipe_value_source_range));
2051-
let Some(unlabeled) = args.unlabeled.take().or(default_unlabeled) else {
2043+
let unlabelled = args.kw_args.unlabeled.take().or_else(|| args.pipe_value.take());
2044+
2045+
let Some(unlabeled) = unlabelled else {
20522046
let param_name = &param.identifier.name;
2053-
return Err(if args.labeled.contains_key(param_name) {
2047+
return Err(if args.kw_args.labeled.contains_key(param_name) {
20542048
KclError::Semantic(KclErrorDetails {
20552049
source_ranges,
20562050
message: format!("The function does declare a parameter named '{param_name}', but this parameter doesn't use a label. Try removing the `{param_name}:`"),
@@ -2065,7 +2059,7 @@ fn assign_args_to_params_kw(
20652059
};
20662060
exec_state.mut_stack().add(
20672061
param.identifier.name.clone(),
2068-
unlabeled.value.clone(),
2062+
unlabeled.value,
20692063
(&param.identifier).into(),
20702064
)?;
20712065
}
@@ -2140,7 +2134,7 @@ async fn call_user_defined_function(
21402134

21412135
async fn call_user_defined_function_kw(
21422136
fn_name: Option<&str>,
2143-
args: crate::std::args::KwArgs,
2137+
args: Args,
21442138
memory: EnvironmentRef,
21452139
function_expression: NodeRef<'_, FunctionExpression>,
21462140
exec_state: &mut ExecState,
@@ -2328,8 +2322,7 @@ impl FunctionSource {
23282322
}
23292323

23302324
let result =
2331-
call_user_defined_function_kw(fn_name.as_deref(), args.kw_args, *memory, ast, exec_state, ctx)
2332-
.await;
2325+
call_user_defined_function_kw(fn_name.as_deref(), args, *memory, ast, exec_state, ctx).await;
23332326

23342327
// Track return operation.
23352328
#[cfg(feature = "artifact-graph")]

rust/kcl-lib/src/execution/mod.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2266,4 +2266,20 @@ foo() |> extrude(length = 1)
22662266
"#;
22672267
parse_execute(ast).await.unwrap();
22682268
}
2269+
2270+
#[tokio::test(flavor = "multi_thread")]
2271+
async fn default_param_for_unlabeled() {
2272+
// Tests that the input param for myExtrude is taken from the pipeline value and that
2273+
// the labelled arg to extrude is ok (i.e., just `length` not `length = length`)
2274+
let ast = r#"fn myExtrude(@sk, length) {
2275+
return extrude(sk, length)
2276+
}
2277+
2278+
sketch001 = startSketchOn(XY)
2279+
|> circle(center = [0, 0], radius = 93.75)
2280+
|> myExtrude(length = 40)
2281+
"#;
2282+
2283+
parse_execute(ast).await.unwrap();
2284+
}
22692285
}

rust/kcl-lib/src/parsing/ast/types/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ impl<T> Node<T> {
182182
self.comment_start = start;
183183
}
184184

185-
pub fn map_ref<'a, U: 'a>(&'a self, f: fn(&'a T) -> U) -> Node<U> {
185+
pub fn map_ref<'a, U: 'a>(&'a self, f: impl Fn(&'a T) -> U) -> Node<U> {
186186
Node {
187187
inner: f(&self.inner),
188188
start: self.start,
@@ -2327,7 +2327,7 @@ impl Name {
23272327

23282328
pub fn local_ident(&self) -> Option<Node<&str>> {
23292329
if self.path.is_empty() && !self.abs_path {
2330-
Some(self.name.map_ref(|n| &n.name))
2330+
Some(self.name.map_ref(|n| &*n.name))
23312331
} else {
23322332
None
23332333
}

rust/kcl-lib/src/parsing/parser.rs

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2709,13 +2709,26 @@ fn pipe_sep(i: &mut TokenSlice) -> PResult<()> {
27092709
}
27102710

27112711
fn labeled_argument(i: &mut TokenSlice) -> PResult<LabeledArg> {
2712-
separated_pair(
2712+
(
27132713
terminated(nameable_identifier, opt(whitespace)),
2714-
terminated(one_of((TokenType::Operator, "=")), opt(whitespace)),
2715-
expression,
2714+
opt((
2715+
terminated(one_of((TokenType::Operator, "=")), opt(whitespace)),
2716+
expression,
2717+
)),
27162718
)
2717-
.map(|(label, arg)| LabeledArg { label, arg })
2718-
.parse_next(i)
2719+
.map(|(label, arg)| match arg {
2720+
Some((_, arg)) => LabeledArg { label, arg },
2721+
None => LabeledArg {
2722+
label: label.clone(),
2723+
arg: Expr::Name(Box::new(label.map_ref(|_| Name {
2724+
name: label.clone(),
2725+
path: Vec::new(),
2726+
abs_path: false,
2727+
digest: None,
2728+
}))),
2729+
},
2730+
})
2731+
.parse_next(i)
27192732
}
27202733

27212734
/// A type of a function argument.
@@ -3035,6 +3048,7 @@ fn fn_call_kw(i: &mut TokenSlice) -> PResult<Node<CallExpressionKw>> {
30353048
return Ok(result);
30363049
}
30373050

3051+
#[derive(Debug)]
30383052
#[allow(clippy::large_enum_variant)]
30393053
enum ArgPlace {
30403054
NonCode(Node<NonCodeNode>),
@@ -4912,7 +4926,7 @@ bar = 1
49124926

49134927
#[test]
49144928
fn test_sensible_error_when_missing_equals_in_kwarg() {
4915-
for (i, program) in ["f(x=1,y)", "f(x=1,y,z)", "f(x=1,y,z=1)", "f(x=1, y, z=1)"]
4929+
for (i, program) in ["f(x=1,y + 1)", "f(x=1,y + 1,f(z))", "f(x=1,3,z=1)", "f(x=1, y::y, z=1)"]
49164930
.into_iter()
49174931
.enumerate()
49184932
{
@@ -4923,11 +4937,6 @@ bar = 1
49234937
cause.message, "This argument needs a label, but it doesn't have one",
49244938
"failed test {i}: {program}"
49254939
);
4926-
assert_eq!(
4927-
cause.source_range.start(),
4928-
program.find("y").unwrap(),
4929-
"failed test {i}: {program}"
4930-
);
49314940
}
49324941
}
49334942

rust/kcl-lib/src/std/args.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ pub struct Args {
160160
pub ctx: ExecutorContext,
161161
/// If this call happens inside a pipe (|>) expression, this holds the LHS of that |>.
162162
/// Otherwise it's None.
163-
pipe_value: Option<Arg>,
163+
pub pipe_value: Option<Arg>,
164164
}
165165

166166
impl Args {

0 commit comments

Comments
 (0)