Skip to content

Commit 8015351

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

File tree

243 files changed

+43065
-57180
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

243 files changed

+43065
-57180
lines changed

docs/kcl-src/modules.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ to other modules.
1212

1313
```kcl
1414
// util.kcl
15-
export fn increment(x) {
15+
export fn increment(@x) {
1616
return x + 1
1717
}
1818
```
@@ -37,11 +37,11 @@ Multiple functions can be exported in a file.
3737

3838
```kcl
3939
// util.kcl
40-
export fn increment(x) {
40+
export fn increment(@x) {
4141
return x + 1
4242
}
4343
44-
export fn decrement(x) {
44+
export fn decrement(@x) {
4545
return x - 1
4646
}
4747
```
@@ -81,7 +81,7 @@ fn cube(center) {
8181
|> extrude(length = 10)
8282
}
8383
84-
myCube = cube([0, 0])
84+
myCube = cube(center = [0, 0])
8585
```
8686

8787
*Pros*

docs/kcl-src/types.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -249,8 +249,8 @@ fn rect(origin) {
249249
|> close()
250250
}
251251
252-
rect([0, 0])
253-
rect([20, 0])
252+
rect(origin = [0, 0])
253+
rect(origin = [20, 0])
254254
```
255255

256256
Those tags would only be available in the `rect` function and not globally.
@@ -279,8 +279,8 @@ fn rect(origin) {
279279
|> close()
280280
}
281281
282-
rect([0, 0])
283-
myRect = rect([20, 0])
282+
rect(origin = [0, 0])
283+
myRect = rect(origin = [20, 0])
284284
285285
myRect
286286
|> extrude(length = 10)

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 & 18 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,
@@ -2068,7 +2068,7 @@ fn assign_args_to_params(
20682068
fn type_check_params_kw(
20692069
fn_name: Option<&str>,
20702070
function_expression: NodeRef<'_, FunctionExpression>,
2071-
args: &mut crate::std::args::KwArgs,
2071+
args: &mut KwArgs,
20722072
exec_state: &mut ExecState,
20732073
) -> Result<(), KclError> {
20742074
for (label, arg) in &mut args.labeled {
@@ -2156,18 +2156,18 @@ fn type_check_params_kw(
21562156
fn assign_args_to_params_kw(
21572157
fn_name: Option<&str>,
21582158
function_expression: NodeRef<'_, FunctionExpression>,
2159-
mut args: crate::std::args::KwArgs,
2159+
mut args: Args,
21602160
exec_state: &mut ExecState,
21612161
) -> Result<(), KclError> {
2162-
type_check_params_kw(fn_name, function_expression, &mut args, exec_state)?;
2162+
type_check_params_kw(fn_name, function_expression, &mut args.kw_args, exec_state)?;
21632163

21642164
// Add the arguments to the memory. A new call frame should have already
21652165
// been created.
21662166
let source_ranges = vec![function_expression.into()];
21672167

21682168
for param in function_expression.params.iter() {
21692169
if param.labeled {
2170-
let arg = args.labeled.get(&param.identifier.name);
2170+
let arg = args.kw_args.labeled.get(&param.identifier.name);
21712171
let arg_val = match arg {
21722172
Some(arg) => arg.value.clone(),
21732173
None => match param.default_value {
@@ -2187,17 +2187,11 @@ fn assign_args_to_params_kw(
21872187
.mut_stack()
21882188
.add(param.identifier.name.clone(), arg_val, (&param.identifier).into())?;
21892189
} else {
2190-
// TODO: Get the actual source range.
2191-
// Part of https://github.com/KittyCAD/modeling-app/issues/6613
2192-
let pipe_value_source_range = Default::default();
2193-
let default_unlabeled = exec_state
2194-
.mod_local
2195-
.pipe_value
2196-
.clone()
2197-
.map(|val| Arg::new(val, pipe_value_source_range));
2198-
let Some(unlabeled) = args.unlabeled.take().or(default_unlabeled) else {
2190+
let unlabelled = args.kw_args.unlabeled.take().or_else(|| args.pipe_value.take());
2191+
2192+
let Some(unlabeled) = unlabelled else {
21992193
let param_name = &param.identifier.name;
2200-
return Err(if args.labeled.contains_key(param_name) {
2194+
return Err(if args.kw_args.labeled.contains_key(param_name) {
22012195
KclError::Semantic(KclErrorDetails {
22022196
source_ranges,
22032197
message: format!("The function does declare a parameter named '{param_name}', but this parameter doesn't use a label. Try removing the `{param_name}:`"),
@@ -2212,7 +2206,7 @@ fn assign_args_to_params_kw(
22122206
};
22132207
exec_state.mut_stack().add(
22142208
param.identifier.name.clone(),
2215-
unlabeled.value.clone(),
2209+
unlabeled.value,
22162210
(&param.identifier).into(),
22172211
)?;
22182212
}
@@ -2287,7 +2281,7 @@ async fn call_user_defined_function(
22872281

22882282
async fn call_user_defined_function_kw(
22892283
fn_name: Option<&str>,
2290-
args: crate::std::args::KwArgs,
2284+
args: Args,
22912285
memory: EnvironmentRef,
22922286
function_expression: NodeRef<'_, FunctionExpression>,
22932287
exec_state: &mut ExecState,
@@ -2474,7 +2468,7 @@ impl FunctionSource {
24742468
});
24752469
}
24762470

2477-
call_user_defined_function_kw(fn_name.as_deref(), args.kw_args, *memory, ast, exec_state, ctx).await
2471+
call_user_defined_function_kw(fn_name.as_deref(), args, *memory, ast, exec_state, ctx).await
24782472
}
24792473
FunctionSource::None => unreachable!(),
24802474
}

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

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2188,4 +2188,20 @@ foo() |> extrude(length = 1)
21882188
"#;
21892189
parse_execute(ast).await.unwrap();
21902190
}
2191+
2192+
#[tokio::test(flavor = "multi_thread")]
2193+
async fn default_param_for_unlabeled() {
2194+
// Tests that the input param for myExtrude is taken from the pipeline value and that
2195+
// the labelled arg to extrude is ok (i.e., just `length` not `length = length`)
2196+
let ast = r#"fn myExtrude(@sk, length) {
2197+
return extrude(sk, length)
2198+
}
2199+
2200+
sketch001 = startSketchOn(XY)
2201+
|> circle(center = [0, 0], radius = 93.75)
2202+
|> myExtrude(length = 40)
2203+
"#;
2204+
2205+
parse_execute(ast).await.unwrap();
2206+
}
21912207
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ impl<T> Node<T> {
176176
self.comment_start = start;
177177
}
178178

179-
pub fn map_ref<'a, U: 'a>(&'a self, f: fn(&'a T) -> U) -> Node<U> {
179+
pub fn map_ref<'a, U: 'a>(&'a self, f: impl Fn(&'a T) -> U) -> Node<U> {
180180
Node {
181181
inner: f(&self.inner),
182182
start: self.start,
@@ -2390,7 +2390,7 @@ impl Name {
23902390

23912391
pub fn local_ident(&self) -> Option<Node<&str>> {
23922392
if self.path.is_empty() && !self.abs_path {
2393-
Some(self.name.map_ref(|n| &n.name))
2393+
Some(self.name.map_ref(|n| &*n.name))
23942394
} else {
23952395
None
23962396
}

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

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2030,8 +2030,8 @@ fn expr_allowed_in_pipe_expr(i: &mut TokenSlice) -> PResult<Expr> {
20302030
bool_value.map(Expr::Literal),
20312031
tag.map(Box::new).map(Expr::TagDeclarator),
20322032
literal.map(Expr::Literal),
2033-
fn_call.map(Box::new).map(Expr::CallExpression),
20342033
fn_call_kw.map(Box::new).map(Expr::CallExpressionKw),
2034+
fn_call.map(Box::new).map(Expr::CallExpression),
20352035
name.map(Box::new).map(Expr::Name),
20362036
array,
20372037
object.map(Box::new).map(Expr::ObjectExpression),
@@ -2050,8 +2050,8 @@ fn possible_operands(i: &mut TokenSlice) -> PResult<Expr> {
20502050
bool_value.map(Expr::Literal),
20512051
member_expression.map(Box::new).map(Expr::MemberExpression),
20522052
literal.map(Expr::Literal),
2053-
fn_call.map(Box::new).map(Expr::CallExpression),
20542053
fn_call_kw.map(Box::new).map(Expr::CallExpressionKw),
2054+
fn_call.map(Box::new).map(Expr::CallExpression),
20552055
name.map(Box::new).map(Expr::Name),
20562056
binary_expr_in_parens.map(Box::new).map(Expr::BinaryExpression),
20572057
unnecessarily_bracketed,
@@ -2719,13 +2719,26 @@ fn arguments(i: &mut TokenSlice) -> PResult<Vec<Expr>> {
27192719
}
27202720

27212721
fn labeled_argument(i: &mut TokenSlice) -> PResult<LabeledArg> {
2722-
separated_pair(
2722+
(
27232723
terminated(nameable_identifier, opt(whitespace)),
2724-
terminated(one_of((TokenType::Operator, "=")), opt(whitespace)),
2725-
expression,
2724+
opt((
2725+
terminated(one_of((TokenType::Operator, "=")), opt(whitespace)),
2726+
expression,
2727+
)),
27262728
)
2727-
.map(|(label, arg)| LabeledArg { label, arg })
2728-
.parse_next(i)
2729+
.map(|(label, arg)| match arg {
2730+
Some((_, arg)) => LabeledArg { label, arg },
2731+
None => LabeledArg {
2732+
label: label.clone(),
2733+
arg: Expr::Name(Box::new(label.map_ref(|_| Name {
2734+
name: label.clone(),
2735+
path: Vec::new(),
2736+
abs_path: false,
2737+
digest: None,
2738+
}))),
2739+
},
2740+
})
2741+
.parse_next(i)
27292742
}
27302743

27312744
/// A type of a function argument.
@@ -2987,8 +3000,8 @@ fn binding_name(i: &mut TokenSlice) -> PResult<Node<Identifier>> {
29873000
/// Either a positional or keyword function call.
29883001
fn fn_call_pos_or_kw(i: &mut TokenSlice) -> PResult<Expr> {
29893002
alt((
2990-
fn_call.map(Box::new).map(Expr::CallExpression),
29913003
fn_call_kw.map(Box::new).map(Expr::CallExpressionKw),
3004+
fn_call.map(Box::new).map(Expr::CallExpression),
29923005
))
29933006
.parse_next(i)
29943007
}
@@ -3086,6 +3099,7 @@ fn fn_call_kw(i: &mut TokenSlice) -> PResult<Node<CallExpressionKw>> {
30863099
return Ok(result);
30873100
}
30883101

3102+
#[derive(Debug)]
30893103
#[allow(clippy::large_enum_variant)]
30903104
enum ArgPlace {
30913105
NonCode(Node<NonCodeNode>),
@@ -4975,7 +4989,7 @@ bar = 1
49754989

49764990
#[test]
49774991
fn test_sensible_error_when_missing_equals_in_kwarg() {
4978-
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)"]
4992+
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)"]
49794993
.into_iter()
49804994
.enumerate()
49814995
{
@@ -4986,11 +5000,6 @@ bar = 1
49865000
cause.message, "This argument needs a label, but it doesn't have one",
49875001
"failed test {i}: {program}"
49885002
);
4989-
assert_eq!(
4990-
cause.source_range.start(),
4991-
program.find("y").unwrap(),
4992-
"failed test {i}: {program}"
4993-
);
49945003
}
49955004
}
49965005

rust/kcl-lib/src/parsing/snapshots/kcl_lib__parsing__parser__snapshot_tests__a.snap

Lines changed: 18 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -19,24 +19,6 @@ expression: actual
1919
"init": {
2020
"body": [
2121
{
22-
"arguments": [
23-
{
24-
"abs_path": false,
25-
"commentStart": 26,
26-
"end": 28,
27-
"name": {
28-
"commentStart": 26,
29-
"end": 28,
30-
"name": "XY",
31-
"start": 26,
32-
"type": "Identifier"
33-
},
34-
"path": [],
35-
"start": 26,
36-
"type": "Name",
37-
"type": "Name"
38-
}
39-
],
4022
"callee": {
4123
"abs_path": false,
4224
"commentStart": 12,
@@ -55,8 +37,24 @@ expression: actual
5537
"commentStart": 12,
5638
"end": 29,
5739
"start": 12,
58-
"type": "CallExpression",
59-
"type": "CallExpression"
40+
"type": "CallExpressionKw",
41+
"type": "CallExpressionKw",
42+
"unlabeled": {
43+
"abs_path": false,
44+
"commentStart": 26,
45+
"end": 28,
46+
"name": {
47+
"commentStart": 26,
48+
"end": 28,
49+
"name": "XY",
50+
"start": 26,
51+
"type": "Identifier"
52+
},
53+
"path": [],
54+
"start": 26,
55+
"type": "Name",
56+
"type": "Name"
57+
}
6058
},
6159
{
6260
"arguments": [

rust/kcl-lib/src/parsing/snapshots/kcl_lib__parsing__parser__snapshot_tests__ad.snap

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,6 @@ expression: actual
6363
"commentStart": 56,
6464
"end": 74,
6565
"expression": {
66-
"arguments": [],
6766
"callee": {
6867
"abs_path": false,
6968
"commentStart": 56,
@@ -82,8 +81,9 @@ expression: actual
8281
"commentStart": 56,
8382
"end": 74,
8483
"start": 56,
85-
"type": "CallExpression",
86-
"type": "CallExpression"
84+
"type": "CallExpressionKw",
85+
"type": "CallExpressionKw",
86+
"unlabeled": null
8787
},
8888
"start": 56,
8989
"type": "ExpressionStatement",

0 commit comments

Comments
 (0)