Merge branch 'main' into pierremtb/issue1349
@ -1,6 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "untitled-app",
 | 
			
		||||
  "version": "0.17.0",
 | 
			
		||||
  "version": "0.17.1",
 | 
			
		||||
  "private": true,
 | 
			
		||||
  "dependencies": {
 | 
			
		||||
    "@codemirror/autocomplete": "^6.15.0",
 | 
			
		||||
@ -26,7 +26,7 @@
 | 
			
		||||
    "@ts-stack/markdown": "^1.5.0",
 | 
			
		||||
    "@tweenjs/tween.js": "^23.1.1",
 | 
			
		||||
    "@types/node": "^18.19.26",
 | 
			
		||||
    "@types/react": "^18.2.67",
 | 
			
		||||
    "@types/react": "^18.2.73",
 | 
			
		||||
    "@types/react-dom": "^18.2.22",
 | 
			
		||||
    "@uiw/react-codemirror": "^4.21.24",
 | 
			
		||||
    "@xstate/inspect": "^0.8.0",
 | 
			
		||||
 | 
			
		||||
@ -55,5 +55,5 @@
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  "productName": "zoo-modeling-app",
 | 
			
		||||
  "version": "0.17.0"
 | 
			
		||||
  "version": "0.17.1"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										70
									
								
								src/wasm-lib/Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						@ -251,9 +251,9 @@ dependencies = [
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "async-trait"
 | 
			
		||||
version = "0.1.78"
 | 
			
		||||
version = "0.1.79"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "461abc97219de0eaaf81fe3ef974a540158f3d079c2ab200f891f1a2ef201e85"
 | 
			
		||||
checksum = "a507401cad91ec6a857ed5513a2073c82a9b9048762b885bb98655b306964681"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "proc-macro2",
 | 
			
		||||
 "quote",
 | 
			
		||||
@ -513,9 +513,9 @@ dependencies = [
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "chrono"
 | 
			
		||||
version = "0.4.35"
 | 
			
		||||
version = "0.4.37"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "8eaf5903dcbc0a39312feb77df2ff4c76387d591b9fc7b04a238dcf8bb62639a"
 | 
			
		||||
checksum = "8a0d04d43504c61aa6c7531f1871dd0d418d91130162063b789da00fd7057a5e"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "android-tzdata",
 | 
			
		||||
 "iana-time-zone",
 | 
			
		||||
@ -565,9 +565,9 @@ dependencies = [
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "clap"
 | 
			
		||||
version = "4.5.3"
 | 
			
		||||
version = "4.5.4"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "949626d00e063efc93b6dca932419ceb5432f99769911c0b995f7e884c778813"
 | 
			
		||||
checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "clap_builder",
 | 
			
		||||
 "clap_derive",
 | 
			
		||||
@ -589,9 +589,9 @@ dependencies = [
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "clap_derive"
 | 
			
		||||
version = "4.5.3"
 | 
			
		||||
version = "4.5.4"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "90239a040c80f5e14809ca132ddc4176ab33d5e17e49691793296e3fcb34d72f"
 | 
			
		||||
checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "heck 0.5.0",
 | 
			
		||||
 "proc-macro2",
 | 
			
		||||
@ -944,6 +944,23 @@ dependencies = [
 | 
			
		||||
 "syn 2.0.55",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "derive-docs"
 | 
			
		||||
version = "0.1.12"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "138b94245509a9dd516008788b585c34847829cf37b40a758b4aa581cf94f147"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "Inflector",
 | 
			
		||||
 "convert_case",
 | 
			
		||||
 "once_cell",
 | 
			
		||||
 "proc-macro2",
 | 
			
		||||
 "quote",
 | 
			
		||||
 "regex",
 | 
			
		||||
 "serde",
 | 
			
		||||
 "serde_tokenstream",
 | 
			
		||||
 "syn 2.0.55",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "diesel_derives"
 | 
			
		||||
version = "2.1.3"
 | 
			
		||||
@ -1730,16 +1747,15 @@ dependencies = [
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "insta"
 | 
			
		||||
version = "1.36.1"
 | 
			
		||||
version = "1.37.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "0a7c22c4d34ef4788c351e971c52bfdfe7ea2766f8c5466bc175dd46e52ac22e"
 | 
			
		||||
checksum = "1718b3f2b85bb5054baf8ce406e36401f27c3169205f4175504c4b1d98252d3f"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "console",
 | 
			
		||||
 "lazy_static",
 | 
			
		||||
 "linked-hash-map",
 | 
			
		||||
 "serde",
 | 
			
		||||
 "similar",
 | 
			
		||||
 "yaml-rust",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
@ -1843,7 +1859,7 @@ dependencies = [
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "kcl-lib"
 | 
			
		||||
version = "0.1.46"
 | 
			
		||||
version = "0.1.47"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "anyhow",
 | 
			
		||||
 "approx 0.5.1",
 | 
			
		||||
@ -1857,7 +1873,7 @@ dependencies = [
 | 
			
		||||
 "criterion",
 | 
			
		||||
 "dashmap",
 | 
			
		||||
 "databake",
 | 
			
		||||
 "derive-docs",
 | 
			
		||||
 "derive-docs 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
 "expectorate",
 | 
			
		||||
 "futures",
 | 
			
		||||
 "gltf-json",
 | 
			
		||||
@ -1944,8 +1960,9 @@ dependencies = [
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "kittycad-execution-plan"
 | 
			
		||||
version = "0.1.1"
 | 
			
		||||
source = "git+https://github.com/KittyCAD/modeling-api?branch=main#a3b8df282c684b3f7003ec96f5cea85284e0f1f9"
 | 
			
		||||
version = "0.1.3"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "e913f8e5f3ef7928cddca2e7b53c6582d7be6a8f900d18ce6c31c04083056270"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "bytes",
 | 
			
		||||
 "gltf-json",
 | 
			
		||||
@ -1967,7 +1984,8 @@ dependencies = [
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "kittycad-execution-plan-macros"
 | 
			
		||||
version = "0.1.9"
 | 
			
		||||
source = "git+https://github.com/KittyCAD/modeling-api?branch=main#a3b8df282c684b3f7003ec96f5cea85284e0f1f9"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "0611fc9b9786175da21d895ffa0f65039e19c9111e94a41b7af999e3b95f045f"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "proc-macro2",
 | 
			
		||||
 "quote",
 | 
			
		||||
@ -1977,7 +1995,8 @@ dependencies = [
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "kittycad-execution-plan-traits"
 | 
			
		||||
version = "0.1.15"
 | 
			
		||||
source = "git+https://github.com/KittyCAD/modeling-api?branch=main#a3b8df282c684b3f7003ec96f5cea85284e0f1f9"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "123cb47e2780ea8ef3aa67b4db237a27b388d3d3b96db457e274aa4565723151"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "serde",
 | 
			
		||||
 "thiserror",
 | 
			
		||||
@ -1986,8 +2005,9 @@ dependencies = [
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "kittycad-modeling-cmds"
 | 
			
		||||
version = "0.2.7"
 | 
			
		||||
source = "git+https://github.com/KittyCAD/modeling-api?branch=main#a3b8df282c684b3f7003ec96f5cea85284e0f1f9"
 | 
			
		||||
version = "0.2.10"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "b41beb7d9b776df93fd449604de5c447e33c7bd3326fd590002dc18cf5f08166"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "anyhow",
 | 
			
		||||
 "chrono",
 | 
			
		||||
@ -2015,7 +2035,8 @@ dependencies = [
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "kittycad-modeling-cmds-macros"
 | 
			
		||||
version = "0.1.5"
 | 
			
		||||
source = "git+https://github.com/KittyCAD/modeling-api?branch=main#a3b8df282c684b3f7003ec96f5cea85284e0f1f9"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "385775cc9d5bf25579f3029824ca1a6e7ab1b7c338e972ec8e8fcefff801f353"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "proc-macro2",
 | 
			
		||||
 "quote",
 | 
			
		||||
@ -2024,8 +2045,9 @@ dependencies = [
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "kittycad-modeling-session"
 | 
			
		||||
version = "0.1.1"
 | 
			
		||||
source = "git+https://github.com/KittyCAD/modeling-api?branch=main#a3b8df282c684b3f7003ec96f5cea85284e0f1f9"
 | 
			
		||||
version = "0.1.2"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "6ee3a24232a086ec12ae4cfee443485c22e6c6959936d861006fa13bebef0904"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "futures",
 | 
			
		||||
 "kittycad",
 | 
			
		||||
@ -3507,9 +3529,9 @@ dependencies = [
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "serde_json"
 | 
			
		||||
version = "1.0.114"
 | 
			
		||||
version = "1.0.115"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0"
 | 
			
		||||
checksum = "12dc5c46daa8e9fdf4f5e71b6cf9a53f2487da0e86e55808e2d35539666497dd"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "indexmap 2.2.5",
 | 
			
		||||
 "itoa",
 | 
			
		||||
 | 
			
		||||
@ -14,7 +14,7 @@ bson = { version = "2.9.0", features = ["uuid-1", "chrono"] }
 | 
			
		||||
gloo-utils = "0.2.0"
 | 
			
		||||
kcl-lib = { path = "kcl" }
 | 
			
		||||
kittycad = { workspace = true }
 | 
			
		||||
serde_json = "1.0.114"
 | 
			
		||||
serde_json = "1.0.115"
 | 
			
		||||
uuid = { version = "1.8.0", features = ["v4", "js", "serde"] }
 | 
			
		||||
wasm-bindgen = "0.2.91"
 | 
			
		||||
wasm-bindgen-futures = "0.4.42"
 | 
			
		||||
@ -60,11 +60,11 @@ members = [
 | 
			
		||||
 | 
			
		||||
[workspace.dependencies]
 | 
			
		||||
kittycad = { version = "0.2.63", default-features = false, features = ["js", "requests"] }
 | 
			
		||||
kittycad-execution-plan = { git = "https://github.com/KittyCAD/modeling-api", branch = "main" }
 | 
			
		||||
kittycad-execution-plan-macros = { git = "https://github.com/KittyCAD/modeling-api", branch = "main" }
 | 
			
		||||
kittycad-execution-plan-traits = { git = "https://github.com/KittyCAD/modeling-api", branch = "main" }
 | 
			
		||||
kittycad-modeling-cmds = { git = "https://github.com/KittyCAD/modeling-api", branch = "main" }
 | 
			
		||||
kittycad-modeling-session = { git = "https://github.com/KittyCAD/modeling-api", branch = "main" }
 | 
			
		||||
kittycad-execution-plan = "0.1.3"
 | 
			
		||||
kittycad-execution-plan-macros = "0.1.9"
 | 
			
		||||
kittycad-execution-plan-traits = "0.1.14"
 | 
			
		||||
kittycad-modeling-cmds = "0.2.10"
 | 
			
		||||
kittycad-modeling-session = "0.1.2"
 | 
			
		||||
 | 
			
		||||
[[test]]
 | 
			
		||||
name = "executor"
 | 
			
		||||
 | 
			
		||||
@ -21,4 +21,4 @@ uuid = "1.8"
 | 
			
		||||
 | 
			
		||||
[dev-dependencies]
 | 
			
		||||
pretty_assertions = "1"
 | 
			
		||||
serde_json = "1.0.114"
 | 
			
		||||
serde_json = "1.0.115"
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,7 @@
 | 
			
		||||
[package]
 | 
			
		||||
name = "kcl-lib"
 | 
			
		||||
description = "KittyCAD Language implementation and tools"
 | 
			
		||||
version = "0.1.46"
 | 
			
		||||
version = "0.1.47"
 | 
			
		||||
edition = "2021"
 | 
			
		||||
license = "MIT"
 | 
			
		||||
repository = "https://github.com/KittyCAD/modeling-app"
 | 
			
		||||
@ -13,13 +13,13 @@ keywords = ["kcl", "KittyCAD", "CAD"]
 | 
			
		||||
[dependencies]
 | 
			
		||||
anyhow = { version = "1.0.81", features = ["backtrace"] }
 | 
			
		||||
async-recursion = "1.1.0"
 | 
			
		||||
async-trait = "0.1.78"
 | 
			
		||||
chrono = "0.4.35"
 | 
			
		||||
clap = { version = "4.5.3", features = ["cargo", "derive", "env", "unicode"], optional = true }
 | 
			
		||||
async-trait = "0.1.79"
 | 
			
		||||
chrono = "0.4.37"
 | 
			
		||||
clap = { version = "4.5.4", features = ["cargo", "derive", "env", "unicode"], optional = true }
 | 
			
		||||
dashmap = "5.5.3"
 | 
			
		||||
databake = { version = "0.1.7", features = ["derive"] }
 | 
			
		||||
#derive-docs = { version = "0.1.12" }
 | 
			
		||||
derive-docs = { path = "../derive-docs" }
 | 
			
		||||
derive-docs = { version = "0.1.12" }
 | 
			
		||||
#derive-docs = { path = "../derive-docs" }
 | 
			
		||||
futures = { version = "0.3.30" }
 | 
			
		||||
gltf-json = "1.4.0"
 | 
			
		||||
kittycad = { workspace = true }
 | 
			
		||||
@ -32,7 +32,7 @@ reqwest = { version = "0.11.26", default-features = false, features = ["stream",
 | 
			
		||||
ropey = "1.6.1"
 | 
			
		||||
schemars = { version = "0.8.16", features = ["impl_json_schema", "url", "uuid1"] }
 | 
			
		||||
serde = { version = "1.0.197", features = ["derive"] }
 | 
			
		||||
serde_json = "1.0.114"
 | 
			
		||||
serde_json = "1.0.115"
 | 
			
		||||
sha2 = "0.10.8"
 | 
			
		||||
thiserror = "1.0.58"
 | 
			
		||||
ts-rs = { version = "7.1.1", features = ["uuid-impl"] }
 | 
			
		||||
@ -72,7 +72,7 @@ convert_case = "0.6.0"
 | 
			
		||||
criterion = "0.5.1"
 | 
			
		||||
expectorate = "1.1.0"
 | 
			
		||||
image = "0.24.9"
 | 
			
		||||
insta = { version = "1.36.1", features = ["json"] }
 | 
			
		||||
insta = { version = "1.37.0", features = ["json"] }
 | 
			
		||||
itertools = "0.12.1"
 | 
			
		||||
pretty_assertions = "1.4.0"
 | 
			
		||||
tokio = { version = "1.36.0", features = ["rt-multi-thread", "macros", "time"] }
 | 
			
		||||
 | 
			
		||||
@ -715,15 +715,9 @@ impl BinaryPart {
 | 
			
		||||
    pub async fn get_result(
 | 
			
		||||
        &self,
 | 
			
		||||
        memory: &mut ProgramMemory,
 | 
			
		||||
        pipe_info: &mut PipeInfo,
 | 
			
		||||
        pipe_info: &PipeInfo,
 | 
			
		||||
        ctx: &ExecutorContext,
 | 
			
		||||
    ) -> Result<MemoryItem, KclError> {
 | 
			
		||||
        // We DO NOT set this globally because if we did and this was called inside a pipe it would
 | 
			
		||||
        // stop the execution of the pipe.
 | 
			
		||||
        // THIS IS IMPORTANT.
 | 
			
		||||
        let mut new_pipe_info = pipe_info.clone();
 | 
			
		||||
        new_pipe_info.is_in_pipe = false;
 | 
			
		||||
 | 
			
		||||
        match self {
 | 
			
		||||
            BinaryPart::Literal(literal) => Ok(literal.into()),
 | 
			
		||||
            BinaryPart::Identifier(identifier) => {
 | 
			
		||||
@ -731,14 +725,10 @@ impl BinaryPart {
 | 
			
		||||
                Ok(value.clone())
 | 
			
		||||
            }
 | 
			
		||||
            BinaryPart::BinaryExpression(binary_expression) => {
 | 
			
		||||
                binary_expression.get_result(memory, &mut new_pipe_info, ctx).await
 | 
			
		||||
            }
 | 
			
		||||
            BinaryPart::CallExpression(call_expression) => {
 | 
			
		||||
                call_expression.execute(memory, &mut new_pipe_info, ctx).await
 | 
			
		||||
            }
 | 
			
		||||
            BinaryPart::UnaryExpression(unary_expression) => {
 | 
			
		||||
                unary_expression.get_result(memory, &mut new_pipe_info, ctx).await
 | 
			
		||||
                binary_expression.get_result(memory, pipe_info, ctx).await
 | 
			
		||||
            }
 | 
			
		||||
            BinaryPart::CallExpression(call_expression) => call_expression.execute(memory, pipe_info, ctx).await,
 | 
			
		||||
            BinaryPart::UnaryExpression(unary_expression) => unary_expression.get_result(memory, pipe_info, ctx).await,
 | 
			
		||||
            BinaryPart::MemberExpression(member_expression) => member_expression.get_result(memory),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@ -1019,7 +1009,7 @@ impl CallExpression {
 | 
			
		||||
    pub async fn execute(
 | 
			
		||||
        &self,
 | 
			
		||||
        memory: &mut ProgramMemory,
 | 
			
		||||
        pipe_info: &mut PipeInfo,
 | 
			
		||||
        pipe_info: &PipeInfo,
 | 
			
		||||
        ctx: &ExecutorContext,
 | 
			
		||||
    ) -> Result<MemoryItem, KclError> {
 | 
			
		||||
        let fn_name = self.callee.name.clone();
 | 
			
		||||
@ -1037,14 +1027,7 @@ impl CallExpression {
 | 
			
		||||
                Value::BinaryExpression(binary_expression) => {
 | 
			
		||||
                    binary_expression.get_result(memory, pipe_info, ctx).await?
 | 
			
		||||
                }
 | 
			
		||||
                Value::CallExpression(call_expression) => {
 | 
			
		||||
                    // We DO NOT set this globally because if we did and this was called inside a pipe it would
 | 
			
		||||
                    // stop the execution of the pipe.
 | 
			
		||||
                    // THIS IS IMPORTANT.
 | 
			
		||||
                    let mut new_pipe_info = pipe_info.clone();
 | 
			
		||||
                    new_pipe_info.is_in_pipe = false;
 | 
			
		||||
                    call_expression.execute(memory, &mut new_pipe_info, ctx).await?
 | 
			
		||||
                }
 | 
			
		||||
                Value::CallExpression(call_expression) => call_expression.execute(memory, pipe_info, ctx).await?,
 | 
			
		||||
                Value::UnaryExpression(unary_expression) => unary_expression.get_result(memory, pipe_info, ctx).await?,
 | 
			
		||||
                Value::ObjectExpression(object_expression) => object_expression.execute(memory, pipe_info, ctx).await?,
 | 
			
		||||
                Value::ArrayExpression(array_expression) => array_expression.execute(memory, pipe_info, ctx).await?,
 | 
			
		||||
@ -1056,7 +1039,7 @@ impl CallExpression {
 | 
			
		||||
                }
 | 
			
		||||
                Value::PipeSubstitution(pipe_substitution) => pipe_info
 | 
			
		||||
                    .previous_results
 | 
			
		||||
                    .get(&pipe_info.index - 1)
 | 
			
		||||
                    .as_ref()
 | 
			
		||||
                    .ok_or_else(|| {
 | 
			
		||||
                        KclError::Semantic(KclErrorDetails {
 | 
			
		||||
                            message: format!("PipeSubstitution index out of bounds: {:?}", pipe_info),
 | 
			
		||||
@ -1081,13 +1064,7 @@ impl CallExpression {
 | 
			
		||||
                // Attempt to call the function.
 | 
			
		||||
                let args = crate::std::Args::new(fn_args, self.into(), ctx.clone());
 | 
			
		||||
                let result = func.std_lib_fn()(args).await?;
 | 
			
		||||
                if pipe_info.is_in_pipe {
 | 
			
		||||
                    pipe_info.index += 1;
 | 
			
		||||
                    pipe_info.previous_results.push(result);
 | 
			
		||||
                    execute_pipe_body(memory, &pipe_info.body.clone(), pipe_info, self.into(), ctx).await
 | 
			
		||||
                } else {
 | 
			
		||||
                    Ok(result)
 | 
			
		||||
                }
 | 
			
		||||
                Ok(result)
 | 
			
		||||
            }
 | 
			
		||||
            FunctionKind::Std(func) => {
 | 
			
		||||
                let function_expression = func.function();
 | 
			
		||||
@ -1152,14 +1129,7 @@ impl CallExpression {
 | 
			
		||||
                })?;
 | 
			
		||||
                let result = result.get_value()?;
 | 
			
		||||
 | 
			
		||||
                if pipe_info.is_in_pipe {
 | 
			
		||||
                    pipe_info.index += 1;
 | 
			
		||||
                    pipe_info.previous_results.push(result);
 | 
			
		||||
 | 
			
		||||
                    execute_pipe_body(memory, &pipe_info.body.clone(), pipe_info, self.into(), ctx).await
 | 
			
		||||
                } else {
 | 
			
		||||
                    Ok(result)
 | 
			
		||||
                }
 | 
			
		||||
                Ok(result)
 | 
			
		||||
            }
 | 
			
		||||
            FunctionKind::UserDefined => {
 | 
			
		||||
                let func = memory.get(&fn_name, self.into())?;
 | 
			
		||||
@ -1175,14 +1145,7 @@ impl CallExpression {
 | 
			
		||||
 | 
			
		||||
                let result = result.get_value()?;
 | 
			
		||||
 | 
			
		||||
                if pipe_info.is_in_pipe {
 | 
			
		||||
                    pipe_info.index += 1;
 | 
			
		||||
                    pipe_info.previous_results.push(result);
 | 
			
		||||
 | 
			
		||||
                    execute_pipe_body(memory, &pipe_info.body.clone(), pipe_info, self.into(), ctx).await
 | 
			
		||||
                } else {
 | 
			
		||||
                    Ok(result)
 | 
			
		||||
                }
 | 
			
		||||
                Ok(result)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@ -1731,7 +1694,7 @@ impl ArrayExpression {
 | 
			
		||||
    pub async fn execute(
 | 
			
		||||
        &self,
 | 
			
		||||
        memory: &mut ProgramMemory,
 | 
			
		||||
        pipe_info: &mut PipeInfo,
 | 
			
		||||
        pipe_info: &PipeInfo,
 | 
			
		||||
        ctx: &ExecutorContext,
 | 
			
		||||
    ) -> Result<MemoryItem, KclError> {
 | 
			
		||||
        let mut results = Vec::with_capacity(self.elements.len());
 | 
			
		||||
@ -1747,14 +1710,7 @@ impl ArrayExpression {
 | 
			
		||||
                Value::BinaryExpression(binary_expression) => {
 | 
			
		||||
                    binary_expression.get_result(memory, pipe_info, ctx).await?
 | 
			
		||||
                }
 | 
			
		||||
                Value::CallExpression(call_expression) => {
 | 
			
		||||
                    // We DO NOT set this globally because if we did and this was called inside a pipe it would
 | 
			
		||||
                    // stop the execution of the pipe.
 | 
			
		||||
                    // THIS IS IMPORTANT.
 | 
			
		||||
                    let mut new_pipe_info = pipe_info.clone();
 | 
			
		||||
                    new_pipe_info.is_in_pipe = false;
 | 
			
		||||
                    call_expression.execute(memory, &mut new_pipe_info, ctx).await?
 | 
			
		||||
                }
 | 
			
		||||
                Value::CallExpression(call_expression) => call_expression.execute(memory, pipe_info, ctx).await?,
 | 
			
		||||
                Value::UnaryExpression(unary_expression) => unary_expression.get_result(memory, pipe_info, ctx).await?,
 | 
			
		||||
                Value::ObjectExpression(object_expression) => object_expression.execute(memory, pipe_info, ctx).await?,
 | 
			
		||||
                Value::ArrayExpression(array_expression) => array_expression.execute(memory, pipe_info, ctx).await?,
 | 
			
		||||
@ -1885,7 +1841,7 @@ impl ObjectExpression {
 | 
			
		||||
    pub async fn execute(
 | 
			
		||||
        &self,
 | 
			
		||||
        memory: &mut ProgramMemory,
 | 
			
		||||
        pipe_info: &mut PipeInfo,
 | 
			
		||||
        pipe_info: &PipeInfo,
 | 
			
		||||
        ctx: &ExecutorContext,
 | 
			
		||||
    ) -> Result<MemoryItem, KclError> {
 | 
			
		||||
        let mut object = Map::new();
 | 
			
		||||
@ -1900,14 +1856,7 @@ impl ObjectExpression {
 | 
			
		||||
                Value::BinaryExpression(binary_expression) => {
 | 
			
		||||
                    binary_expression.get_result(memory, pipe_info, ctx).await?
 | 
			
		||||
                }
 | 
			
		||||
                Value::CallExpression(call_expression) => {
 | 
			
		||||
                    // We DO NOT set this globally because if we did and this was called inside a pipe it would
 | 
			
		||||
                    // stop the execution of the pipe.
 | 
			
		||||
                    // THIS IS IMPORTANT.
 | 
			
		||||
                    let mut new_pipe_info = pipe_info.clone();
 | 
			
		||||
                    new_pipe_info.is_in_pipe = false;
 | 
			
		||||
                    call_expression.execute(memory, &mut new_pipe_info, ctx).await?
 | 
			
		||||
                }
 | 
			
		||||
                Value::CallExpression(call_expression) => call_expression.execute(memory, pipe_info, ctx).await?,
 | 
			
		||||
                Value::UnaryExpression(unary_expression) => unary_expression.get_result(memory, pipe_info, ctx).await?,
 | 
			
		||||
                Value::ObjectExpression(object_expression) => object_expression.execute(memory, pipe_info, ctx).await?,
 | 
			
		||||
                Value::ArrayExpression(array_expression) => array_expression.execute(memory, pipe_info, ctx).await?,
 | 
			
		||||
@ -2338,25 +2287,11 @@ impl BinaryExpression {
 | 
			
		||||
    pub async fn get_result(
 | 
			
		||||
        &self,
 | 
			
		||||
        memory: &mut ProgramMemory,
 | 
			
		||||
        pipe_info: &mut PipeInfo,
 | 
			
		||||
        pipe_info: &PipeInfo,
 | 
			
		||||
        ctx: &ExecutorContext,
 | 
			
		||||
    ) -> Result<MemoryItem, KclError> {
 | 
			
		||||
        // We DO NOT set this globally because if we did and this was called inside a pipe it would
 | 
			
		||||
        // stop the execution of the pipe.
 | 
			
		||||
        // THIS IS IMPORTANT.
 | 
			
		||||
        let mut new_pipe_info = pipe_info.clone();
 | 
			
		||||
        new_pipe_info.is_in_pipe = false;
 | 
			
		||||
 | 
			
		||||
        let left_json_value = self
 | 
			
		||||
            .left
 | 
			
		||||
            .get_result(memory, &mut new_pipe_info, ctx)
 | 
			
		||||
            .await?
 | 
			
		||||
            .get_json_value()?;
 | 
			
		||||
        let right_json_value = self
 | 
			
		||||
            .right
 | 
			
		||||
            .get_result(memory, &mut new_pipe_info, ctx)
 | 
			
		||||
            .await?
 | 
			
		||||
            .get_json_value()?;
 | 
			
		||||
        let left_json_value = self.left.get_result(memory, pipe_info, ctx).await?.get_json_value()?;
 | 
			
		||||
        let right_json_value = self.right.get_result(memory, pipe_info, ctx).await?.get_json_value()?;
 | 
			
		||||
 | 
			
		||||
        // First check if we are doing string concatenation.
 | 
			
		||||
        if self.operator == BinaryOperator::Add {
 | 
			
		||||
@ -2542,19 +2477,13 @@ impl UnaryExpression {
 | 
			
		||||
    pub async fn get_result(
 | 
			
		||||
        &self,
 | 
			
		||||
        memory: &mut ProgramMemory,
 | 
			
		||||
        pipe_info: &mut PipeInfo,
 | 
			
		||||
        pipe_info: &PipeInfo,
 | 
			
		||||
        ctx: &ExecutorContext,
 | 
			
		||||
    ) -> Result<MemoryItem, KclError> {
 | 
			
		||||
        // We DO NOT set this globally because if we did and this was called inside a pipe it would
 | 
			
		||||
        // stop the execution of the pipe.
 | 
			
		||||
        // THIS IS IMPORTANT.
 | 
			
		||||
        let mut new_pipe_info = pipe_info.clone();
 | 
			
		||||
        new_pipe_info.is_in_pipe = false;
 | 
			
		||||
 | 
			
		||||
        let num = parse_json_number_as_f64(
 | 
			
		||||
            &self
 | 
			
		||||
                .argument
 | 
			
		||||
                .get_result(memory, &mut new_pipe_info, ctx)
 | 
			
		||||
                .get_result(memory, pipe_info, ctx)
 | 
			
		||||
                .await?
 | 
			
		||||
                .get_json_value()?,
 | 
			
		||||
            self.into(),
 | 
			
		||||
@ -2606,6 +2535,8 @@ pub enum UnaryOperator {
 | 
			
		||||
pub struct PipeExpression {
 | 
			
		||||
    pub start: usize,
 | 
			
		||||
    pub end: usize,
 | 
			
		||||
    // TODO: Only the first body expression can be any Value.
 | 
			
		||||
    // The rest will be CallExpression, and the AST type should reflect this.
 | 
			
		||||
    pub body: Vec<Value>,
 | 
			
		||||
    pub non_code_meta: NonCodeMeta,
 | 
			
		||||
}
 | 
			
		||||
@ -2696,12 +2627,9 @@ impl PipeExpression {
 | 
			
		||||
    pub async fn get_result(
 | 
			
		||||
        &self,
 | 
			
		||||
        memory: &mut ProgramMemory,
 | 
			
		||||
        pipe_info: &mut PipeInfo,
 | 
			
		||||
        pipe_info: &PipeInfo,
 | 
			
		||||
        ctx: &ExecutorContext,
 | 
			
		||||
    ) -> Result<MemoryItem, KclError> {
 | 
			
		||||
        // Reset the previous results.
 | 
			
		||||
        pipe_info.previous_results = vec![];
 | 
			
		||||
        pipe_info.index = 0;
 | 
			
		||||
        execute_pipe_body(memory, &self.body, pipe_info, self.into(), ctx).await
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -2717,57 +2645,59 @@ impl PipeExpression {
 | 
			
		||||
async fn execute_pipe_body(
 | 
			
		||||
    memory: &mut ProgramMemory,
 | 
			
		||||
    body: &[Value],
 | 
			
		||||
    pipe_info: &mut PipeInfo,
 | 
			
		||||
    pipe_info: &PipeInfo,
 | 
			
		||||
    source_range: SourceRange,
 | 
			
		||||
    ctx: &ExecutorContext,
 | 
			
		||||
) -> Result<MemoryItem, KclError> {
 | 
			
		||||
    if pipe_info.index == body.len() {
 | 
			
		||||
        pipe_info.is_in_pipe = false;
 | 
			
		||||
        return Ok(pipe_info
 | 
			
		||||
            .previous_results
 | 
			
		||||
            .last()
 | 
			
		||||
            .ok_or_else(|| {
 | 
			
		||||
                KclError::Semantic(KclErrorDetails {
 | 
			
		||||
                    message: "Pipe body results should have at least one expression".to_string(),
 | 
			
		||||
                    source_ranges: vec![source_range],
 | 
			
		||||
                })
 | 
			
		||||
            })?
 | 
			
		||||
            .clone());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let expression = body.get(pipe_info.index).ok_or_else(|| {
 | 
			
		||||
    let mut body_iter = body.iter();
 | 
			
		||||
    let first = body_iter.next().ok_or_else(|| {
 | 
			
		||||
        KclError::Semantic(KclErrorDetails {
 | 
			
		||||
            message: format!("Invalid index for pipe: {}", pipe_info.index),
 | 
			
		||||
            message: "Pipe expressions cannot be empty".to_owned(),
 | 
			
		||||
            source_ranges: vec![source_range],
 | 
			
		||||
        })
 | 
			
		||||
    })?;
 | 
			
		||||
 | 
			
		||||
    match expression {
 | 
			
		||||
        Value::BinaryExpression(binary_expression) => {
 | 
			
		||||
            let result = binary_expression.get_result(memory, pipe_info, ctx).await?;
 | 
			
		||||
            pipe_info.previous_results.push(result);
 | 
			
		||||
            pipe_info.index += 1;
 | 
			
		||||
            execute_pipe_body(memory, body, pipe_info, source_range, ctx).await
 | 
			
		||||
        }
 | 
			
		||||
        Value::CallExpression(call_expression) => {
 | 
			
		||||
            pipe_info.is_in_pipe = true;
 | 
			
		||||
            pipe_info.body = body.to_vec();
 | 
			
		||||
            call_expression.execute(memory, pipe_info, ctx).await
 | 
			
		||||
        }
 | 
			
		||||
        Value::Identifier(identifier) => {
 | 
			
		||||
            let result = memory.get(&identifier.name, identifier.into())?;
 | 
			
		||||
            pipe_info.previous_results.push(result.clone());
 | 
			
		||||
            pipe_info.index += 1;
 | 
			
		||||
            execute_pipe_body(memory, body, pipe_info, source_range, ctx).await
 | 
			
		||||
        }
 | 
			
		||||
    // Evaluate the first element in the pipeline.
 | 
			
		||||
    // They use the `pipe_info` from some AST node above this, so that if pipe expression is nested in a larger pipe expression,
 | 
			
		||||
    // they use the % from the parent. After all, this pipe expression hasn't been executed yet, so it doesn't have any % value
 | 
			
		||||
    // of its own.
 | 
			
		||||
    let output = match first {
 | 
			
		||||
        Value::BinaryExpression(binary_expression) => binary_expression.get_result(memory, pipe_info, ctx).await?,
 | 
			
		||||
        Value::CallExpression(call_expression) => call_expression.execute(memory, pipe_info, ctx).await?,
 | 
			
		||||
        Value::Identifier(identifier) => memory.get(&identifier.name, identifier.into())?.clone(),
 | 
			
		||||
        _ => {
 | 
			
		||||
            // Return an error this should not happen.
 | 
			
		||||
            Err(KclError::Semantic(KclErrorDetails {
 | 
			
		||||
                message: format!("PipeExpression not implemented here: {:?}", expression),
 | 
			
		||||
                source_ranges: vec![expression.into()],
 | 
			
		||||
            }))
 | 
			
		||||
            return Err(KclError::Semantic(KclErrorDetails {
 | 
			
		||||
                message: format!("PipeExpression not implemented here: {:?}", first),
 | 
			
		||||
                source_ranges: vec![first.into()],
 | 
			
		||||
            }));
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
    // Now that we've evaluated the first child expression in the pipeline, following child expressions
 | 
			
		||||
    // should use the previous child expression for %.
 | 
			
		||||
    // This means there's no more need for the previous `pipe_info` from the parent AST node above this one.
 | 
			
		||||
    let mut new_pipe_info = PipeInfo::new();
 | 
			
		||||
    new_pipe_info.previous_results = Some(output);
 | 
			
		||||
    // Evaluate remaining elements.
 | 
			
		||||
    for expression in body {
 | 
			
		||||
        let output = match expression {
 | 
			
		||||
            Value::BinaryExpression(binary_expression) => {
 | 
			
		||||
                binary_expression.get_result(memory, &new_pipe_info, ctx).await?
 | 
			
		||||
            }
 | 
			
		||||
            Value::CallExpression(call_expression) => call_expression.execute(memory, &new_pipe_info, ctx).await?,
 | 
			
		||||
            Value::Identifier(identifier) => memory.get(&identifier.name, identifier.into())?.clone(),
 | 
			
		||||
            _ => {
 | 
			
		||||
                // Return an error this should not happen.
 | 
			
		||||
                return Err(KclError::Semantic(KclErrorDetails {
 | 
			
		||||
                    message: format!("PipeExpression not implemented here: {:?}", expression),
 | 
			
		||||
                    source_ranges: vec![expression.into()],
 | 
			
		||||
                }));
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
        new_pipe_info.previous_results = Some(output);
 | 
			
		||||
    }
 | 
			
		||||
    // Safe to unwrap here, because `newpipe_info` always has something pushed in when the `match first` executes.
 | 
			
		||||
    let final_output = new_pipe_info.previous_results.unwrap();
 | 
			
		||||
    Ok(final_output)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq, JsonSchema, Bake, FromStr, Display)]
 | 
			
		||||
 | 
			
		||||
@ -953,20 +953,12 @@ impl ExtrudeSurface {
 | 
			
		||||
#[ts(export)]
 | 
			
		||||
#[serde(rename_all = "camelCase")]
 | 
			
		||||
pub struct PipeInfo {
 | 
			
		||||
    pub previous_results: Vec<MemoryItem>,
 | 
			
		||||
    pub is_in_pipe: bool,
 | 
			
		||||
    pub index: usize,
 | 
			
		||||
    pub body: Vec<Value>,
 | 
			
		||||
    pub previous_results: Option<MemoryItem>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl PipeInfo {
 | 
			
		||||
    pub fn new() -> Self {
 | 
			
		||||
        Self {
 | 
			
		||||
            previous_results: Vec::new(),
 | 
			
		||||
            is_in_pipe: false,
 | 
			
		||||
            index: 0,
 | 
			
		||||
            body: Vec::new(),
 | 
			
		||||
        }
 | 
			
		||||
        Self { previous_results: None }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1022,14 +1014,14 @@ pub async fn execute(
 | 
			
		||||
        )
 | 
			
		||||
        .await?;
 | 
			
		||||
 | 
			
		||||
    let mut pipe_info = PipeInfo::default();
 | 
			
		||||
    let pipe_info = PipeInfo::default();
 | 
			
		||||
 | 
			
		||||
    // Iterate over the body of the program.
 | 
			
		||||
    for statement in &program.body {
 | 
			
		||||
        match statement {
 | 
			
		||||
            BodyItem::ExpressionStatement(expression_statement) => {
 | 
			
		||||
                if let Value::PipeExpression(pipe_expr) = &expression_statement.expression {
 | 
			
		||||
                    pipe_expr.get_result(memory, &mut pipe_info, ctx).await?;
 | 
			
		||||
                    pipe_expr.get_result(memory, &pipe_info, ctx).await?;
 | 
			
		||||
                } else if let Value::CallExpression(call_expr) = &expression_statement.expression {
 | 
			
		||||
                    let fn_name = call_expr.callee.name.to_string();
 | 
			
		||||
                    let mut args: Vec<MemoryItem> = Vec::new();
 | 
			
		||||
@ -1041,23 +1033,23 @@ pub async fn execute(
 | 
			
		||||
                                args.push(memory_item.clone());
 | 
			
		||||
                            }
 | 
			
		||||
                            Value::CallExpression(call_expr) => {
 | 
			
		||||
                                let result = call_expr.execute(memory, &mut pipe_info, ctx).await?;
 | 
			
		||||
                                let result = call_expr.execute(memory, &pipe_info, ctx).await?;
 | 
			
		||||
                                args.push(result);
 | 
			
		||||
                            }
 | 
			
		||||
                            Value::BinaryExpression(binary_expression) => {
 | 
			
		||||
                                let result = binary_expression.get_result(memory, &mut pipe_info, ctx).await?;
 | 
			
		||||
                                let result = binary_expression.get_result(memory, &pipe_info, ctx).await?;
 | 
			
		||||
                                args.push(result);
 | 
			
		||||
                            }
 | 
			
		||||
                            Value::UnaryExpression(unary_expression) => {
 | 
			
		||||
                                let result = unary_expression.get_result(memory, &mut pipe_info, ctx).await?;
 | 
			
		||||
                                let result = unary_expression.get_result(memory, &pipe_info, ctx).await?;
 | 
			
		||||
                                args.push(result);
 | 
			
		||||
                            }
 | 
			
		||||
                            Value::ObjectExpression(object_expression) => {
 | 
			
		||||
                                let result = object_expression.execute(memory, &mut pipe_info, ctx).await?;
 | 
			
		||||
                                let result = object_expression.execute(memory, &pipe_info, ctx).await?;
 | 
			
		||||
                                args.push(result);
 | 
			
		||||
                            }
 | 
			
		||||
                            Value::ArrayExpression(array_expression) => {
 | 
			
		||||
                                let result = array_expression.execute(memory, &mut pipe_info, ctx).await?;
 | 
			
		||||
                                let result = array_expression.execute(memory, &pipe_info, ctx).await?;
 | 
			
		||||
                                args.push(result);
 | 
			
		||||
                            }
 | 
			
		||||
                            // We do nothing for the rest.
 | 
			
		||||
@ -1108,7 +1100,7 @@ pub async fn execute(
 | 
			
		||||
                            memory.add(&var_name, value.clone(), source_range)?;
 | 
			
		||||
                        }
 | 
			
		||||
                        Value::BinaryExpression(binary_expression) => {
 | 
			
		||||
                            let result = binary_expression.get_result(memory, &mut pipe_info, ctx).await?;
 | 
			
		||||
                            let result = binary_expression.get_result(memory, &pipe_info, ctx).await?;
 | 
			
		||||
                            memory.add(&var_name, result, source_range)?;
 | 
			
		||||
                        }
 | 
			
		||||
                        Value::FunctionExpression(function_expression) => {
 | 
			
		||||
@ -1145,11 +1137,11 @@ pub async fn execute(
 | 
			
		||||
                            )?;
 | 
			
		||||
                        }
 | 
			
		||||
                        Value::CallExpression(call_expression) => {
 | 
			
		||||
                            let result = call_expression.execute(memory, &mut pipe_info, ctx).await?;
 | 
			
		||||
                            let result = call_expression.execute(memory, &pipe_info, ctx).await?;
 | 
			
		||||
                            memory.add(&var_name, result, source_range)?;
 | 
			
		||||
                        }
 | 
			
		||||
                        Value::PipeExpression(pipe_expression) => {
 | 
			
		||||
                            let result = pipe_expression.get_result(memory, &mut pipe_info, ctx).await?;
 | 
			
		||||
                            let result = pipe_expression.get_result(memory, &pipe_info, ctx).await?;
 | 
			
		||||
                            memory.add(&var_name, result, source_range)?;
 | 
			
		||||
                        }
 | 
			
		||||
                        Value::PipeSubstitution(pipe_substitution) => {
 | 
			
		||||
@ -1162,11 +1154,11 @@ pub async fn execute(
 | 
			
		||||
                            }));
 | 
			
		||||
                        }
 | 
			
		||||
                        Value::ArrayExpression(array_expression) => {
 | 
			
		||||
                            let result = array_expression.execute(memory, &mut pipe_info, ctx).await?;
 | 
			
		||||
                            let result = array_expression.execute(memory, &pipe_info, ctx).await?;
 | 
			
		||||
                            memory.add(&var_name, result, source_range)?;
 | 
			
		||||
                        }
 | 
			
		||||
                        Value::ObjectExpression(object_expression) => {
 | 
			
		||||
                            let result = object_expression.execute(memory, &mut pipe_info, ctx).await?;
 | 
			
		||||
                            let result = object_expression.execute(memory, &pipe_info, ctx).await?;
 | 
			
		||||
                            memory.add(&var_name, result, source_range)?;
 | 
			
		||||
                        }
 | 
			
		||||
                        Value::MemberExpression(member_expression) => {
 | 
			
		||||
@ -1174,7 +1166,7 @@ pub async fn execute(
 | 
			
		||||
                            memory.add(&var_name, result, source_range)?;
 | 
			
		||||
                        }
 | 
			
		||||
                        Value::UnaryExpression(unary_expression) => {
 | 
			
		||||
                            let result = unary_expression.get_result(memory, &mut pipe_info, ctx).await?;
 | 
			
		||||
                            let result = unary_expression.get_result(memory, &pipe_info, ctx).await?;
 | 
			
		||||
                            memory.add(&var_name, result, source_range)?;
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
@ -1182,11 +1174,11 @@ pub async fn execute(
 | 
			
		||||
            }
 | 
			
		||||
            BodyItem::ReturnStatement(return_statement) => match &return_statement.argument {
 | 
			
		||||
                Value::BinaryExpression(bin_expr) => {
 | 
			
		||||
                    let result = bin_expr.get_result(memory, &mut pipe_info, ctx).await?;
 | 
			
		||||
                    let result = bin_expr.get_result(memory, &pipe_info, ctx).await?;
 | 
			
		||||
                    memory.return_ = Some(ProgramReturn::Value(result));
 | 
			
		||||
                }
 | 
			
		||||
                Value::UnaryExpression(unary_expr) => {
 | 
			
		||||
                    let result = unary_expr.get_result(memory, &mut pipe_info, ctx).await?;
 | 
			
		||||
                    let result = unary_expr.get_result(memory, &pipe_info, ctx).await?;
 | 
			
		||||
                    memory.return_ = Some(ProgramReturn::Value(result));
 | 
			
		||||
                }
 | 
			
		||||
                Value::Identifier(identifier) => {
 | 
			
		||||
@ -1197,15 +1189,15 @@ pub async fn execute(
 | 
			
		||||
                    memory.return_ = Some(ProgramReturn::Value(literal.into()));
 | 
			
		||||
                }
 | 
			
		||||
                Value::ArrayExpression(array_expr) => {
 | 
			
		||||
                    let result = array_expr.execute(memory, &mut pipe_info, ctx).await?;
 | 
			
		||||
                    let result = array_expr.execute(memory, &pipe_info, ctx).await?;
 | 
			
		||||
                    memory.return_ = Some(ProgramReturn::Value(result));
 | 
			
		||||
                }
 | 
			
		||||
                Value::ObjectExpression(obj_expr) => {
 | 
			
		||||
                    let result = obj_expr.execute(memory, &mut pipe_info, ctx).await?;
 | 
			
		||||
                    let result = obj_expr.execute(memory, &pipe_info, ctx).await?;
 | 
			
		||||
                    memory.return_ = Some(ProgramReturn::Value(result));
 | 
			
		||||
                }
 | 
			
		||||
                Value::CallExpression(call_expr) => {
 | 
			
		||||
                    let result = call_expr.execute(memory, &mut pipe_info, ctx).await?;
 | 
			
		||||
                    let result = call_expr.execute(memory, &pipe_info, ctx).await?;
 | 
			
		||||
                    memory.return_ = Some(ProgramReturn::Value(result));
 | 
			
		||||
                }
 | 
			
		||||
                Value::MemberExpression(member_expr) => {
 | 
			
		||||
@ -1213,7 +1205,7 @@ pub async fn execute(
 | 
			
		||||
                    memory.return_ = Some(ProgramReturn::Value(result));
 | 
			
		||||
                }
 | 
			
		||||
                Value::PipeExpression(pipe_expr) => {
 | 
			
		||||
                    let result = pipe_expr.get_result(memory, &mut pipe_info, ctx).await?;
 | 
			
		||||
                    let result = pipe_expr.get_result(memory, &pipe_info, ctx).await?;
 | 
			
		||||
                    memory.return_ = Some(ProgramReturn::Value(result));
 | 
			
		||||
                }
 | 
			
		||||
                Value::PipeSubstitution(_) => {}
 | 
			
		||||
 | 
			
		||||
@ -142,6 +142,15 @@ const part002 = startSketchOn(part001, "start")
 | 
			
		||||
    twenty_twenty::assert_image("tests/executor/outputs/sketch_on_face_start.png", &result, 0.999);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[tokio::test(flavor = "multi_thread")]
 | 
			
		||||
async fn serial_test_mike_stress_lines() {
 | 
			
		||||
    let code = include_str!("inputs/mike_stress_test.kcl");
 | 
			
		||||
    let result = execute_and_snapshot(code, kittycad::types::UnitLength::Mm)
 | 
			
		||||
        .await
 | 
			
		||||
        .unwrap();
 | 
			
		||||
    twenty_twenty::assert_image("tests/executor/outputs/mike_stress_test.png", &result, 0.999);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[tokio::test(flavor = "multi_thread")]
 | 
			
		||||
async fn serial_test_sketch_on_face_end() {
 | 
			
		||||
    let code = r#"fn cube = (pos, scale) => {
 | 
			
		||||
@ -493,7 +502,7 @@ async fn serial_test_execute_i_shape() {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[tokio::test(flavor = "multi_thread")]
 | 
			
		||||
#[ignore] // ignore until more stack fixes
 | 
			
		||||
#[ignore] // No longer a stack overflow problem, instead it causes an engine internal error.
 | 
			
		||||
async fn serial_test_execute_pipes_on_pipes() {
 | 
			
		||||
    let code = include_str!("inputs/pipes_on_pipes.kcl");
 | 
			
		||||
 | 
			
		||||
@ -514,7 +523,6 @@ async fn serial_test_execute_cylinder() {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[tokio::test(flavor = "multi_thread")]
 | 
			
		||||
#[ignore = "currently stack overflows"]
 | 
			
		||||
async fn serial_test_execute_kittycad_svg() {
 | 
			
		||||
    let code = include_str!("inputs/kittycad_svg.kcl");
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
		 Before Width: | Height: | Size: 125 KiB After Width: | Height: | Size: 125 KiB  | 
| 
		 Before Width: | Height: | Size: 90 KiB After Width: | Height: | Size: 107 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								src/wasm-lib/tests/executor/outputs/mike_stress_test.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 122 KiB  | 
| 
		 Before Width: | Height: | Size: 95 KiB After Width: | Height: | Size: 95 KiB  | 
| 
		 Before Width: | Height: | Size: 100 KiB After Width: | Height: | Size: 100 KiB  | 
| 
		 Before Width: | Height: | Size: 114 KiB After Width: | Height: | Size: 114 KiB  | 
| 
		 Before Width: | Height: | Size: 114 KiB After Width: | Height: | Size: 114 KiB  | 
| 
		 Before Width: | Height: | Size: 111 KiB After Width: | Height: | Size: 111 KiB  | 
| 
		 Before Width: | Height: | Size: 109 KiB After Width: | Height: | Size: 110 KiB  | 
| 
		 Before Width: | Height: | Size: 111 KiB After Width: | Height: | Size: 112 KiB  | 
| 
		 Before Width: | Height: | Size: 112 KiB After Width: | Height: | Size: 112 KiB  | 
| 
		 Before Width: | Height: | Size: 95 KiB After Width: | Height: | Size: 95 KiB  | 
| 
		 Before Width: | Height: | Size: 95 KiB After Width: | Height: | Size: 95 KiB  | 
| 
		 Before Width: | Height: | Size: 95 KiB After Width: | Height: | Size: 95 KiB  | 
							
								
								
									
										14
									
								
								yarn.lock
									
									
									
									
									
								
							
							
						
						@ -2506,20 +2506,14 @@
 | 
			
		||||
  dependencies:
 | 
			
		||||
    "@types/react" "*"
 | 
			
		||||
 | 
			
		||||
"@types/react@*", "@types/react@^18.2.67":
 | 
			
		||||
  version "18.2.67"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.67.tgz#96b7af0b5e79c756f4bdd981de2ca28472c858e5"
 | 
			
		||||
  integrity sha512-vkIE2vTIMHQ/xL0rgmuoECBCkZFZeHr49HeWSc24AptMbNRo7pwSBvj73rlJJs9fGKj0koS+V7kQB1jHS0uCgw==
 | 
			
		||||
"@types/react@*", "@types/react@^18.2.73":
 | 
			
		||||
  version "18.2.73"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.73.tgz#0579548ad122660d99e00499d22e33b81e73ed94"
 | 
			
		||||
  integrity sha512-XcGdod0Jjv84HOC7N5ziY3x+qL0AfmubvKOZ9hJjJ2yd5EE+KYjWhdOjt387e9HPheHkdggF9atTifMRtyAaRA==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    "@types/prop-types" "*"
 | 
			
		||||
    "@types/scheduler" "*"
 | 
			
		||||
    csstype "^3.0.2"
 | 
			
		||||
 | 
			
		||||
"@types/scheduler@*":
 | 
			
		||||
  version "0.16.3"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.3.tgz#cef09e3ec9af1d63d2a6cc5b383a737e24e6dcf5"
 | 
			
		||||
  integrity sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==
 | 
			
		||||
 | 
			
		||||
"@types/semver@^7.3.12":
 | 
			
		||||
  version "7.5.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.0.tgz#591c1ce3a702c45ee15f47a42ade72c2fd78978a"
 | 
			
		||||
 | 
			
		||||