Add array concatenation using the plus operator

This commit is contained in:
Jonathan Tran
2025-07-01 19:02:50 -04:00
parent fba62dab98
commit 4de0b57ea4
7 changed files with 380 additions and 16 deletions

View File

@ -1086,6 +1086,32 @@ impl Node<MemberExpression> {
}
}
fn concat(left: &[KclValue], left_el_ty: &RuntimeType, right: &[KclValue], right_el_ty: &RuntimeType) -> KclValue {
if left.is_empty() {
return KclValue::HomArray {
value: right.to_vec(),
ty: right_el_ty.clone(),
};
}
if right.is_empty() {
return KclValue::HomArray {
value: left.to_vec(),
ty: left_el_ty.clone(),
};
}
let mut new = left.to_vec();
new.extend_from_slice(right);
// Propagate the element type if we can.
let ty = if right_el_ty.subtype(left_el_ty) {
left_el_ty.clone()
} else if left_el_ty.subtype(right_el_ty) {
right_el_ty.clone()
} else {
RuntimeType::any()
};
KclValue::HomArray { value: new, ty }
}
impl Node<BinaryExpression> {
#[async_recursion]
pub async fn get_result(&self, exec_state: &mut ExecState, ctx: &ExecutorContext) -> Result<KclValue, KclError> {
@ -1104,6 +1130,50 @@ impl Node<BinaryExpression> {
meta,
});
}
// Array plus is concatenation.
match (&left_value, &right_value) {
(
KclValue::HomArray {
value: left,
ty: left_el_ty,
..
},
KclValue::HomArray {
value: right,
ty: right_el_ty,
..
},
) => {
return Ok(concat(left, left_el_ty, right, right_el_ty));
}
(
KclValue::HomArray {
value: left,
ty: left_el_ty,
..
},
_,
) => {
// Any single value can be coerced to an array.
let right = vec![right_value.clone()];
let right_el_ty = RuntimeType::any();
return Ok(concat(left, left_el_ty, &right, &right_el_ty));
}
(
_,
KclValue::HomArray {
value: right,
ty: right_el_ty,
..
},
) => {
// Any single value can be coerced to an array.
let left = vec![left_value.clone()];
let left_el_ty = RuntimeType::any();
return Ok(concat(&left, &left_el_ty, right, right_el_ty));
}
_ => {}
}
}
// Then check if we have solids.

View File

@ -246,7 +246,7 @@ impl RuntimeType {
}
// Subtype with no coercion, including refining numeric types.
fn subtype(&self, sup: &RuntimeType) -> bool {
pub(super) fn subtype(&self, sup: &RuntimeType) -> bool {
use RuntimeType::*;
match (self, sup) {

View File

@ -14,7 +14,7 @@ description: Result of parsing add_arrays.kcl
"commentStart": 0,
"end": 0,
"moduleId": 0,
"name": "answer",
"name": "a",
"start": 0,
"type": "Identifier"
},
@ -96,6 +96,170 @@ description: Result of parsing add_arrays.kcl
"start": 0,
"type": "VariableDeclaration",
"type": "VariableDeclaration"
},
{
"commentStart": 0,
"declaration": {
"commentStart": 0,
"end": 0,
"id": {
"commentStart": 0,
"end": 0,
"moduleId": 0,
"name": "b",
"start": 0,
"type": "Identifier"
},
"init": {
"commentStart": 0,
"end": 0,
"left": {
"commentStart": 0,
"elements": [
{
"commentStart": 0,
"end": 0,
"moduleId": 0,
"raw": "0",
"start": 0,
"type": "Literal",
"type": "Literal",
"value": {
"value": 0.0,
"suffix": "None"
}
},
{
"commentStart": 0,
"end": 0,
"moduleId": 0,
"raw": "1",
"start": 0,
"type": "Literal",
"type": "Literal",
"value": {
"value": 1.0,
"suffix": "None"
}
}
],
"end": 0,
"moduleId": 0,
"start": 0,
"type": "ArrayExpression",
"type": "ArrayExpression"
},
"moduleId": 0,
"operator": "+",
"right": {
"commentStart": 0,
"end": 0,
"moduleId": 0,
"raw": "2",
"start": 0,
"type": "Literal",
"type": "Literal",
"value": {
"value": 2.0,
"suffix": "None"
}
},
"start": 0,
"type": "BinaryExpression",
"type": "BinaryExpression"
},
"moduleId": 0,
"start": 0,
"type": "VariableDeclarator"
},
"end": 0,
"kind": "const",
"moduleId": 0,
"start": 0,
"type": "VariableDeclaration",
"type": "VariableDeclaration"
},
{
"commentStart": 0,
"declaration": {
"commentStart": 0,
"end": 0,
"id": {
"commentStart": 0,
"end": 0,
"moduleId": 0,
"name": "c",
"start": 0,
"type": "Identifier"
},
"init": {
"commentStart": 0,
"end": 0,
"left": {
"commentStart": 0,
"end": 0,
"moduleId": 0,
"raw": "0",
"start": 0,
"type": "Literal",
"type": "Literal",
"value": {
"value": 0.0,
"suffix": "None"
}
},
"moduleId": 0,
"operator": "+",
"right": {
"commentStart": 0,
"elements": [
{
"commentStart": 0,
"end": 0,
"moduleId": 0,
"raw": "1",
"start": 0,
"type": "Literal",
"type": "Literal",
"value": {
"value": 1.0,
"suffix": "None"
}
},
{
"commentStart": 0,
"end": 0,
"moduleId": 0,
"raw": "2",
"start": 0,
"type": "Literal",
"type": "Literal",
"value": {
"value": 2.0,
"suffix": "None"
}
}
],
"end": 0,
"moduleId": 0,
"start": 0,
"type": "ArrayExpression",
"type": "ArrayExpression"
},
"start": 0,
"type": "BinaryExpression",
"type": "BinaryExpression"
},
"moduleId": 0,
"start": 0,
"type": "VariableDeclarator"
},
"end": 0,
"kind": "const",
"moduleId": 0,
"start": 0,
"type": "VariableDeclaration",
"type": "VariableDeclaration"
}
],
"commentStart": 0,

View File

@ -1,12 +0,0 @@
---
source: kcl-lib/src/simulation_tests.rs
description: Error from executing add_arrays.kcl
---
KCL Semantic error
× semantic: Expected a number, but found an array of `number`, `number`
╭────
1 │ answer = [0, 1] + [2]
· ───┬──
· ╰── tests/add_arrays/input.kcl
╰────

View File

@ -1 +1,3 @@
answer = [0, 1] + [2]
a = [0, 1] + [2]
b = [0, 1] + 2
c = 0 + [1, 2]

View File

@ -0,0 +1,138 @@
---
source: kcl-lib/src/simulation_tests.rs
description: Variables in memory after executing add_arrays.kcl
---
{
"a": {
"type": "HomArray",
"value": [
{
"type": "Number",
"value": 0.0,
"ty": {
"type": "Default",
"len": {
"type": "Mm"
},
"angle": {
"type": "Degrees"
}
}
},
{
"type": "Number",
"value": 1.0,
"ty": {
"type": "Default",
"len": {
"type": "Mm"
},
"angle": {
"type": "Degrees"
}
}
},
{
"type": "Number",
"value": 2.0,
"ty": {
"type": "Default",
"len": {
"type": "Mm"
},
"angle": {
"type": "Degrees"
}
}
}
]
},
"b": {
"type": "HomArray",
"value": [
{
"type": "Number",
"value": 0.0,
"ty": {
"type": "Default",
"len": {
"type": "Mm"
},
"angle": {
"type": "Degrees"
}
}
},
{
"type": "Number",
"value": 1.0,
"ty": {
"type": "Default",
"len": {
"type": "Mm"
},
"angle": {
"type": "Degrees"
}
}
},
{
"type": "Number",
"value": 2.0,
"ty": {
"type": "Default",
"len": {
"type": "Mm"
},
"angle": {
"type": "Degrees"
}
}
}
]
},
"c": {
"type": "HomArray",
"value": [
{
"type": "Number",
"value": 0.0,
"ty": {
"type": "Default",
"len": {
"type": "Mm"
},
"angle": {
"type": "Degrees"
}
}
},
{
"type": "Number",
"value": 1.0,
"ty": {
"type": "Default",
"len": {
"type": "Mm"
},
"angle": {
"type": "Degrees"
}
}
},
{
"type": "Number",
"value": 2.0,
"ty": {
"type": "Default",
"len": {
"type": "Mm"
},
"angle": {
"type": "Degrees"
}
}
}
]
}
}

View File

@ -2,4 +2,6 @@
source: kcl-lib/src/simulation_tests.rs
description: Result of unparsing add_arrays.kcl
---
answer = [0, 1] + [2]
a = [0, 1] + [2]
b = [0, 1] + 2
c = 0 + [1, 2]