2024-03-13 14:22:22 -07:00
|
|
|
---
|
|
|
|
title: "KCL Types"
|
|
|
|
excerpt: "Documentation of types for the KCL standard library for the Zoo Modeling App."
|
|
|
|
layout: manual
|
|
|
|
---
|
2023-09-13 11:59:21 -07:00
|
|
|
|
|
|
|
`KCL` defines the following types and keywords the language.
|
|
|
|
|
|
|
|
All these types can be nested in various forms where nesting applies. Like
|
|
|
|
arrays can hold objects and vice versa.
|
|
|
|
|
|
|
|
## Boolean
|
|
|
|
|
|
|
|
`true` or `false` work when defining values.
|
|
|
|
|
2024-09-16 11:50:59 -07:00
|
|
|
## Constant declaration
|
2023-09-13 11:59:21 -07:00
|
|
|
|
2024-10-02 14:19:40 -05:00
|
|
|
Constants are defined with a name and a value, like so:
|
2023-09-13 11:59:21 -07:00
|
|
|
|
|
|
|
```
|
2024-10-02 14:19:40 -05:00
|
|
|
myBool = false
|
2023-09-13 11:59:21 -07:00
|
|
|
```
|
|
|
|
|
2024-09-16 11:50:59 -07:00
|
|
|
Currently you cannot redeclare a constant.
|
|
|
|
|
2023-09-13 11:59:21 -07:00
|
|
|
## Array
|
|
|
|
|
|
|
|
An array is defined with `[]` braces. What is inside the brackets can
|
|
|
|
be of any type. For example, the following is completely valid:
|
|
|
|
|
|
|
|
```
|
2024-10-02 14:19:40 -05:00
|
|
|
myArray = ["thing", 2, false]
|
2023-09-13 11:59:21 -07:00
|
|
|
```
|
|
|
|
|
|
|
|
If you want to get a value from an array you can use the index like so:
|
|
|
|
`myArray[0]`.
|
|
|
|
|
|
|
|
|
|
|
|
## Object
|
|
|
|
|
|
|
|
An object is defined with `{}` braces. Here is an example object:
|
|
|
|
|
|
|
|
```
|
2024-11-27 11:14:59 -05:00
|
|
|
myObj = { a = 0, b = "thing" }
|
2023-09-13 11:59:21 -07:00
|
|
|
```
|
|
|
|
|
|
|
|
We support two different ways of getting properties from objects, you can call
|
|
|
|
`myObj.a` or `myObj["a"]` both work.
|
|
|
|
|
2025-02-05 13:03:28 -06:00
|
|
|
## Binary expressions
|
|
|
|
|
|
|
|
You can also do math! Let's show an example below:
|
|
|
|
|
|
|
|
```
|
|
|
|
myMathExpression = 3 + 1 * 2 / 3 - 7
|
|
|
|
```
|
|
|
|
|
|
|
|
You can nest expressions in parenthesis as well:
|
|
|
|
|
|
|
|
```
|
|
|
|
myMathExpression = 3 + (1 * 2 / (3 - 7))
|
|
|
|
```
|
2023-09-13 11:59:21 -07:00
|
|
|
|
|
|
|
## Functions
|
|
|
|
|
|
|
|
We also have support for defining your own functions. Functions can take in any
|
|
|
|
type of argument. Below is an example of the syntax:
|
|
|
|
|
|
|
|
```
|
2024-12-03 13:17:02 -05:00
|
|
|
fn myFn(x) {
|
2023-09-13 11:59:21 -07:00
|
|
|
return x
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
As you can see above `myFn` just returns whatever it is given.
|
|
|
|
|
2025-02-27 09:34:55 +13:00
|
|
|
KCL's early drafts used positional arguments, but we now use keyword arguments:
|
2023-09-13 11:59:21 -07:00
|
|
|
|
2025-02-05 13:03:28 -06:00
|
|
|
```
|
2025-02-27 09:34:55 +13:00
|
|
|
// If you declare a function like this
|
2025-02-05 13:03:28 -06:00
|
|
|
fn add(left, right) {
|
|
|
|
return left + right
|
|
|
|
}
|
2023-09-13 11:59:21 -07:00
|
|
|
|
2025-02-27 09:34:55 +13:00
|
|
|
// You can call it like this:
|
2025-02-05 13:03:28 -06:00
|
|
|
total = add(left = 1, right = 2)
|
2023-09-13 11:59:21 -07:00
|
|
|
```
|
|
|
|
|
2025-02-05 13:03:28 -06:00
|
|
|
Functions can also declare one *unlabeled* arg. If you do want to declare an unlabeled arg, it must
|
|
|
|
be the first arg declared.
|
2023-09-13 11:59:21 -07:00
|
|
|
|
|
|
|
```
|
2025-02-05 13:03:28 -06:00
|
|
|
// The @ indicates an argument can be used without a label.
|
|
|
|
// Note that only the first argument can use @.
|
|
|
|
fn increment(@x) {
|
|
|
|
return x + 1
|
|
|
|
}
|
|
|
|
|
|
|
|
fn add(@x, delta) {
|
|
|
|
return x + delta
|
|
|
|
}
|
|
|
|
|
|
|
|
two = increment(1)
|
|
|
|
three = add(1, delta = 2)
|
|
|
|
```
|
|
|
|
|
|
|
|
## Pipelines
|
|
|
|
|
|
|
|
It can be hard to read repeated function calls, because of all the nested brackets.
|
|
|
|
|
2025-02-27 09:34:55 +13:00
|
|
|
```norun
|
2025-02-05 13:03:28 -06:00
|
|
|
i = 1
|
|
|
|
x = h(g(f(i)))
|
|
|
|
```
|
|
|
|
|
|
|
|
You can make this easier to read by breaking it into many declarations, but that is a bit annoying.
|
|
|
|
|
2025-02-27 09:34:55 +13:00
|
|
|
```norun
|
2025-02-05 13:03:28 -06:00
|
|
|
i = 1
|
|
|
|
x0 = f(i)
|
|
|
|
x1 = g(x0)
|
|
|
|
x = h(x1)
|
|
|
|
```
|
|
|
|
|
|
|
|
Instead, you can use the pipeline operator (`|>`) to simplify this.
|
|
|
|
|
|
|
|
Basically, `x |> f(%)` is a shorthand for `f(x)`. The left-hand side of the `|>` gets put into
|
|
|
|
the `%` in the right-hand side.
|
|
|
|
|
|
|
|
So, this means `x |> f(%) |> g(%)` is shorthand for `g(f(x))`. The code example above, with its
|
|
|
|
somewhat-clunky `x0` and `x1` constants could be rewritten as
|
|
|
|
|
2025-02-27 09:34:55 +13:00
|
|
|
```norun
|
2025-02-05 13:03:28 -06:00
|
|
|
i = 1
|
|
|
|
x = i
|
2025-02-27 09:34:55 +13:00
|
|
|
|> f(%)
|
|
|
|
|> g(%)
|
|
|
|
|> h(%)
|
2025-02-05 13:03:28 -06:00
|
|
|
```
|
|
|
|
|
|
|
|
This helps keep your code neat and avoid unnecessary declarations.
|
|
|
|
|
|
|
|
## Pipelines and keyword arguments
|
|
|
|
|
|
|
|
Say you have a long pipeline of sketch functions, like this:
|
|
|
|
|
2025-02-27 09:34:55 +13:00
|
|
|
```norun
|
|
|
|
startSketchOn('XZ')
|
|
|
|
|> line(%, end = [3, 4])
|
|
|
|
|> line(%, end = [10, 10])
|
|
|
|
|> line(%, end = [-13, -14])
|
|
|
|
|> close(%)
|
2025-02-05 13:03:28 -06:00
|
|
|
```
|
|
|
|
|
|
|
|
In this example, each function call outputs a sketch, and it gets put into the next function call via
|
|
|
|
the `%`, into the first (unlabeled) argument.
|
|
|
|
|
|
|
|
If a function call uses an unlabeled first parameter, it will default to `%` if it's not given. This
|
|
|
|
means that `|> line(%, end = [3, 4])` and `|> line(end = [3, 4])` are equivalent! So the above
|
|
|
|
could be rewritten as
|
|
|
|
|
2025-02-27 09:34:55 +13:00
|
|
|
```norun
|
|
|
|
startSketchOn('XZ')
|
|
|
|
|> line(end = [3, 4])
|
|
|
|
|> line(end = [10, 10])
|
|
|
|
|> line(end = [-13, -14])
|
|
|
|
|> close()
|
2025-02-05 13:03:28 -06:00
|
|
|
```
|
|
|
|
|
|
|
|
Note that we are still in the process of migrating KCL's standard library to use keyword arguments. So some
|
|
|
|
functions are still unfortunately using positional arguments. We're moving them over, so keep checking back.
|
|
|
|
Some functions like `angledLine`, `startProfileAt` etc are still using the old positional argument syntax.
|
|
|
|
Check the docs page for each function and look at its examples to see.
|
2023-09-13 11:59:21 -07:00
|
|
|
|
2024-07-05 16:53:13 -07:00
|
|
|
## Tags
|
2024-07-05 10:44:29 -07:00
|
|
|
|
2024-07-05 16:53:13 -07:00
|
|
|
Tags are used to give a name (tag) to a specific path.
|
2024-07-05 10:44:29 -07:00
|
|
|
|
2024-07-05 16:53:13 -07:00
|
|
|
### Tag Declaration
|
|
|
|
|
|
|
|
The syntax for declaring a tag is `$myTag` you would use it in the following
|
|
|
|
way:
|
|
|
|
|
2025-02-27 09:34:55 +13:00
|
|
|
```norun
|
2024-07-05 16:53:13 -07:00
|
|
|
startSketchOn('XZ')
|
|
|
|
|> startProfileAt(origin, %)
|
2025-02-05 13:03:28 -06:00
|
|
|
|> angledLine({angle = 0, length = 191.26}, %, $rectangleSegmentA001)
|
|
|
|
|> angledLine({
|
|
|
|
angle = segAng(rectangleSegmentA001) - 90,
|
|
|
|
length = 196.99,
|
|
|
|
}, %, $rectangleSegmentB001)
|
|
|
|
|> angledLine({
|
|
|
|
angle = segAng(rectangleSegmentA001),
|
|
|
|
length = -segLen(rectangleSegmentA001),
|
|
|
|
}, %, $rectangleSegmentC001)
|
|
|
|
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
|
|
|
|> close()
|
2024-07-05 16:53:13 -07:00
|
|
|
```
|
|
|
|
|
|
|
|
### Tag Identifier
|
|
|
|
|
|
|
|
As per the example above you can use the tag identifier to get a reference to the
|
|
|
|
tagged object. The syntax for this is `myTag`.
|
|
|
|
|
|
|
|
In the example above we use the tag identifier to get the angle of the segment
|
|
|
|
`segAng(rectangleSegmentA001, %)`.
|
|
|
|
|
|
|
|
|
|
|
|
### Tag Scope
|
|
|
|
|
|
|
|
Tags are scoped globally if in the root context meaning in this example you can
|
|
|
|
use the tag `rectangleSegmentA001` in any function or expression in the file.
|
|
|
|
|
|
|
|
However if the code was written like this:
|
|
|
|
|
2025-02-27 09:34:55 +13:00
|
|
|
```norun
|
2024-12-03 13:17:02 -05:00
|
|
|
fn rect(origin) {
|
2024-07-05 16:53:13 -07:00
|
|
|
return startSketchOn('XZ')
|
2024-11-27 11:14:59 -05:00
|
|
|
|> startProfileAt(origin, %)
|
2025-02-05 13:03:28 -06:00
|
|
|
|> angledLine({angle = 0, length = 191.26}, %, $rectangleSegmentA001)
|
|
|
|
|> angledLine({
|
|
|
|
angle = segAng(rectangleSegmentA001) - 90,
|
|
|
|
length = 196.99
|
|
|
|
}, %, $rectangleSegmentB001)
|
|
|
|
|> angledLine({
|
|
|
|
angle = segAng(rectangleSegmentA001),
|
|
|
|
length = -segLen(rectangleSegmentA001)
|
|
|
|
}, %, $rectangleSegmentC001)
|
|
|
|
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
|
|
|
|> close()
|
2024-07-05 16:53:13 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
rect([0, 0])
|
|
|
|
rect([20, 0])
|
|
|
|
```
|
|
|
|
|
|
|
|
Those tags would only be available in the `rect` function and not globally.
|
|
|
|
|
|
|
|
However you likely want to use those tags somewhere outside the `rect` function.
|
|
|
|
|
|
|
|
Tags are accessible through the sketch group they are declared in.
|
|
|
|
For example the following code works.
|
|
|
|
|
2025-02-27 09:34:55 +13:00
|
|
|
```norun
|
2024-12-03 13:17:02 -05:00
|
|
|
fn rect(origin) {
|
2024-07-05 16:53:13 -07:00
|
|
|
return startSketchOn('XZ')
|
2024-11-27 11:14:59 -05:00
|
|
|
|> startProfileAt(origin, %)
|
2025-02-05 13:03:28 -06:00
|
|
|
|> angledLine({angle = 0, length = 191.26}, %, $rectangleSegmentA001)
|
|
|
|
|> angledLine({
|
|
|
|
angle = segAng(rectangleSegmentA001) - 90,
|
|
|
|
length = 196.99
|
|
|
|
}, %, $rectangleSegmentB001)
|
|
|
|
|> angledLine({
|
|
|
|
angle = segAng(rectangleSegmentA001),
|
|
|
|
length = -segLen(rectangleSegmentA001)
|
|
|
|
}, %, $rectangleSegmentC001)
|
|
|
|
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
|
|
|
|> close()
|
2024-07-05 16:53:13 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
rect([0, 0])
|
2024-10-02 14:19:40 -05:00
|
|
|
myRect = rect([20, 0])
|
2024-07-05 16:53:13 -07:00
|
|
|
|
2024-11-27 11:14:59 -05:00
|
|
|
myRect
|
2024-07-05 16:53:13 -07:00
|
|
|
|> extrude(10, %)
|
2025-02-21 14:41:25 -06:00
|
|
|
|> fillet(
|
2024-11-27 11:14:59 -05:00
|
|
|
radius = 0.5,
|
|
|
|
tags = [myRect.tags.rectangleSegmentA001]
|
2025-02-21 14:41:25 -06:00
|
|
|
)
|
2024-07-05 16:53:13 -07:00
|
|
|
```
|
|
|
|
|
|
|
|
See how we use the tag `rectangleSegmentA001` in the `fillet` function outside
|
|
|
|
the `rect` function. This is because the `rect` function is returning the
|
|
|
|
sketch group that contains the tags.
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
If you find any issues using any of the above expressions or syntax,
|
2023-09-13 11:59:21 -07:00
|
|
|
please file an issue with the `ast` label on the [modeling-app
|
|
|
|
repo](https://github.com/KittyCAD/modeling-app/issues/new).
|