Skip to content

Commit 01c7b69

Browse files
authored
Function types (#6891)
* Change Fn to fn for function types Signed-off-by: Nick Cameron <[email protected]> * Support args and return types in function types Signed-off-by: Nick Cameron <[email protected]> * Use fancy function types in the docs Signed-off-by: Nick Cameron <[email protected]> --------- Signed-off-by: Nick Cameron <[email protected]>
1 parent 47feae3 commit 01c7b69

File tree

16 files changed

+209
-47
lines changed

16 files changed

+209
-47
lines changed

docs/kcl-std/functions/std-array-map.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ Apply a function to every element of a list.
1010
```kcl
1111
map(
1212
@array: [any],
13-
f: Fn,
13+
f: fn(any): any,
1414
): [any]
1515
```
1616

@@ -22,7 +22,7 @@ Given a list like `[a, b, c]`, and a function like `f`, returns
2222
| Name | Type | Description | Required |
2323
|----------|------|-------------|----------|
2424
| `array` | [`[any]`](/docs/kcl-std/types/std-types-any) | Input array. The output array is this input array, but every element has had the function `f` run on it. | Yes |
25-
| `f` | [`Fn`](/docs/kcl-std/types/std-types-Fn) | A function. The output array is just the input array, but `f` has been run on every item. | Yes |
25+
| `f` | [`fn(any): any`](/docs/kcl-std/types/std-types-fn) | A function. The output array is just the input array, but `f` has been run on every item. | Yes |
2626

2727
### Returns
2828

docs/kcl-std/functions/std-array-reduce.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ layout: manual
1111
reduce(
1212
@array: [any],
1313
initial: any,
14-
f: Fn,
14+
f: fn(any, accum: any): any,
1515
): [any]
1616
```
1717

@@ -24,7 +24,7 @@ using the previous value and the element.
2424
|----------|------|-------------|----------|
2525
| `array` | [`[any]`](/docs/kcl-std/types/std-types-any) | Each element of this array gets run through the function `f`, combined with the previous output from `f`, and then used for the next run. | Yes |
2626
| `initial` | [`any`](/docs/kcl-std/types/std-types-any) | The first time `f` is run, it will be called with the first item of `array` and this initial starting value. | Yes |
27-
| `f` | [`Fn`](/docs/kcl-std/types/std-types-Fn) | Run once per item in the input `array`. This function takes an item from the array, and the previous output from `f` (or `initial` on the very first run). The final time `f` is run, its output is returned as the final output from `reduce`. | Yes |
27+
| `f` | [`fn(any, accum: any): any`](/docs/kcl-std/types/std-types-fn) | Run once per item in the input `array`. This function takes an item from the array, and the previous output from `f` (or `initial` on the very first run). The final time `f` is run, its output is returned as the final output from `reduce`. | Yes |
2828

2929
### Returns
3030

docs/kcl-std/index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,13 +140,13 @@ See also the [types overview](/docs/kcl-lang/types)
140140

141141
* [**Primitive types**](/docs/kcl-lang/types)
142142
* [`End`](/docs/kcl-lang/types#End)
143-
* [`Fn`](/docs/kcl-std/types/std-types-Fn)
144143
* [`ImportedGeometry`](/docs/kcl-std/types/std-types-ImportedGeometry)
145144
* [`Start`](/docs/kcl-lang/types#Start)
146145
* [`TagDeclarator`](/docs/kcl-lang/types#TagDeclarator)
147146
* [`TagIdentifier`](/docs/kcl-lang/types#TagIdentifier)
148147
* [`any`](/docs/kcl-std/types/std-types-any)
149148
* [`bool`](/docs/kcl-std/types/std-types-bool)
149+
* [`fn`](/docs/kcl-std/types/std-types-fn)
150150
* [`number`](/docs/kcl-std/types/std-types-number)
151151
* [`string`](/docs/kcl-std/types/std-types-string)
152152
* [`tag`](/docs/kcl-std/types/std-types-tag)

docs/kcl-std/modules/std-types.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ Types can (optionally) be used to describe a function's arguments and returned v
1717
* [`Axis3d`](/docs/kcl-std/types/std-types-Axis3d)
1818
* [`Edge`](/docs/kcl-std/types/std-types-Edge)
1919
* [`Face`](/docs/kcl-std/types/std-types-Face)
20-
* [`Fn`](/docs/kcl-std/types/std-types-Fn)
2120
* [`Helix`](/docs/kcl-std/types/std-types-Helix)
2221
* [`ImportedGeometry`](/docs/kcl-std/types/std-types-ImportedGeometry)
2322
* [`Plane`](/docs/kcl-std/types/std-types-Plane)
@@ -27,6 +26,7 @@ Types can (optionally) be used to describe a function's arguments and returned v
2726
* [`Solid`](/docs/kcl-std/types/std-types-Solid)
2827
* [`any`](/docs/kcl-std/types/std-types-any)
2928
* [`bool`](/docs/kcl-std/types/std-types-bool)
29+
* [`fn`](/docs/kcl-std/types/std-types-fn)
3030
* [`number`](/docs/kcl-std/types/std-types-number)
3131
* [`string`](/docs/kcl-std/types/std-types-string)
3232
* [`tag`](/docs/kcl-std/types/std-types-tag)

docs/kcl-std/types/std-types-Fn.md renamed to docs/kcl-std/types/std-types-fn.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
---
2-
title: "Fn"
2+
title: "fn"
33
subtitle: "Type in std::types"
44
excerpt: "The type of any function in KCL."
55
layout: manual

rust/kcl-lib/src/docs/gen_std_tests.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -674,6 +674,8 @@ fn cleanup_type_string(input: &str, fmt_for_text: bool) -> String {
674674

675675
if fmt_for_text && ty.starts_with("number") {
676676
format!("[{prefix}{ty}{suffix}](/docs/kcl-std/types/std-types-number)")
677+
} else if fmt_for_text && ty.starts_with("fn") {
678+
format!("[{prefix}{ty}{suffix}](/docs/kcl-std/types/std-types-fn)")
677679
} else if fmt_for_text && SPECIAL_TYPES.contains(&ty) {
678680
format!("[{prefix}{ty}{suffix}](/docs/kcl-lang/types#{ty})")
679681
} else if fmt_for_text && DECLARED_TYPES.contains(&ty) {

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ const DECLARED_TYPES: [&str; 17] = [
3939
"Axis2d",
4040
"Axis3d",
4141
"ImportedGeometry",
42-
"Fn",
42+
"fn",
4343
];
4444

4545
lazy_static::lazy_static! {

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ impl RuntimeType {
183183
AstPrimitiveType::Named(name) => Self::from_alias(&name.name, exec_state, source_range)?,
184184
AstPrimitiveType::Tag => RuntimeType::Primitive(PrimitiveType::Tag),
185185
AstPrimitiveType::ImportedGeometry => RuntimeType::Primitive(PrimitiveType::ImportedGeometry),
186-
AstPrimitiveType::Function => RuntimeType::Primitive(PrimitiveType::Function),
186+
AstPrimitiveType::Function(_) => RuntimeType::Primitive(PrimitiveType::Function),
187187
})
188188
}
189189

rust/kcl-lib/src/parsing/ast/digest.rs

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ use sha2::{Digest as DigestTrait, Sha256};
22

33
use crate::parsing::ast::types::{
44
Annotation, ArrayExpression, ArrayRangeExpression, AscribedExpression, BinaryExpression, BinaryPart, BodyItem,
5-
CallExpressionKw, DefaultParamVal, ElseIf, Expr, ExpressionStatement, FunctionExpression, Identifier, IfExpression,
6-
ImportItem, ImportSelector, ImportStatement, ItemVisibility, KclNone, LabelledExpression, Literal,
5+
CallExpressionKw, DefaultParamVal, ElseIf, Expr, ExpressionStatement, FunctionExpression, FunctionType, Identifier,
6+
IfExpression, ImportItem, ImportSelector, ImportStatement, ItemVisibility, KclNone, LabelledExpression, Literal,
77
LiteralIdentifier, LiteralValue, MemberExpression, MemberObject, Name, ObjectExpression, ObjectProperty, Parameter,
88
PipeExpression, PipeSubstitution, PrimitiveType, Program, ReturnStatement, TagDeclarator, Type, TypeDeclaration,
99
UnaryExpression, VariableDeclaration, VariableDeclarator, VariableKind,
@@ -233,13 +233,28 @@ impl PrimitiveType {
233233
PrimitiveType::Boolean => hasher.update(b"bool"),
234234
PrimitiveType::Tag => hasher.update(b"tag"),
235235
PrimitiveType::ImportedGeometry => hasher.update(b"ImportedGeometry"),
236-
PrimitiveType::Function => hasher.update(b"Fn"),
236+
PrimitiveType::Function(f) => hasher.update(f.compute_digest()),
237237
}
238238

239239
hasher.finalize().into()
240240
}
241241
}
242242

243+
impl FunctionType {
244+
compute_digest!(|slf, hasher| {
245+
if let Some(u) = &mut slf.unnamed_arg {
246+
hasher.update(u.compute_digest());
247+
}
248+
slf.named_args.iter_mut().for_each(|(a, t)| {
249+
a.compute_digest();
250+
t.compute_digest();
251+
});
252+
if let Some(r) = &mut slf.return_type {
253+
hasher.update(r.compute_digest());
254+
}
255+
});
256+
}
257+
243258
impl Parameter {
244259
compute_digest!(|slf, hasher| {
245260
hasher.update(slf.identifier.compute_digest());

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

Lines changed: 49 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3199,8 +3199,8 @@ pub enum PrimitiveType {
31993199
Tag,
32003200
/// Imported from other CAD system.
32013201
ImportedGeometry,
3202-
/// `Fn`, type of functions.
3203-
Function,
3202+
/// `fn`, type of functions.
3203+
Function(FunctionType),
32043204
/// An identifier used as a type (not really a primitive type, but whatever).
32053205
Named(Node<Identifier>),
32063206
}
@@ -3215,7 +3215,6 @@ impl PrimitiveType {
32153215
("number", None) => Some(PrimitiveType::Number(NumericSuffix::None)),
32163216
("number", Some(s)) => Some(PrimitiveType::Number(s)),
32173217
("ImportedGeometry", None) => Some(PrimitiveType::ImportedGeometry),
3218-
("Fn", None) => Some(PrimitiveType::Function),
32193218
_ => None,
32203219
}
32213220
}
@@ -3236,12 +3235,57 @@ impl fmt::Display for PrimitiveType {
32363235
PrimitiveType::Boolean => write!(f, "bool"),
32373236
PrimitiveType::Tag => write!(f, "tag"),
32383237
PrimitiveType::ImportedGeometry => write!(f, "ImportedGeometry"),
3239-
PrimitiveType::Function => write!(f, "Fn"),
3238+
PrimitiveType::Function(t) => {
3239+
write!(f, "fn")?;
3240+
if t.unnamed_arg.is_some() || !t.named_args.is_empty() || t.return_type.is_some() {
3241+
write!(f, "(")?;
3242+
if let Some(u) = &t.unnamed_arg {
3243+
write!(f, "{u}")?;
3244+
if !t.named_args.is_empty() {
3245+
write!(f, ", ")?;
3246+
}
3247+
}
3248+
for (i, (a, t)) in t.named_args.iter().enumerate() {
3249+
if i != 0 {
3250+
write!(f, ", ")?;
3251+
}
3252+
write!(f, "{}: {t}", a.name)?;
3253+
}
3254+
write!(f, ")")?;
3255+
if let Some(r) = &t.return_type {
3256+
write!(f, ": {r}")?;
3257+
}
3258+
}
3259+
Ok(())
3260+
}
32403261
PrimitiveType::Named(n) => write!(f, "{}", n.name),
32413262
}
32423263
}
32433264
}
32443265

3266+
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
3267+
#[ts(export)]
3268+
pub struct FunctionType {
3269+
pub unnamed_arg: Option<BoxNode<Type>>,
3270+
pub named_args: Vec<(Node<Identifier>, Node<Type>)>,
3271+
pub return_type: Option<BoxNode<Type>>,
3272+
3273+
#[serde(default, skip_serializing_if = "Option::is_none")]
3274+
#[ts(optional)]
3275+
pub digest: Option<Digest>,
3276+
}
3277+
3278+
impl FunctionType {
3279+
pub fn empty_fn_type() -> Self {
3280+
FunctionType {
3281+
unnamed_arg: None,
3282+
named_args: Vec::new(),
3283+
return_type: None,
3284+
digest: None,
3285+
}
3286+
}
3287+
}
3288+
32453289
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
32463290
#[ts(export)]
32473291
#[serde(tag = "type")]
@@ -3293,7 +3337,7 @@ impl fmt::Display for Type {
32933337
} else {
32943338
write!(f, ",")?;
32953339
}
3296-
write!(f, "{}: ", p.identifier.name)?;
3340+
write!(f, " {}:", p.identifier.name)?;
32973341
if let Some(ty) = &p.type_ {
32983342
write!(f, " {}", ty.inner)?;
32993343
}

0 commit comments

Comments
 (0)