parallelized modules from kcl (#6206)

* wip

* sketch a bit more; going to pull this out of tests next

* wip

* lock start things

* this was a bad idea

* Revert "this was a bad idea"

This reverts commit a2092e7ed6.

* prepare prelude before spawning

* error

* poop

* yike

* :(

* ok

* Reapply "this was a bad idea"

This reverts commit fafdf41093.

* chip away more

* man this is bad

* fix rebase add feature flag

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* get rid of execution kind

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* clippy

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* logs

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* updates

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* no extra executes

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* race w batch

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* cluppy

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* no printlns

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* no printlns

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* fix source ranges

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* batch shit

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* fixes

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* updates

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* fix

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* fix some bugs

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* fix error

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* cut 1

* preserve mem

* re-ad deep_clone

the helper we were calling was pushing a new call, which was hanging
out. we can skip the middleman since we already have something properly
prepared, just without a stdlib in some cases.

* skip non-kcl

* clean up source range bug

* error message changed

the uuids also changed because the error is hit before execute even
starts.

* typo

* rensnapshot a few

* order things

* MAYBE REVERT LATER:

attempt at an ordering

* snapsnap

* Revert "snapsnap"

This reverts commit 7350b32c7d.

* Revert "MAYBE REVERT LATER:"

This reverts commit ab49f3e85f.

* ugh

* poop

* poop2

* lint

* tranche 1

* more

* more snaps

* snap

* more

* update

* MAYBE REVERT THIS

* cache multi-file

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* addd tests

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* set to false

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* add test outputs

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* clippy

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* kcl-py-bindings uses carwheel

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* update snapshots

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* updates

Signed-off-by: Jess Frazelle <github@jessfraz.com>

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
Co-authored-by: Paul R. Tagliamonte <paul@zoo.dev>
Co-authored-by: Paul Tagliamonte <paultag@gmail.com>
This commit is contained in:
Jess Frazelle
2025-04-16 11:52:14 -07:00
committed by GitHub
parent 5586646a60
commit d9fe78171f
195 changed files with 15585 additions and 8887 deletions

File diff suppressed because one or more lines are too long

View File

@ -67,6 +67,7 @@
PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH = "${pkgs.playwright-driver.browsers}/chromium-1091/chrome-linux/chrome";
PLAYWRIGHT_BROWSERS_PATH = "${pkgs.playwright-driver.browsers}";
NODE_ENV = "development";
RUSTFMT = "${pkgs.rust-bin.stable.latest.rustfmt}/bin/rustfmt";
};
});

20
rust/Cargo.lock generated
View File

@ -1907,6 +1907,7 @@ dependencies = [
"serde_json",
"sha2",
"tabled",
"tempdir",
"thiserror 2.0.12",
"tokio",
"tokio-tungstenite",
@ -3084,6 +3085,15 @@ version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
[[package]]
name = "remove_dir_all"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
dependencies = [
"winapi",
]
[[package]]
name = "reqwest"
version = "0.12.15"
@ -3779,6 +3789,16 @@ version = "0.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e502f78cdbb8ba4718f566c418c52bc729126ffd16baee5baa718cf25dd5a69a"
[[package]]
name = "tempdir"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8"
dependencies = [
"rand 0.4.6",
"remove_dir_all",
]
[[package]]
name = "tempfile"
version = "3.19.0"

View File

@ -22,7 +22,6 @@ debug = 0
[profile.dev.package]
insta = { opt-level = 3 }
similar = { opt-level = 3 }
[profile.test]
debug = "line-tables-only"

View File

@ -69,6 +69,7 @@ serde = { workspace = true }
serde_json = { workspace = true }
sha2 = "0.10.8"
tabled = { version = "0.18.0", optional = true }
tempdir = "0.3.7"
thiserror = "2.0.0"
toml = "0.8.19"
ts-rs = { version = "10.1.0", features = [

View File

@ -7,6 +7,7 @@ use kittycad_modeling_cmds as kcmc;
#[derive(Debug)]
struct Variation<'a> {
code: &'a str,
other_files: Vec<(std::path::PathBuf, std::string::String)>,
settings: &'a kcl_lib::ExecutorSettings,
}
@ -31,7 +32,31 @@ async fn cache_test(
// set the new settings.
ctx.settings = variation.settings.clone();
let outcome = ctx.run_with_caching(program).await.unwrap();
if !variation.other_files.is_empty() {
let tmp_dir = std::env::temp_dir();
let tmp_dir = tmp_dir
.join(format!("kcl_test_{}", test_name))
.join(uuid::Uuid::new_v4().to_string());
// Create a temporary file for each of the other files.
for (variant_path, variant_code) in &variation.other_files {
let tmp_file = tmp_dir.join(variant_path);
std::fs::create_dir_all(tmp_file.parent().unwrap()).unwrap();
std::fs::write(tmp_file, variant_code).unwrap();
}
ctx.settings.project_directory = Some(tmp_dir.clone());
}
let outcome = match ctx.run_with_caching(program).await {
Ok(outcome) => outcome,
Err(error) => {
let report = error.clone().into_miette_report_with_outputs(variation.code).unwrap();
let report = miette::Report::new(report);
panic!("{:?}", report);
}
};
let snapshot_png_bytes = ctx.prepare_snapshot().await.unwrap().contents.0;
// Decode the snapshot, return it.
@ -68,6 +93,7 @@ async fn kcl_test_cache_change_grid_visualizes_grid_off_to_on() {
vec![
Variation {
code,
other_files: vec![],
settings: &kcl_lib::ExecutorSettings {
show_grid: false,
..Default::default()
@ -75,6 +101,7 @@ async fn kcl_test_cache_change_grid_visualizes_grid_off_to_on() {
},
Variation {
code,
other_files: vec![],
settings: &kcl_lib::ExecutorSettings {
show_grid: true,
..Default::default()
@ -107,6 +134,7 @@ async fn kcl_test_cache_change_grid_visualizes_grid_on_to_off() {
vec![
Variation {
code,
other_files: vec![],
settings: &kcl_lib::ExecutorSettings {
show_grid: true,
..Default::default()
@ -114,6 +142,7 @@ async fn kcl_test_cache_change_grid_visualizes_grid_on_to_off() {
},
Variation {
code,
other_files: vec![],
settings: &kcl_lib::ExecutorSettings {
show_grid: false,
..Default::default()
@ -146,6 +175,7 @@ async fn kcl_test_cache_change_highlight_edges_changes_visual() {
vec![
Variation {
code,
other_files: vec![],
settings: &kcl_lib::ExecutorSettings {
highlight_edges: true,
..Default::default()
@ -153,6 +183,7 @@ async fn kcl_test_cache_change_highlight_edges_changes_visual() {
},
Variation {
code,
other_files: vec![],
settings: &kcl_lib::ExecutorSettings {
highlight_edges: false,
..Default::default()
@ -168,6 +199,58 @@ async fn kcl_test_cache_change_highlight_edges_changes_visual() {
assert!(first.1 != second.1);
}
#[tokio::test(flavor = "multi_thread")]
async fn kcl_test_cache_multi_file_same_code_dont_reexecute() {
let code = r#"import "toBeImported.kcl" as importedCube
importedCube
sketch001 = startSketchOn(XZ)
profile001 = startProfileAt([-134.53, -56.17], sketch001)
|> angledLine(angle = 0, length = 79.05, tag = $rectangleSegmentA001)
|> angledLine(angle = segAng(rectangleSegmentA001) - 90, length = 76.28)
|> angledLine(angle = segAng(rectangleSegmentA001), length = -segLen(rectangleSegmentA001), tag = $seg01)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)], tag = $seg02)
|> close()
extrude001 = extrude(profile001, length = 100)
sketch003 = startSketchOn(extrude001, face = seg02)
sketch002 = startSketchOn(extrude001, face = seg01)
"#;
let other_file = (
std::path::PathBuf::from("toBeImported.kcl"),
r#"sketch001 = startSketchOn(XZ)
profile001 = startProfileAt([281.54, 305.81], sketch001)
|> angledLine(angle = 0, length = 123.43, tag = $rectangleSegmentA001)
|> angledLine(angle = segAng(rectangleSegmentA001) - 90, length = 85.99)
|> angledLine(angle = segAng(rectangleSegmentA001), length = -segLen(rectangleSegmentA001))
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close()
extrude(profile001, length = 100)"#
.to_string(),
);
let result = cache_test(
"multi_file_same_code_dont_reexecute",
vec![
Variation {
code,
other_files: vec![other_file.clone()],
settings: &Default::default(),
},
Variation {
code,
other_files: vec![other_file],
settings: &Default::default(),
},
],
)
.await;
result.first().unwrap();
result.last().unwrap();
}
#[tokio::test(flavor = "multi_thread")]
async fn kcl_test_cache_add_line_preserves_artifact_commands() {
let code = r#"sketch001 = startSketchOn('XY')
@ -190,10 +273,12 @@ extrude(sketch001, length = 4)
vec![
Variation {
code,
other_files: vec![],
settings: &Default::default(),
},
Variation {
code: code_with_extrude.as_str(),
other_files: vec![],
settings: &Default::default(),
},
],
@ -282,3 +367,109 @@ async fn kcl_test_cache_empty_file_pop_cache_empty_file_planes_work() {
ctx.close().await;
}
#[tokio::test(flavor = "multi_thread")]
async fn kcl_test_cache_multi_file_after_empty_with_export() {
let code = r#"import importedCube from "toBeImported.kcl"
importedCube
sketch001 = startSketchOn(XZ)
profile001 = startProfileAt([-134.53, -56.17], sketch001)
|> angledLine(angle = 0, length = 79.05, tag = $rectangleSegmentA001)
|> angledLine(angle = segAng(rectangleSegmentA001) - 90, length = 76.28)
|> angledLine(angle = segAng(rectangleSegmentA001), length = -segLen(rectangleSegmentA001), tag = $seg01)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)], tag = $seg02)
|> close()
extrude001 = extrude(profile001, length = 100)
sketch003 = startSketchOn(extrude001, face = seg02)
sketch002 = startSketchOn(extrude001, face = seg01)
"#;
let other_file = (
std::path::PathBuf::from("toBeImported.kcl"),
r#"sketch001 = startSketchOn(XZ)
profile001 = startProfileAt([281.54, 305.81], sketch001)
|> angledLine(angle = 0, length = 123.43, tag = $rectangleSegmentA001)
|> angledLine(angle = segAng(rectangleSegmentA001) - 90, length = 85.99)
|> angledLine(angle = segAng(rectangleSegmentA001), length = -segLen(rectangleSegmentA001))
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close()
export importedCube = extrude(profile001, length = 100)
"#
.to_string(),
);
let result = cache_test(
"multi_file_after_empty",
vec![
Variation {
code: "",
other_files: vec![],
settings: &Default::default(),
},
Variation {
code,
other_files: vec![other_file],
settings: &Default::default(),
},
],
)
.await;
result.first().unwrap();
result.last().unwrap();
}
#[tokio::test(flavor = "multi_thread")]
async fn kcl_test_cache_multi_file_after_empty_with_woo() {
let code = r#"import "toBeImported.kcl" as importedCube
importedCube
sketch001 = startSketchOn(XZ)
profile001 = startProfileAt([-134.53, -56.17], sketch001)
|> angledLine(angle = 0, length = 79.05, tag = $rectangleSegmentA001)
|> angledLine(angle = segAng(rectangleSegmentA001) - 90, length = 76.28)
|> angledLine(angle = segAng(rectangleSegmentA001), length = -segLen(rectangleSegmentA001), tag = $seg01)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)], tag = $seg02)
|> close()
extrude001 = extrude(profile001, length = 100)
sketch003 = startSketchOn(extrude001, face = seg02)
sketch002 = startSketchOn(extrude001, face = seg01)
"#;
let other_file = (
std::path::PathBuf::from("toBeImported.kcl"),
r#"sketch001 = startSketchOn(XZ)
profile001 = startProfileAt([281.54, 305.81], sketch001)
|> angledLine(angle = 0, length = 123.43, tag = $rectangleSegmentA001)
|> angledLine(angle = segAng(rectangleSegmentA001) - 90, length = 85.99)
|> angledLine(angle = segAng(rectangleSegmentA001), length = -segLen(rectangleSegmentA001))
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close()
extrude(profile001, length = 100)
"#
.to_string(),
);
let result = cache_test(
"multi_file_after_empty",
vec![
Variation {
code: "",
other_files: vec![],
settings: &Default::default(),
},
Variation {
code,
other_files: vec![other_file],
settings: &Default::default(),
},
],
)
.await;
result.first().unwrap();
result.last().unwrap();
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

View File

@ -18,7 +18,7 @@ use tokio::sync::{mpsc, oneshot, RwLock};
use tokio_tungstenite::tungstenite::Message as WsMsg;
use uuid::Uuid;
use super::{EngineStats, ExecutionKind};
use super::EngineStats;
use crate::{
engine::EngineManager,
errors::{KclError, KclErrorDetails},
@ -51,7 +51,6 @@ pub struct EngineConnection {
/// If the server sends session data, it'll be copied to here.
session_data: Arc<RwLock<Option<ModelingSessionData>>>,
execution_kind: Arc<RwLock<ExecutionKind>>,
stats: EngineStats,
}
@ -344,7 +343,6 @@ impl EngineConnection {
artifact_commands: Arc::new(RwLock::new(Vec::new())),
default_planes: Default::default(),
session_data,
execution_kind: Default::default(),
stats: Default::default(),
})
}
@ -368,18 +366,6 @@ impl EngineManager for EngineConnection {
self.artifact_commands.clone()
}
async fn execution_kind(&self) -> ExecutionKind {
let guard = self.execution_kind.read().await;
*guard
}
async fn replace_execution_kind(&self, execution_kind: ExecutionKind) -> ExecutionKind {
let mut guard = self.execution_kind.write().await;
let original = *guard;
*guard = execution_kind;
original
}
fn stats(&self) -> &EngineStats {
&self.stats
}

View File

@ -16,7 +16,7 @@ use kittycad_modeling_cmds::{self as kcmc};
use tokio::sync::RwLock;
use uuid::Uuid;
use super::{EngineStats, ExecutionKind};
use super::EngineStats;
use crate::{
errors::KclError,
exec::DefaultPlanes,
@ -29,7 +29,6 @@ pub struct EngineConnection {
batch: Arc<RwLock<Vec<(WebSocketRequest, SourceRange)>>>,
batch_end: Arc<RwLock<IndexMap<uuid::Uuid, (WebSocketRequest, SourceRange)>>>,
artifact_commands: Arc<RwLock<Vec<ArtifactCommand>>>,
execution_kind: Arc<RwLock<ExecutionKind>>,
/// The default planes for the scene.
default_planes: Arc<RwLock<Option<DefaultPlanes>>>,
stats: EngineStats,
@ -41,7 +40,6 @@ impl EngineConnection {
batch: Arc::new(RwLock::new(Vec::new())),
batch_end: Arc::new(RwLock::new(IndexMap::new())),
artifact_commands: Arc::new(RwLock::new(Vec::new())),
execution_kind: Default::default(),
default_planes: Default::default(),
stats: Default::default(),
})
@ -70,18 +68,6 @@ impl crate::engine::EngineManager for EngineConnection {
self.artifact_commands.clone()
}
async fn execution_kind(&self) -> ExecutionKind {
let guard = self.execution_kind.read().await;
*guard
}
async fn replace_execution_kind(&self, execution_kind: ExecutionKind) -> ExecutionKind {
let mut guard = self.execution_kind.write().await;
let original = *guard;
*guard = execution_kind;
original
}
fn get_default_planes(&self) -> Arc<RwLock<Option<DefaultPlanes>>> {
self.default_planes.clone()
}

View File

@ -11,7 +11,7 @@ use uuid::Uuid;
use wasm_bindgen::prelude::*;
use crate::{
engine::{EngineStats, ExecutionKind},
engine::EngineStats,
errors::{KclError, KclErrorDetails},
execution::{ArtifactCommand, DefaultPlanes, IdGenerator},
SourceRange,
@ -42,7 +42,6 @@ pub struct EngineConnection {
batch_end: Arc<RwLock<IndexMap<uuid::Uuid, (WebSocketRequest, SourceRange)>>>,
responses: Arc<RwLock<IndexMap<Uuid, WebSocketResponse>>>,
artifact_commands: Arc<RwLock<Vec<ArtifactCommand>>>,
execution_kind: Arc<RwLock<ExecutionKind>>,
/// The default planes for the scene.
default_planes: Arc<RwLock<Option<DefaultPlanes>>>,
stats: EngineStats,
@ -61,7 +60,6 @@ impl EngineConnection {
batch_end: Arc::new(RwLock::new(IndexMap::new())),
responses: Arc::new(RwLock::new(IndexMap::new())),
artifact_commands: Arc::new(RwLock::new(Vec::new())),
execution_kind: Default::default(),
default_planes: Default::default(),
stats: Default::default(),
})
@ -164,18 +162,6 @@ impl crate::engine::EngineManager for EngineConnection {
self.artifact_commands.clone()
}
async fn execution_kind(&self) -> ExecutionKind {
let guard = self.execution_kind.read().await;
*guard
}
async fn replace_execution_kind(&self, execution_kind: ExecutionKind) -> ExecutionKind {
let mut guard = self.execution_kind.write().await;
let original = *guard;
*guard = execution_kind;
original
}
fn get_default_planes(&self) -> Arc<RwLock<Option<DefaultPlanes>>> {
self.default_planes.clone()
}
@ -218,11 +204,6 @@ impl crate::engine::EngineManager for EngineConnection {
.do_send_modeling_cmd(id, source_range, cmd, id_to_source_range)
.await?;
// In isolated mode, we don't save the response.
if self.execution_kind().await.is_isolated() {
return Ok(ws_result);
}
let mut responses = self.responses.write().await;
responses.insert(id, ws_result.clone());
drop(responses);

View File

@ -47,23 +47,6 @@ lazy_static::lazy_static! {
pub static ref GRID_SCALE_TEXT_OBJECT_ID: uuid::Uuid = uuid::Uuid::parse_str("10782f33-f588-4668-8bcd-040502d26590").unwrap();
}
/// The mode of execution. When isolated, like during an import, attempting to
/// send a command results in an error.
#[derive(Debug, Default, Clone, Copy, Deserialize, Serialize, PartialEq, Eq, ts_rs::TS, JsonSchema)]
#[ts(export)]
#[serde(rename_all = "camelCase")]
pub enum ExecutionKind {
#[default]
Normal,
Isolated,
}
impl ExecutionKind {
pub fn is_isolated(&self) -> bool {
matches!(self, ExecutionKind::Isolated)
}
}
#[derive(Default, Debug)]
pub struct EngineStats {
pub commands_batched: AtomicUsize,
@ -118,13 +101,6 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
std::mem::take(&mut *self.responses().write().await)
}
/// Get the current execution kind.
async fn execution_kind(&self) -> ExecutionKind;
/// Replace the current execution kind with a new value and return the
/// existing value.
async fn replace_execution_kind(&self, execution_kind: ExecutionKind) -> ExecutionKind;
/// Get the default planes.
fn get_default_planes(&self) -> Arc<RwLock<Option<DefaultPlanes>>>;
@ -289,11 +265,6 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
source_range: SourceRange,
cmd: &ModelingCmd,
) -> Result<(), crate::errors::KclError> {
// In isolated mode, we don't send the command to the engine.
if self.execution_kind().await.is_isolated() {
return Ok(());
}
let req = WebSocketRequest::ModelingCmdReq(ModelingCmdReq {
cmd: cmd.clone(),
cmd_id: id.into(),
@ -315,11 +286,6 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
source_range: SourceRange,
cmds: &[ModelingCmdReq],
) -> Result<(), crate::errors::KclError> {
// In isolated mode, we don't send the command to the engine.
if self.execution_kind().await.is_isolated() {
return Ok(());
}
// Add cmds to the batch.
let mut extended_cmds = Vec::with_capacity(cmds.len());
for cmd in cmds {
@ -342,11 +308,6 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
source_range: SourceRange,
cmd: &ModelingCmd,
) -> Result<(), crate::errors::KclError> {
// In isolated mode, we don't send the command to the engine.
if self.execution_kind().await.is_isolated() {
return Ok(());
}
let req = WebSocketRequest::ModelingCmdReq(ModelingCmdReq {
cmd: cmd.clone(),
cmd_id: id.into(),
@ -365,36 +326,36 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
source_range: SourceRange,
cmd: &ModelingCmd,
) -> Result<OkWebSocketResponseData, crate::errors::KclError> {
self.batch_modeling_cmd(id, source_range, cmd).await?;
let mut requests = self.take_batch().await.clone();
// Add the command to the batch.
requests.push((
WebSocketRequest::ModelingCmdReq(ModelingCmdReq {
cmd: cmd.clone(),
cmd_id: id.into(),
}),
source_range,
));
self.stats().commands_batched.fetch_add(1, Ordering::Relaxed);
// Flush the batch queue.
self.flush_batch(false, source_range).await
self.run_batch(requests, source_range).await
}
/// Force flush the batch queue.
async fn flush_batch(
/// Run the batch for the specific commands.
async fn run_batch(
&self,
// Whether or not to flush the end commands as well.
// We only do this at the very end of the file.
batch_end: bool,
orig_requests: Vec<(WebSocketRequest, SourceRange)>,
source_range: SourceRange,
) -> Result<OkWebSocketResponseData, crate::errors::KclError> {
let all_requests = if batch_end {
let mut requests = self.take_batch().await.clone();
requests.extend(self.take_batch_end().await.values().cloned());
requests
} else {
self.take_batch().await.clone()
};
// Return early if we have no commands to send.
if all_requests.is_empty() {
if orig_requests.is_empty() {
return Ok(OkWebSocketResponseData::Modeling {
modeling_response: OkModelingCmdResponse::Empty {},
});
}
let requests: Vec<ModelingCmdReq> = all_requests
let requests: Vec<ModelingCmdReq> = orig_requests
.iter()
.filter_map(|(val, _)| match val {
WebSocketRequest::ModelingCmdReq(ModelingCmdReq { cmd, cmd_id }) => Some(ModelingCmdReq {
@ -411,9 +372,9 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
responses: true,
});
let final_req = if all_requests.len() == 1 {
let final_req = if orig_requests.len() == 1 {
// We can unwrap here because we know the batch has only one element.
all_requests.first().unwrap().0.clone()
orig_requests.first().unwrap().0.clone()
} else {
batched_requests
};
@ -421,7 +382,7 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
// Create the map of original command IDs to source range.
// This is for the wasm side, kurt needs it for selections.
let mut id_to_source_range = HashMap::new();
for (req, range) in all_requests.iter() {
for (req, range) in orig_requests.iter() {
match req {
WebSocketRequest::ModelingCmdReq(ModelingCmdReq { cmd: _, cmd_id }) => {
id_to_source_range.insert(Uuid::from(*cmd_id), *range);
@ -436,7 +397,7 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
}
// Do the artifact commands.
for (req, _) in all_requests.iter() {
for (req, _) in orig_requests.iter() {
match &req {
WebSocketRequest::ModelingCmdBatchReq(ModelingBatch { requests, .. }) => {
for request in requests {
@ -506,6 +467,25 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
}
}
/// Force flush the batch queue.
async fn flush_batch(
&self,
// Whether or not to flush the end commands as well.
// We only do this at the very end of the file.
batch_end: bool,
source_range: SourceRange,
) -> Result<OkWebSocketResponseData, crate::errors::KclError> {
let all_requests = if batch_end {
let mut requests = self.take_batch().await.clone();
requests.extend(self.take_batch_end().await.values().cloned());
requests
} else {
self.take_batch().await.clone()
};
self.run_batch(all_requests, source_range).await
}
async fn make_default_plane(
&self,
plane_id: uuid::Uuid,

View File

@ -217,10 +217,13 @@ impl IntoDiagnostic for KclErrorWithOutputs {
fn to_lsp_diagnostics(&self, code: &str) -> Vec<Diagnostic> {
let message = self.error.get_message();
let source_ranges = self.error.source_ranges();
println!("self: {:?}", self);
source_ranges
.into_iter()
.map(|source_range| {
println!("source_range: {:?}", source_range);
println!("filenames: {:?}", self.filenames);
let source = self
.source_files
.get(&source_range.module_id())

View File

@ -243,7 +243,7 @@ fn generate_changed_program(old_ast: Node<Program>, mut new_ast: Node<Program>,
#[cfg(test)]
mod tests {
use super::*;
use crate::execution::{parse_execute, ExecTestResults};
use crate::execution::{parse_execute, parse_execute_with_project_dir, ExecTestResults};
#[tokio::test(flavor = "multi_thread")]
async fn test_get_changed_program_same_code() {
@ -600,4 +600,64 @@ startSketchOn('XY')
}
);
}
#[tokio::test(flavor = "multi_thread")]
async fn test_multi_file_no_changes_does_not_reexecute() {
let code = r#"import "toBeImported.kcl" as importedCube
importedCube
sketch001 = startSketchOn(XZ)
profile001 = startProfileAt([-134.53, -56.17], sketch001)
|> angledLine(angle = 0, length = 79.05, tag = $rectangleSegmentA001)
|> angledLine(angle = segAng(rectangleSegmentA001) - 90, length = 76.28)
|> angledLine(angle = segAng(rectangleSegmentA001), length = -segLen(rectangleSegmentA001), tag = $seg01)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)], tag = $seg02)
|> close()
extrude001 = extrude(profile001, length = 100)
sketch003 = startSketchOn(extrude001, face = seg02)
sketch002 = startSketchOn(extrude001, face = seg01)
"#;
let other_file = (
std::path::PathBuf::from("toBeImported.kcl"),
r#"sketch001 = startSketchOn(XZ)
profile001 = startProfileAt([281.54, 305.81], sketch001)
|> angledLine(angle = 0, length = 123.43, tag = $rectangleSegmentA001)
|> angledLine(angle = segAng(rectangleSegmentA001) - 90, length = 85.99)
|> angledLine(angle = segAng(rectangleSegmentA001), length = -segLen(rectangleSegmentA001))
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close()
extrude(profile001, length = 100)"#
.to_string(),
);
let tmp_dir = std::env::temp_dir();
let tmp_dir = tmp_dir.join(uuid::Uuid::new_v4().to_string());
// Create a temporary file for each of the other files.
let tmp_file = tmp_dir.join(other_file.0);
std::fs::create_dir_all(tmp_file.parent().unwrap()).unwrap();
std::fs::write(tmp_file, other_file.1).unwrap();
let ExecTestResults { program, exec_ctxt, .. } =
parse_execute_with_project_dir(code, Some(tmp_dir)).await.unwrap();
let mut new_program = crate::Program::parse_no_errs(code).unwrap();
new_program.compute_digest();
let result = get_changed_program(
CacheInformation {
ast: &program.ast,
settings: &exec_ctxt.settings,
},
CacheInformation {
ast: &new_program.ast,
settings: &exec_ctxt.settings,
},
)
.await;
assert_eq!(result, CacheResult::NoAction(false));
}
}

View File

@ -9,7 +9,6 @@ use super::{
types::{PrimitiveType, CHECK_NUMERIC_TYPES},
};
use crate::{
engine::ExecutionKind,
errors::{KclError, KclErrorDetails},
execution::{
annotations,
@ -66,7 +65,6 @@ impl ExecutorContext {
exec_state.mod_local.explicit_length_units = true;
}
let new_units = exec_state.length_unit();
if !self.engine.execution_kind().await.is_isolated() {
self.engine
.set_units(
new_units.into(),
@ -74,7 +72,6 @@ impl ExecutorContext {
exec_state.id_generator(),
)
.await?;
}
} else {
exec_state.err(CompilationError::err(
annotation.as_source_range(),
@ -104,15 +101,11 @@ impl ExecutorContext {
&self,
program: &Node<Program>,
exec_state: &mut ExecState,
exec_kind: ExecutionKind,
preserve_mem: bool,
module_id: ModuleId,
path: &ModulePath,
) -> Result<(Option<KclValue>, EnvironmentRef, Vec<String>), KclError> {
crate::log::log(format!("enter module {path} {} {exec_kind:?}", exec_state.stack()));
let old_units = exec_state.length_unit();
let original_execution = self.engine.replace_execution_kind(exec_kind).await;
crate::log::log(format!("enter module {path} {}", exec_state.stack()));
let mut local_state = ModuleState::new(path.std_path(), exec_state.stack().memory.clone(), Some(module_id));
if !preserve_mem {
@ -131,7 +124,6 @@ impl ExecutorContext {
.exec_block(program, exec_state, crate::execution::BodyType::Root)
.await;
let new_units = exec_state.length_unit();
let env_ref = if preserve_mem {
exec_state.mut_stack().pop_and_preserve_env()
} else {
@ -141,17 +133,6 @@ impl ExecutorContext {
std::mem::swap(&mut exec_state.mod_local, &mut local_state);
}
// We only need to reset the units if we are not on the Main path.
// If we reset at the end of the main path, then we just add on an extra
// command and we'd need to flush the batch again.
// This avoids that.
if !exec_kind.is_isolated() && new_units != old_units && *path != ModulePath::Main {
self.engine
.set_units(old_units.into(), Default::default(), exec_state.id_generator())
.await?;
}
self.engine.replace_execution_kind(original_execution).await;
crate::log::log(format!("leave {path}"));
result.map(|result| (result, env_ref, local_state.module_exports))
@ -161,7 +142,7 @@ impl ExecutorContext {
#[async_recursion]
pub(super) async fn exec_block<'a>(
&'a self,
program: NodeRef<'a, crate::parsing::ast::types::Program>,
program: NodeRef<'a, Program>,
exec_state: &mut ExecState,
body_type: BodyType,
) -> Result<Option<KclValue>, KclError> {
@ -185,9 +166,8 @@ impl ExecutorContext {
match &import_stmt.selector {
ImportSelector::List { items } => {
let (env_ref, module_exports) = self
.exec_module_for_items(module_id, exec_state, ExecutionKind::Isolated, source_range)
.await?;
let (env_ref, module_exports) =
self.exec_module_for_items(module_id, exec_state, source_range).await?;
for import_item in items {
// Extract the item from the module.
let item = exec_state
@ -228,9 +208,8 @@ impl ExecutorContext {
}
}
ImportSelector::Glob(_) => {
let (env_ref, module_exports) = self
.exec_module_for_items(module_id, exec_state, ExecutionKind::Isolated, source_range)
.await?;
let (env_ref, module_exports) =
self.exec_module_for_items(module_id, exec_state, source_range).await?;
for name in module_exports.iter() {
let item = exec_state
.stack()
@ -421,7 +400,7 @@ impl ExecutorContext {
Ok(last_expr)
}
pub(super) async fn open_module(
pub async fn open_module(
&self,
path: &ImportPath,
attrs: &[Node<Annotation>],
@ -429,6 +408,7 @@ impl ExecutorContext {
source_range: SourceRange,
) -> Result<ModuleId, KclError> {
let resolved_path = ModulePath::from_import_path(path, &self.settings.project_directory);
match path {
ImportPath::Kcl { .. } => {
exec_state.global.mod_loader.cycle_check(&resolved_path, source_range)?;
@ -485,7 +465,6 @@ impl ExecutorContext {
&self,
module_id: ModuleId,
exec_state: &mut ExecState,
exec_kind: ExecutionKind,
source_range: SourceRange,
) -> Result<(EnvironmentRef, Vec<String>), KclError> {
let path = exec_state.global.module_infos[&module_id].path.clone();
@ -494,12 +473,12 @@ impl ExecutorContext {
let result = match &mut repr {
ModuleRepr::Root => Err(exec_state.circular_import_error(&path, source_range)),
ModuleRepr::Kcl(_, Some((env_ref, items))) => Ok((*env_ref, items.clone())),
ModuleRepr::Kcl(_, Some((_, env_ref, items))) => Ok((*env_ref, items.clone())),
ModuleRepr::Kcl(program, cache) => self
.exec_module_from_ast(program, module_id, &path, exec_state, exec_kind, source_range)
.exec_module_from_ast(program, module_id, &path, exec_state, source_range, false)
.await
.map(|(_, er, items)| {
*cache = Some((er, items.clone()));
.map(|(val, er, items)| {
*cache = Some((val, er, items.clone()));
(er, items)
}),
ModuleRepr::Foreign(geom) => Err(KclError::Semantic(KclErrorDetails {
@ -518,7 +497,6 @@ impl ExecutorContext {
module_id: ModuleId,
module_name: &BoxNode<Name>,
exec_state: &mut ExecState,
exec_kind: ExecutionKind,
source_range: SourceRange,
) -> Result<Option<KclValue>, KclError> {
exec_state.global.operations.push(Operation::GroupBegin {
@ -535,13 +513,14 @@ impl ExecutorContext {
let result = match &mut repr {
ModuleRepr::Root => Err(exec_state.circular_import_error(&path, source_range)),
ModuleRepr::Kcl(_, Some((val, _, _))) => Ok(val.clone()),
ModuleRepr::Kcl(program, cached_items) => {
let result = self
.exec_module_from_ast(program, module_id, &path, exec_state, exec_kind, source_range)
.exec_module_from_ast(program, module_id, &path, exec_state, source_range, false)
.await;
match result {
Ok((val, env, items)) => {
*cached_items = Some((env, items));
*cached_items = Some((val.clone(), env, items));
Ok(val)
}
Err(e) => Err(e),
@ -560,18 +539,18 @@ impl ExecutorContext {
result
}
async fn exec_module_from_ast(
pub async fn exec_module_from_ast(
&self,
program: &Node<Program>,
module_id: ModuleId,
path: &ModulePath,
exec_state: &mut ExecState,
exec_kind: ExecutionKind,
source_range: SourceRange,
preserve_mem: bool,
) -> Result<(Option<KclValue>, EnvironmentRef, Vec<String>), KclError> {
exec_state.global.mod_loader.enter_module(path);
let result = self
.exec_module_body(program, exec_state, exec_kind, false, module_id, path)
.exec_module_body(program, exec_state, preserve_mem, module_id, path)
.await;
exec_state.global.mod_loader.leave_module(path);
@ -608,7 +587,7 @@ impl ExecutorContext {
Expr::Name(name) => {
let value = name.get_result(exec_state, self).await?.clone();
if let KclValue::Module { value: module_id, meta } = value {
self.exec_module_for_result(module_id, name, exec_state, ExecutionKind::Normal, metadata.source_range)
self.exec_module_for_result(module_id, name, exec_state, metadata.source_range)
.await?
.unwrap_or_else(|| {
exec_state.warn(CompilationError::err(
@ -808,7 +787,7 @@ impl Node<Name> {
};
mem_spec = Some(
ctx.exec_module_for_items(*module_id, exec_state, ExecutionKind::Normal, p.as_source_range())
ctx.exec_module_for_items(*module_id, exec_state, p.as_source_range())
.await?,
);
}
@ -1320,7 +1299,7 @@ impl Node<CallExpressionKw> {
));
}
let op = if func.feature_tree_operation() && !ctx.is_isolated_execution().await {
let op = if func.feature_tree_operation() {
let op_labeled_args = args
.kw_args
.labeled
@ -1406,7 +1385,7 @@ impl Node<CallExpressionKw> {
e.add_source_ranges(vec![callsite])
})?;
if matches!(fn_src, FunctionSource::User { .. }) && !ctx.is_isolated_execution().await {
if matches!(fn_src, FunctionSource::User { .. }) {
// Track return operation.
exec_state.global.operations.push(Operation::GroupEnd);
}
@ -1458,7 +1437,7 @@ impl Node<CallExpression> {
));
}
let op = if func.feature_tree_operation() && !ctx.is_isolated_execution().await {
let op = if func.feature_tree_operation() {
let op_labeled_args = func
.args(false)
.iter()
@ -1516,7 +1495,6 @@ impl Node<CallExpression> {
// exec_state.
let func = fn_name.get_result(exec_state, ctx).await?.clone();
if !ctx.is_isolated_execution().await {
// Track call operation.
exec_state.global.operations.push(Operation::GroupBegin {
group: Group::FunctionCall {
@ -1528,7 +1506,6 @@ impl Node<CallExpression> {
},
source_range: callsite,
});
}
let Some(fn_src) = func.as_fn() else {
return Err(KclError::Semantic(KclErrorDetails {
@ -1557,10 +1534,8 @@ impl Node<CallExpression> {
})
})?;
if !ctx.is_isolated_execution().await {
// Track return operation.
exec_state.global.operations.push(Operation::GroupEnd);
}
Ok(result)
}
@ -2313,7 +2288,7 @@ impl FunctionSource {
}
}
let op = if props.include_in_feature_tree && !ctx.is_isolated_execution().await {
let op = if props.include_in_feature_tree {
let op_labeled_args = args
.kw_args
.labeled
@ -2357,7 +2332,6 @@ impl FunctionSource {
Ok(Some(result))
}
FunctionSource::User { ast, memory, .. } => {
if !ctx.is_isolated_execution().await {
// Track call operation.
let op_labeled_args = args
.kw_args
@ -2378,7 +2352,6 @@ impl FunctionSource {
},
source_range: callsite,
});
}
call_user_defined_function_kw(fn_name.as_deref(), args.kw_args, *memory, ast, exec_state, ctx).await
}
@ -2391,10 +2364,13 @@ impl FunctionSource {
mod test {
use std::sync::Arc;
use tokio::io::AsyncWriteExt;
use super::*;
use crate::{
execution::{memory::Stack, parse_execute, ContextType},
parsing::ast::types::{DefaultParamVal, Identifier, Parameter},
ExecutorSettings,
};
#[tokio::test(flavor = "multi_thread")]
@ -2504,7 +2480,7 @@ mod test {
// Run each test.
let func_expr = &Node::no_src(FunctionExpression {
params,
body: crate::parsing::ast::types::Program::empty(),
body: Program::empty(),
return_type: None,
digest: None,
});
@ -2607,6 +2583,102 @@ a = foo()
assert!(result.unwrap_err().to_string().contains("return"));
}
#[tokio::test(flavor = "multi_thread")]
async fn load_all_modules() {
// program a.kcl
let programa_kcl = r#"
export a = 1
"#;
// program b.kcl
let programb_kcl = r#"
import a from 'a.kcl'
export b = a + 1
"#;
// program c.kcl
let programc_kcl = r#"
import a from 'a.kcl'
export c = a + 2
"#;
// program main.kcl
let main_kcl = r#"
import b from 'b.kcl'
import c from 'c.kcl'
d = b + c
"#;
let main = crate::parsing::parse_str(main_kcl, ModuleId::default())
.parse_errs_as_err()
.unwrap();
let tmpdir = tempdir::TempDir::new("zma_kcl_load_all_modules").unwrap();
tokio::fs::File::create(tmpdir.path().join("main.kcl"))
.await
.unwrap()
.write_all(main_kcl.as_bytes())
.await
.unwrap();
tokio::fs::File::create(tmpdir.path().join("a.kcl"))
.await
.unwrap()
.write_all(programa_kcl.as_bytes())
.await
.unwrap();
tokio::fs::File::create(tmpdir.path().join("b.kcl"))
.await
.unwrap()
.write_all(programb_kcl.as_bytes())
.await
.unwrap();
tokio::fs::File::create(tmpdir.path().join("c.kcl"))
.await
.unwrap()
.write_all(programc_kcl.as_bytes())
.await
.unwrap();
let exec_ctxt = ExecutorContext {
engine: Arc::new(Box::new(
crate::engine::conn_mock::EngineConnection::new()
.await
.map_err(|err| {
KclError::Internal(crate::errors::KclErrorDetails {
message: format!("Failed to create mock engine connection: {}", err),
source_ranges: vec![SourceRange::default()],
})
})
.unwrap(),
)),
fs: Arc::new(crate::fs::FileManager::new()),
settings: ExecutorSettings {
project_directory: Some(tmpdir.path().into()),
..Default::default()
},
stdlib: Arc::new(crate::std::StdLib::new()),
context_type: ContextType::Mock,
};
let mut exec_state = ExecState::new(&exec_ctxt);
exec_ctxt
.run_concurrent(
&crate::Program {
ast: main.clone(),
original_file_contents: "".to_owned(),
},
&mut exec_state,
false,
)
.await
.unwrap();
}
#[tokio::test(flavor = "multi_thread")]
async fn user_coercion() {
let program = r#"fn foo(x: Axis2d) {

View File

@ -4,13 +4,13 @@ use anyhow::Result;
use schemars::JsonSchema;
use serde::Serialize;
use super::{types::UnitLen, EnvironmentRef, ExecState, MetaSettings};
use crate::{
errors::KclErrorDetails,
execution::{
annotations::{SETTINGS, SETTINGS_UNIT_LENGTH},
types::{NumericType, PrimitiveType, RuntimeType},
Face, Helix, ImportedGeometry, Metadata, Plane, Sketch, Solid, TagIdentifier,
types::{NumericType, PrimitiveType, RuntimeType, UnitLen},
EnvironmentRef, ExecState, Face, Helix, ImportedGeometry, MetaSettings, Metadata, Plane, Sketch, Solid,
TagIdentifier,
},
parsing::ast::types::{
DefaultParamVal, FunctionExpression, KclNone, Literal, LiteralValue, Node, TagDeclarator, TagNode,

View File

@ -28,18 +28,18 @@ pub use state::{ExecState, MetaSettings};
use crate::{
engine::EngineManager,
errors::KclError,
errors::{KclError, KclErrorDetails},
execution::{
artifact::build_artifact_graph,
cache::{CacheInformation, CacheResult},
types::{UnitAngle, UnitLen},
},
fs::FileManager,
modules::{ModuleId, ModulePath},
modules::{ModuleId, ModulePath, ModuleRepr},
parsing::ast::types::{Expr, ImportPath, NodeRef},
source_range::SourceRange,
std::StdLib,
CompilationError, ExecError, ExecutionKind, KclErrorWithOutputs,
CompilationError, ExecError, KclErrorWithOutputs,
};
pub(crate) mod annotations;
@ -495,13 +495,9 @@ impl ExecutorContext {
self.context_type == ContextType::Mock || self.context_type == ContextType::MockCustomForwarded
}
pub async fn is_isolated_execution(&self) -> bool {
self.engine.execution_kind().await.is_isolated()
}
/// Returns true if we should not send engine commands for any reason.
pub async fn no_engine_commands(&self) -> bool {
self.is_mock() || self.is_isolated_execution().await
self.is_mock()
}
pub async fn send_clear_scene(
@ -672,7 +668,7 @@ impl ExecutorContext {
(program, exec_state, false)
};
let result = self.inner_run(&program, &mut exec_state, preserve_mem).await;
let result = self.run_concurrent(&program, &mut exec_state, preserve_mem).await;
if result.is_err() {
cache::bust_cache().await;
@ -705,9 +701,210 @@ impl ExecutorContext {
program: &crate::Program,
exec_state: &mut ExecState,
) -> Result<(EnvironmentRef, Option<ModelingSessionData>), KclErrorWithOutputs> {
self.run_concurrent(program, exec_state, false).await
}
/// Perform the execution of a program.
///
/// You can optionally pass in some initialization memory for partial
/// execution.
///
/// To access non-fatal errors and warnings, extract them from the `ExecState`.
pub async fn run_single_threaded(
&self,
program: &crate::Program,
exec_state: &mut ExecState,
) -> Result<(EnvironmentRef, Option<ModelingSessionData>), KclErrorWithOutputs> {
exec_state.add_root_module_contents(program);
self.eval_prelude(exec_state, SourceRange::synthetic())
.await
.map_err(KclErrorWithOutputs::no_outputs)?;
self.inner_run(program, exec_state, false).await
}
/// Perform the execution of a program using an (experimental!) concurrent
/// execution model. This has the same signature as [Self::run].
///
/// For now -- do not use this unless you're willing to accept some
/// breakage.
///
/// You can optionally pass in some initialization memory for partial
/// execution.
///
/// To access non-fatal errors and warnings, extract them from the `ExecState`.
pub async fn run_concurrent(
&self,
program: &crate::Program,
exec_state: &mut ExecState,
preserve_mem: bool,
) -> Result<(EnvironmentRef, Option<ModelingSessionData>), KclErrorWithOutputs> {
exec_state.add_root_module_contents(program);
self.eval_prelude(exec_state, SourceRange::synthetic())
.await
.map_err(KclErrorWithOutputs::no_outputs)?;
let mut universe = std::collections::HashMap::new();
let default_planes = self.engine.get_default_planes().read().await.clone();
crate::walk::import_universe(self, &program.ast, &mut universe, exec_state)
.await
.map_err(|err| {
let module_id_to_module_path: IndexMap<ModuleId, ModulePath> = exec_state
.global
.path_to_source_id
.iter()
.map(|(k, v)| ((*v), k.clone()))
.collect();
KclErrorWithOutputs::new(
err,
exec_state.global.operations.clone(),
exec_state.global.artifact_commands.clone(),
exec_state.global.artifact_graph.clone(),
module_id_to_module_path,
exec_state.global.id_to_source.clone(),
default_planes.clone(),
)
})?;
for modules in crate::walk::import_graph(&universe, self)
.map_err(|err| {
let module_id_to_module_path: IndexMap<ModuleId, ModulePath> = exec_state
.global
.path_to_source_id
.iter()
.map(|(k, v)| ((*v), k.clone()))
.collect();
KclErrorWithOutputs::new(
err,
exec_state.global.operations.clone(),
exec_state.global.artifact_commands.clone(),
exec_state.global.artifact_graph.clone(),
module_id_to_module_path,
exec_state.global.id_to_source.clone(),
default_planes.clone(),
)
})?
.into_iter()
{
#[cfg(not(target_arch = "wasm32"))]
let mut set = tokio::task::JoinSet::new();
#[allow(clippy::type_complexity)]
let (results_tx, mut results_rx): (
tokio::sync::mpsc::Sender<(
ModuleId,
ModulePath,
Result<(Option<KclValue>, EnvironmentRef, Vec<String>), KclError>,
)>,
tokio::sync::mpsc::Receiver<_>,
) = tokio::sync::mpsc::channel(1);
for module in modules {
let Some((import_stmt, module_id, module_path, program)) = universe.get(&module) else {
return Err(KclErrorWithOutputs::no_outputs(KclError::Internal(KclErrorDetails {
message: format!("Module {module} not found in universe"),
source_ranges: Default::default(),
})));
};
let module_id = *module_id;
let module_path = module_path.clone();
let program = program.clone();
let exec_state = exec_state.clone();
let exec_ctxt = self.clone();
let results_tx = results_tx.clone();
let source_range = SourceRange::from(import_stmt);
#[cfg(target_arch = "wasm32")]
{
wasm_bindgen_futures::spawn_local(async move {
//set.spawn(async move {
let mut exec_state = exec_state;
let exec_ctxt = exec_ctxt;
let result = exec_ctxt
.exec_module_from_ast(
&program,
module_id,
&module_path,
&mut exec_state,
source_range,
false,
)
.await;
results_tx
.send((module_id, module_path, result))
.await
.unwrap_or_default();
});
}
#[cfg(not(target_arch = "wasm32"))]
{
set.spawn(async move {
let mut exec_state = exec_state;
let exec_ctxt = exec_ctxt;
let result = exec_ctxt
.exec_module_from_ast(
&program,
module_id,
&module_path,
&mut exec_state,
source_range,
false,
)
.await;
results_tx
.send((module_id, module_path, result))
.await
.unwrap_or_default();
});
}
}
drop(results_tx);
while let Some((module_id, _, result)) = results_rx.recv().await {
match result {
Ok((val, session_data, variables)) => {
let mut repr = exec_state.global.module_infos[&module_id].take_repr();
let ModuleRepr::Kcl(_, cache) = &mut repr else {
continue;
};
*cache = Some((val, session_data, variables));
exec_state.global.module_infos[&module_id].restore_repr(repr);
}
Err(e) => {
let module_id_to_module_path: IndexMap<ModuleId, ModulePath> = exec_state
.global
.path_to_source_id
.iter()
.map(|(k, v)| ((*v), k.clone()))
.collect();
return Err(KclErrorWithOutputs::new(
e,
exec_state.global.operations.clone(),
exec_state.global.artifact_commands.clone(),
exec_state.global.artifact_graph.clone(),
module_id_to_module_path,
exec_state.global.id_to_source.clone(),
default_planes,
));
}
}
}
}
self.inner_run(program, exec_state, preserve_mem).await
}
/// Perform the execution of a program. Accept all possible parameters and
/// output everything.
async fn inner_run(
@ -716,8 +913,6 @@ impl ExecutorContext {
exec_state: &mut ExecState,
preserve_mem: bool,
) -> Result<(EnvironmentRef, Option<ModelingSessionData>), KclErrorWithOutputs> {
exec_state.add_root_module_contents(program);
let _stats = crate::log::LogPerfStats::new("Interpretation");
// Re-apply the settings, in case the cache was busted.
@ -783,7 +978,6 @@ impl ExecutorContext {
.exec_module_body(
program,
exec_state,
ExecutionKind::Normal,
preserve_mem,
ModuleId::default(),
&ModulePath::Main,
@ -837,9 +1031,7 @@ impl ExecutorContext {
source_range,
)
.await?;
let (module_memory, _) = self
.exec_module_for_items(id, exec_state, ExecutionKind::Isolated, source_range)
.await?;
let (module_memory, _) = self.exec_module_for_items(id, exec_state, source_range).await?;
exec_state.mut_stack().memory.set_std(module_memory);
}
@ -947,6 +1139,14 @@ impl ExecutorContext {
#[cfg(test)]
pub(crate) async fn parse_execute(code: &str) -> Result<ExecTestResults, KclError> {
parse_execute_with_project_dir(code, None).await
}
#[cfg(test)]
pub(crate) async fn parse_execute_with_project_dir(
code: &str,
project_directory: Option<std::path::PathBuf>,
) -> Result<ExecTestResults, KclError> {
let program = crate::Program::parse_no_errs(code)?;
let exec_ctxt = ExecutorContext {
@ -960,7 +1160,10 @@ pub(crate) async fn parse_execute(code: &str) -> Result<ExecTestResults, KclErro
)),
fs: Arc::new(crate::fs::FileManager::new()),
stdlib: Arc::new(crate::std::StdLib::new()),
settings: Default::default(),
settings: ExecutorSettings {
project_directory,
..Default::default()
},
context_type: ContextType::Mock,
};
let mut exec_state = ExecState::new(&exec_ctxt);

View File

@ -229,6 +229,10 @@ impl ExecState {
self.global.module_infos.insert(id, module_info);
}
pub fn get_module(&mut self, id: ModuleId) -> Option<&ModuleInfo> {
self.global.module_infos.get(&id)
}
pub fn current_default_units(&self) -> NumericType {
NumericType::Default {
len: self.length_unit(),

View File

@ -76,12 +76,12 @@ pub mod std;
pub mod test_server;
mod thread;
mod unparser;
mod walk;
pub mod walk;
#[cfg(target_arch = "wasm32")]
mod wasm;
pub use coredump::CoreDump;
pub use engine::{EngineManager, EngineStats, ExecutionKind};
pub use engine::{EngineManager, EngineStats};
pub use errors::{
CompilationError, ConnectionError, ExecError, KclError, KclErrorWithOutputs, Report, ReportWithOutputs,
};

View File

@ -6,6 +6,7 @@ use serde::{Deserialize, Serialize};
use crate::{
errors::{KclError, KclErrorDetails},
exec::KclValue,
execution::{EnvironmentRef, PreImportedGeometry},
fs::{FileManager, FileSystem},
parsing::ast::types::{ImportPath, Node, Program},
@ -94,7 +95,7 @@ pub(crate) fn read_std(mod_name: &str) -> Option<&'static str> {
}
/// Info about a module.
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
#[derive(Debug, Clone, PartialEq, Serialize)]
pub struct ModuleInfo {
/// The ID of the module.
pub(crate) id: ModuleId,
@ -117,11 +118,11 @@ impl ModuleInfo {
}
#[allow(clippy::large_enum_variant)]
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
#[derive(Debug, Clone, PartialEq, Serialize)]
pub enum ModuleRepr {
Root,
// AST, memory, exported names
Kcl(Node<Program>, Option<(EnvironmentRef, Vec<String>)>),
Kcl(Node<Program>, Option<(Option<KclValue>, EnvironmentRef, Vec<String>)>),
Foreign(PreImportedGeometry),
Dummy,
}

View File

@ -1,4 +1,5 @@
use std::{
collections::HashMap,
panic::{catch_unwind, AssertUnwindSafe},
path::{Path, PathBuf},
};
@ -251,6 +252,38 @@ fn assert_common_snapshots(
artifact_commands: Vec<ArtifactCommand>,
artifact_graph: ArtifactGraph,
) {
let artifact_commands = {
// Due to our newfound concurrency, we're going to mess with the
// artifact_commands a bit -- we're going to maintain the order,
// but only for a given module ID. This means the artifact_commands
// is no longer meaningful, but it is deterministic and will hopefully
// catch meaningful changes in behavior.
let mut artifact_commands_map = artifact_commands
.into_iter()
.map(|v| (v.range.module_id().as_usize(), v))
.fold(
HashMap::<usize, Vec<ArtifactCommand>>::new(),
|mut map, (module_id, el)| {
let mut v = map.remove(&module_id).unwrap_or_default();
v.push(el);
map.insert(module_id, v);
map
},
);
let mut artifact_commands_keys = artifact_commands_map.keys().cloned().collect::<Vec<_>>();
artifact_commands_keys.sort();
let artifact_commands: Vec<ArtifactCommand> = artifact_commands_keys
.iter()
.flat_map(|idx| artifact_commands_map.remove(idx).unwrap())
.collect();
assert_eq!(0, artifact_commands_map.len());
artifact_commands
};
let result1 = catch_unwind(AssertUnwindSafe(|| {
assert_snapshot(test, "Operations executed", || {
insta::assert_json_snapshot!("ops", operations, {

View File

@ -86,7 +86,7 @@ async fn do_execute_and_snapshot(
) -> Result<(ExecState, EnvironmentRef, image::DynamicImage), ExecErrorWithState> {
let mut exec_state = ExecState::new(ctx);
let result = ctx
.run(&program, &mut exec_state)
.run_single_threaded(&program, &mut exec_state)
.await
.map_err(|err| ExecErrorWithState::new(err.into(), exec_state.clone()))?;
for e in exec_state.errors() {

View File

@ -6,31 +6,37 @@ use std::{
use anyhow::Result;
use crate::{
parsing::ast::types::{ImportPath, NodeRef, Program},
errors::KclErrorDetails,
modules::{ModulePath, ModuleRepr},
parsing::ast::types::{ImportPath, ImportStatement, Node as AstNode, NodeRef, Program},
walk::{Node, Visitable},
ExecState, ExecutorContext, KclError, ModuleId, SourceRange,
};
/// Specific dependency between two modules. The 0th element of this tuple
/// Specific dependency between two modules. The 0th element of this info
/// is the "importing" module, the 1st is the "imported" module. The 0th
/// module *depends on* the 1st module.
type Dependency = (String, String);
type Graph = Vec<Dependency>;
type DependencyInfo = (AstNode<ImportStatement>, ModuleId, ModulePath, AstNode<Program>);
type Universe = HashMap<String, DependencyInfo>;
/// Process a number of programs, returning the graph of dependencies.
///
/// This will (currently) return a list of lists of IDs that can be safely
/// run concurrently. Each "stage" is blocking in this model, which will
/// change in the future. Don't use this function widely, yet.
#[allow(clippy::iter_over_hash_type)]
pub fn import_graph(progs: HashMap<String, NodeRef<'_, Program>>) -> Result<Vec<Vec<String>>> {
pub fn import_graph(progs: &Universe, ctx: &ExecutorContext) -> Result<Vec<Vec<String>>, KclError> {
let mut graph = Graph::new();
for (name, program) in progs.iter() {
for (name, (_, _, _, program)) in progs.iter() {
graph.extend(
import_dependencies(program)?
import_dependencies(program, ctx)?
.into_iter()
.map(|dependency| (name.clone(), dependency))
.map(|(dependency, _, _)| (name.clone(), dependency))
.collect::<Vec<_>>(),
);
}
@ -40,7 +46,10 @@ pub fn import_graph(progs: HashMap<String, NodeRef<'_, Program>>) -> Result<Vec<
}
#[allow(clippy::iter_over_hash_type)]
fn topsort(all_modules: &[&str], graph: Graph) -> Result<Vec<Vec<String>>> {
fn topsort(all_modules: &[&str], graph: Graph) -> Result<Vec<Vec<String>>, KclError> {
if all_modules.is_empty() {
return Ok(vec![]);
}
let mut dep_map = HashMap::<String, Vec<String>>::new();
for (dependent, dependency) in graph.iter() {
@ -83,7 +92,13 @@ fn topsort(all_modules: &[&str], graph: Graph) -> Result<Vec<Vec<String>>> {
}
if stage_modules.is_empty() {
anyhow::bail!("imports are acyclic");
waiting_modules.sort();
return Err(KclError::ImportCycle(KclErrorDetails {
message: format!("circular import of modules not allowed: {}", waiting_modules.join(", ")),
// TODO: we can get the right import lines from the AST, but we don't
source_ranges: vec![SourceRange::default()],
}));
}
// not strictly needed here, but perhaps helpful to avoid thinking
@ -101,33 +116,97 @@ fn topsort(all_modules: &[&str], graph: Graph) -> Result<Vec<Vec<String>>> {
Ok(order)
}
pub(crate) fn import_dependencies(prog: NodeRef<'_, Program>) -> Result<Vec<String>> {
type ImportDependencies = Vec<(String, AstNode<ImportStatement>, ModulePath)>;
pub(crate) fn import_dependencies(
prog: NodeRef<Program>,
ctx: &ExecutorContext,
) -> Result<ImportDependencies, KclError> {
let ret = Arc::new(Mutex::new(vec![]));
fn walk(ret: Arc<Mutex<Vec<String>>>, node: Node<'_>) {
fn walk(ret: Arc<Mutex<ImportDependencies>>, node: Node<'_>, ctx: &ExecutorContext) -> Result<(), KclError> {
if let Node::ImportStatement(is) = node {
let dependency = match &is.path {
ImportPath::Kcl { filename } => filename.to_string(),
ImportPath::Foreign { path } => path.to_string(),
ImportPath::Std { path } => path.join("::"),
// We only care about Kcl imports for now.
if let ImportPath::Kcl { filename } = &is.path {
let resolved_path = ModulePath::from_import_path(&is.path, &ctx.settings.project_directory);
// We need to lock the mutex to push the dependency.
// This is a bit of a hack, but it works for now.
ret.lock()
.map_err(|err| {
KclError::Internal(KclErrorDetails {
message: format!("Failed to lock mutex: {}", err),
source_ranges: Default::default(),
})
})?
.push((filename.to_string(), is.clone(), resolved_path));
}
}
for child in node.children().iter() {
walk(ret.clone(), *child, ctx)?;
}
Ok(())
}
walk(ret.clone(), prog.into(), ctx)?;
let ret = ret.lock().map_err(|err| {
KclError::Internal(KclErrorDetails {
message: format!("Failed to lock mutex: {}", err),
source_ranges: Default::default(),
})
})?;
Ok(ret.clone())
}
pub(crate) async fn import_universe(
ctx: &ExecutorContext,
prog: NodeRef<'_, Program>,
out: &mut Universe,
exec_state: &mut ExecState,
) -> Result<(), KclError> {
let modules = import_dependencies(prog, ctx)?;
for (filename, import_stmt, module_path) in modules {
if out.contains_key(&filename) {
continue;
}
let module_id = ctx
.open_module(&import_stmt.path, &[], exec_state, Default::default())
.await?;
let program = {
let Some(module_info) = exec_state.get_module(module_id) else {
return Err(KclError::Internal(KclErrorDetails {
message: format!("Module {} not found", module_id),
source_ranges: vec![import_stmt.into()],
}));
};
let ModuleRepr::Kcl(program, _) = &module_info.repr else {
// if it's not a KCL module we can skip it since it has no
// dependencies.
continue;
};
program.clone()
};
ret.lock().unwrap().push(dependency);
}
for child in node.children().iter() {
walk(ret.clone(), *child)
}
out.insert(
filename.clone(),
(import_stmt.clone(), module_id, module_path.clone(), program.clone()),
);
Box::pin(import_universe(ctx, &program, out, exec_state)).await?;
}
walk(ret.clone(), prog.into());
let ret = ret.lock().unwrap().clone();
Ok(ret)
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
use crate::parsing::ast::types::ImportSelector;
macro_rules! kcl {
( $kcl:expr ) => {{
@ -135,26 +214,41 @@ mod tests {
}};
}
#[test]
fn order_imports() {
fn into_module_info(program: AstNode<Program>) -> DependencyInfo {
(
AstNode::no_src(ImportStatement {
selector: ImportSelector::None { alias: None },
path: ImportPath::Kcl { filename: "".into() },
visibility: Default::default(),
digest: None,
}),
ModuleId::default(),
ModulePath::Local { value: "".into() },
program,
)
}
#[tokio::test]
async fn order_imports() {
let mut modules = HashMap::new();
let a = kcl!("");
modules.insert("a.kcl".to_owned(), &a);
modules.insert("a.kcl".to_owned(), into_module_info(a));
let b = kcl!(
"
import \"a.kcl\"
"
);
modules.insert("b.kcl".to_owned(), &b);
modules.insert("b.kcl".to_owned(), into_module_info(b));
let order = import_graph(modules).unwrap();
let ctx = ExecutorContext::new_mock().await;
let order = import_graph(&modules, &ctx).unwrap();
assert_eq!(vec![vec!["a.kcl".to_owned()], vec!["b.kcl".to_owned()]], order);
}
#[test]
fn order_imports_none() {
#[tokio::test]
async fn order_imports_none() {
let mut modules = HashMap::new();
let a = kcl!(
@ -162,49 +256,51 @@ import \"a.kcl\"
y = 2
"
);
modules.insert("a.kcl".to_owned(), &a);
modules.insert("a.kcl".to_owned(), into_module_info(a));
let b = kcl!(
"
x = 1
"
);
modules.insert("b.kcl".to_owned(), &b);
modules.insert("b.kcl".to_owned(), into_module_info(b));
let order = import_graph(modules).unwrap();
let ctx = ExecutorContext::new_mock().await;
let order = import_graph(&modules, &ctx).unwrap();
assert_eq!(vec![vec!["a.kcl".to_owned(), "b.kcl".to_owned()]], order);
}
#[test]
fn order_imports_2() {
#[tokio::test]
async fn order_imports_2() {
let mut modules = HashMap::new();
let a = kcl!("");
modules.insert("a.kcl".to_owned(), &a);
modules.insert("a.kcl".to_owned(), into_module_info(a));
let b = kcl!(
"
import \"a.kcl\"
"
);
modules.insert("b.kcl".to_owned(), &b);
modules.insert("b.kcl".to_owned(), into_module_info(b));
let c = kcl!(
"
import \"a.kcl\"
"
);
modules.insert("c.kcl".to_owned(), &c);
modules.insert("c.kcl".to_owned(), into_module_info(c));
let order = import_graph(modules).unwrap();
let ctx = ExecutorContext::new_mock().await;
let order = import_graph(&modules, &ctx).unwrap();
assert_eq!(
vec![vec!["a.kcl".to_owned()], vec!["b.kcl".to_owned(), "c.kcl".to_owned()]],
order
);
}
#[test]
fn order_imports_cycle() {
#[tokio::test]
async fn order_imports_cycle() {
let mut modules = HashMap::new();
let a = kcl!(
@ -212,15 +308,16 @@ import \"a.kcl\"
import \"b.kcl\"
"
);
modules.insert("a.kcl".to_owned(), &a);
modules.insert("a.kcl".to_owned(), into_module_info(a));
let b = kcl!(
"
import \"a.kcl\"
"
);
modules.insert("b.kcl".to_owned(), &b);
modules.insert("b.kcl".to_owned(), into_module_info(b));
import_graph(modules).unwrap_err();
let ctx = ExecutorContext::new_mock().await;
import_graph(&modules, &ctx).unwrap_err();
}
}

View File

@ -8,3 +8,5 @@ mod import_graph;
pub use ast_node::Node;
pub use ast_visitor::Visitable;
pub use ast_walk::walk;
pub use import_graph::import_graph;
pub(crate) use import_graph::import_universe;

View File

@ -28,5 +28,29 @@ description: Artifact commands add_lots.kcl
"object_id": "[uuid]",
"hidden": true
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
}
]

View File

@ -360,5 +360,29 @@ description: Artifact commands angled_line.kcl
"edge_id": "[uuid]",
"face_id": "[uuid]"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
}
]

View File

@ -28,5 +28,29 @@ description: Artifact commands argument_error.kcl
"object_id": "[uuid]",
"hidden": true
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
}
]

View File

@ -1,5 +1,5 @@
---
source: kcl/src/simulation_tests.rs
source: kcl-lib/src/simulation_tests.rs
description: Error from executing argument_error.kcl
---
KCL Type error

View File

@ -28,5 +28,29 @@ description: Artifact commands array_elem_pop.kcl
"object_id": "[uuid]",
"hidden": true
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
}
]

View File

@ -28,5 +28,29 @@ description: Artifact commands array_elem_pop_empty_fail.kcl
"object_id": "[uuid]",
"hidden": true
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
}
]

View File

@ -28,5 +28,29 @@ description: Artifact commands array_elem_pop_fail.kcl
"object_id": "[uuid]",
"hidden": true
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
}
]

View File

@ -28,5 +28,29 @@ description: Artifact commands array_elem_push.kcl
"object_id": "[uuid]",
"hidden": true
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
}
]

View File

@ -28,5 +28,29 @@ description: Artifact commands array_elem_push_fail.kcl
"object_id": "[uuid]",
"hidden": true
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
}
]

View File

@ -28,5 +28,29 @@ description: Artifact commands array_index_oob.kcl
"object_id": "[uuid]",
"hidden": true
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
}
]

View File

@ -28,5 +28,29 @@ description: Artifact commands array_range_expr.kcl
"object_id": "[uuid]",
"hidden": true
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
}
]

View File

@ -28,5 +28,29 @@ description: Artifact commands array_range_negative_expr.kcl
"object_id": "[uuid]",
"hidden": true
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
}
]

View File

@ -520,5 +520,29 @@ description: Artifact commands artifact_graph_example_code1.kcl
"edge_id": "[uuid]",
"face_id": "[uuid]"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
}
]

View File

@ -291,5 +291,29 @@ description: Artifact commands artifact_graph_example_code_no_3d.kcl
"angle_snap_increment": null
}
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
}
]

View File

@ -214,5 +214,29 @@ description: Artifact commands artifact_graph_example_code_offset_planes.kcl
"object_id": "[uuid]",
"hidden": true
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
}
]

View File

@ -881,5 +881,29 @@ description: Artifact commands artifact_graph_sketch_on_face_etc.kcl
"edge_id": "[uuid]",
"face_id": "[uuid]"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
}
]

View File

@ -37,6 +37,30 @@ description: Artifact commands assembly_mixed_units_cubes.kcl
"unit": "in"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
@ -602,13 +626,5 @@ description: Artifact commands assembly_mixed_units_cubes.kcl
"edge_id": "[uuid]",
"face_id": "[uuid]"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "in"
}
}
]

View File

@ -37,6 +37,30 @@ description: Artifact commands assembly_non_default_units.kcl
"unit": "in"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
@ -254,5 +278,13 @@ description: Artifact commands assembly_non_default_units.kcl
"type": "close_path",
"path_id": "[uuid]"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "in"
}
}
]

View File

@ -28,5 +28,29 @@ description: Artifact commands bad_units_in_annotation.kcl
"object_id": "[uuid]",
"hidden": true
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
}
]

View File

@ -320,5 +320,29 @@ description: Artifact commands basic_fillet_cube_close_opposite.kcl
"tolerance": 0.0000001,
"cut_type": "fillet"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
}
]

View File

@ -320,5 +320,29 @@ description: Artifact commands basic_fillet_cube_end.kcl
"tolerance": 0.0000001,
"cut_type": "fillet"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
}
]

View File

@ -308,5 +308,29 @@ description: Artifact commands basic_fillet_cube_next_adjacent.kcl
"tolerance": 0.0000001,
"cut_type": "fillet"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
}
]

View File

@ -308,5 +308,29 @@ description: Artifact commands basic_fillet_cube_previous_adjacent.kcl
"tolerance": 0.0000001,
"cut_type": "fillet"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
}
]

View File

@ -310,5 +310,29 @@ description: Artifact commands basic_fillet_cube_start.kcl
"tolerance": 0.0000001,
"cut_type": "fillet"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
}
]

View File

@ -249,5 +249,29 @@ description: Artifact commands big_number_angle_to_match_length_x.kcl
"edge_id": "[uuid]",
"face_id": "[uuid]"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
}
]

View File

@ -249,5 +249,29 @@ description: Artifact commands big_number_angle_to_match_length_y.kcl
"edge_id": "[uuid]",
"face_id": "[uuid]"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
}
]

View File

@ -28,5 +28,29 @@ description: Artifact commands boolean_logical_and.kcl
"object_id": "[uuid]",
"hidden": true
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
}
]

View File

@ -28,5 +28,29 @@ description: Artifact commands boolean_logical_multiple.kcl
"object_id": "[uuid]",
"hidden": true
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
}
]

View File

@ -28,5 +28,29 @@ description: Artifact commands boolean_logical_or.kcl
"object_id": "[uuid]",
"hidden": true
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
}
]

View File

@ -200,5 +200,29 @@ description: Artifact commands circle_three_point.kcl
"edge_id": "[uuid]",
"face_id": "[uuid]"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
}
]

View File

@ -618,5 +618,29 @@ description: Artifact commands circular_pattern3d_a_pattern.kcl
"arc_degrees": 360.0,
"rotate_duplicates": false
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
}
]

View File

@ -28,5 +28,29 @@ description: Artifact commands comparisons.kcl
"object_id": "[uuid]",
"hidden": true
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
}
]

View File

@ -28,5 +28,29 @@ description: Artifact commands comparisons_multiple.kcl
"object_id": "[uuid]",
"hidden": true
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
}
]

View File

@ -28,5 +28,29 @@ description: Artifact commands computed_var.kcl
"object_id": "[uuid]",
"hidden": true
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
}
]

View File

@ -1655,5 +1655,29 @@ description: Artifact commands crazy_multi_profile.kcl
"edge_id": "[uuid]",
"face_id": "[uuid]"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
}
]

View File

@ -303,5 +303,29 @@ description: Artifact commands cube.kcl
"edge_id": "[uuid]",
"face_id": "[uuid]"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
}
]

View File

@ -223,5 +223,29 @@ description: Artifact commands cube_with_error.kcl
"object_id": "[uuid]",
"edge_id": "[uuid]"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
}
]

View File

@ -28,5 +28,29 @@ description: Artifact commands double_map_fn.kcl
"object_id": "[uuid]",
"hidden": true
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
}
]

View File

@ -1830,5 +1830,29 @@ description: Artifact commands fillet-and-shell.kcl
"shell_thickness": 1.0,
"hollow": false
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
}
]

View File

@ -322,5 +322,29 @@ description: Artifact commands flush_batch_on_end.kcl
"edge_id": "[uuid]",
"face_id": "[uuid]"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
}
]

View File

@ -286,5 +286,29 @@ description: Artifact commands function_sketch.kcl
"edge_id": "[uuid]",
"face_id": "[uuid]"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
}
]

View File

@ -286,5 +286,29 @@ description: Artifact commands function_sketch_with_position.kcl
"edge_id": "[uuid]",
"face_id": "[uuid]"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
}
]

View File

@ -215,5 +215,29 @@ description: Artifact commands helix_ccw.kcl
"is_clockwise": false,
"length": 10.0
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
}
]

View File

@ -129,5 +129,29 @@ description: Artifact commands helix_simple.kcl
"is_clockwise": false,
"edge_id": "[uuid]"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
}
]

View File

@ -1433,5 +1433,29 @@ description: Artifact commands i_shape.kcl
"edge_id": "[uuid]",
"face_id": "[uuid]"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
}
]

View File

@ -28,5 +28,29 @@ description: Artifact commands if_else.kcl
"object_id": "[uuid]",
"hidden": true
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
}
]

View File

@ -28,5 +28,29 @@ description: Artifact commands import_constant.kcl
"object_id": "[uuid]",
"hidden": true
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
}
]

View File

@ -28,5 +28,29 @@ description: Artifact commands import_cycle1.kcl
"object_id": "[uuid]",
"hidden": true
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
}
]

View File

@ -28,5 +28,29 @@ description: Artifact commands import_export.kcl
"object_id": "[uuid]",
"hidden": true
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
}
]

View File

@ -28,5 +28,29 @@ description: Artifact commands import_file_not_exist_error.kcl
"object_id": "[uuid]",
"hidden": true
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
}
]

View File

@ -28,5 +28,29 @@ description: Artifact commands import_file_parse_error.kcl
"object_id": "[uuid]",
"hidden": true
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
}
]

View File

@ -3021,5 +3021,29 @@ description: Artifact commands import_foreign.kcl
"type": "gltf"
}
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
}
]

View File

@ -36,5 +36,434 @@ description: Artifact commands import_function_not_sketch.kcl
"type": "set_scene_units",
"unit": "in"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "make_plane",
"origin": {
"x": 0.0,
"y": 0.0,
"z": 0.0
},
"x_axis": {
"x": 1.0,
"y": 0.0,
"z": 0.0
},
"y_axis": {
"x": 0.0,
"y": 1.0,
"z": 0.0
},
"size": 60.0,
"clobber": false,
"hide": true
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "enable_sketch_mode",
"entity_id": "[uuid]",
"ortho": false,
"animated": false,
"adjust_camera": false,
"planar_normal": {
"x": 0.0,
"y": 0.0,
"z": 1.0
}
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "start_path"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "move_path_pen",
"path": "[uuid]",
"to": {
"x": 4.0,
"y": 12.0,
"z": 0.0
}
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "sketch_mode_disable"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "extend_path",
"path": "[uuid]",
"segment": {
"type": "line",
"end": {
"x": 2.0,
"y": 0.0,
"z": 0.0
},
"relative": true
}
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "extend_path",
"path": "[uuid]",
"segment": {
"type": "line",
"end": {
"x": 0.0,
"y": -6.0,
"z": 0.0
},
"relative": true
}
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "extend_path",
"path": "[uuid]",
"segment": {
"type": "line",
"end": {
"x": 4.0,
"y": -6.0,
"z": 0.0
},
"relative": true
}
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "extend_path",
"path": "[uuid]",
"segment": {
"type": "line",
"end": {
"x": 0.0,
"y": -6.0,
"z": 0.0
},
"relative": true
}
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "extend_path",
"path": "[uuid]",
"segment": {
"type": "line",
"end": {
"x": -3.75,
"y": -4.5,
"z": 0.0
},
"relative": true
}
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "extend_path",
"path": "[uuid]",
"segment": {
"type": "line",
"end": {
"x": 0.0,
"y": -5.5,
"z": 0.0
},
"relative": true
}
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "extend_path",
"path": "[uuid]",
"segment": {
"type": "line",
"end": {
"x": -2.0,
"y": 0.0,
"z": 0.0
},
"relative": true
}
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "close_path",
"path_id": "[uuid]"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "revolve",
"target": "[uuid]",
"origin": {
"x": 0.0,
"y": 0.0,
"z": 0.0
},
"axis": {
"x": 0.0,
"y": 1.0,
"z": 0.0
},
"axis_is_2d": true,
"angle": {
"unit": "degrees",
"value": 360.0
},
"tolerance": 0.0000001,
"opposite": "None"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "object_bring_to_front",
"object_id": "[uuid]"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "solid3d_get_extrusion_face_info",
"object_id": "[uuid]",
"edge_id": "[uuid]"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "solid3d_get_opposite_edge",
"object_id": "[uuid]",
"edge_id": "[uuid]",
"face_id": "[uuid]"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "solid3d_get_next_adjacent_edge",
"object_id": "[uuid]",
"edge_id": "[uuid]",
"face_id": "[uuid]"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "solid3d_get_opposite_edge",
"object_id": "[uuid]",
"edge_id": "[uuid]",
"face_id": "[uuid]"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "solid3d_get_next_adjacent_edge",
"object_id": "[uuid]",
"edge_id": "[uuid]",
"face_id": "[uuid]"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "solid3d_get_opposite_edge",
"object_id": "[uuid]",
"edge_id": "[uuid]",
"face_id": "[uuid]"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "solid3d_get_next_adjacent_edge",
"object_id": "[uuid]",
"edge_id": "[uuid]",
"face_id": "[uuid]"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "solid3d_get_opposite_edge",
"object_id": "[uuid]",
"edge_id": "[uuid]",
"face_id": "[uuid]"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "solid3d_get_next_adjacent_edge",
"object_id": "[uuid]",
"edge_id": "[uuid]",
"face_id": "[uuid]"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "solid3d_get_opposite_edge",
"object_id": "[uuid]",
"edge_id": "[uuid]",
"face_id": "[uuid]"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "solid3d_get_next_adjacent_edge",
"object_id": "[uuid]",
"edge_id": "[uuid]",
"face_id": "[uuid]"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "solid3d_get_opposite_edge",
"object_id": "[uuid]",
"edge_id": "[uuid]",
"face_id": "[uuid]"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "solid3d_get_next_adjacent_edge",
"object_id": "[uuid]",
"edge_id": "[uuid]",
"face_id": "[uuid]"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "solid3d_get_opposite_edge",
"object_id": "[uuid]",
"edge_id": "[uuid]",
"face_id": "[uuid]"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "solid3d_get_next_adjacent_edge",
"object_id": "[uuid]",
"edge_id": "[uuid]",
"face_id": "[uuid]"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "solid3d_get_opposite_edge",
"object_id": "[uuid]",
"edge_id": "[uuid]",
"face_id": "[uuid]"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "solid3d_get_next_adjacent_edge",
"object_id": "[uuid]",
"edge_id": "[uuid]",
"face_id": "[uuid]"
}
}
]

View File

@ -1,6 +1,5 @@
---
source: kcl/src/simulation_tests.rs
assertion_line: 189
source: kcl-lib/src/simulation_tests.rs
description: Artifact graph flowchart import_function_not_sketch.kcl
extension: md
snapshot_kind: binary

View File

@ -1,3 +1,82 @@
```mermaid
flowchart LR
subgraph path2 [Path]
2["Path<br>[75, 101, 5]"]
3["Segment<br>[107, 125, 5]"]
4["Segment<br>[131, 150, 5]"]
5["Segment<br>[156, 175, 5]"]
6["Segment<br>[181, 200, 5]"]
7["Segment<br>[206, 231, 5]"]
8["Segment<br>[237, 258, 5]"]
9["Segment<br>[264, 283, 5]"]
10["Segment<br>[289, 296, 5]"]
11[Solid2d]
end
1["Plane<br>[52, 69, 5]"]
12["Sweep Revolve<br>[302, 319, 5]"]
13[Wall]
14[Wall]
15[Wall]
16[Wall]
17[Wall]
18[Wall]
19[Wall]
20[Wall]
21["SweepEdge Adjacent"]
22["SweepEdge Adjacent"]
23["SweepEdge Adjacent"]
24["SweepEdge Adjacent"]
25["SweepEdge Adjacent"]
26["SweepEdge Adjacent"]
27["SweepEdge Adjacent"]
1 --- 2
2 --- 3
2 --- 4
2 --- 5
2 --- 6
2 --- 7
2 --- 8
2 --- 9
2 --- 10
2 ---- 12
2 --- 11
3 --- 13
3 x--> 21
4 --- 14
4 --- 21
5 --- 15
5 --- 22
6 --- 16
6 --- 23
7 --- 17
7 --- 24
8 --- 18
8 --- 25
9 --- 19
9 --- 26
10 --- 20
10 --- 27
12 --- 13
12 --- 14
12 --- 15
12 --- 16
12 --- 17
12 --- 18
12 --- 19
12 --- 20
12 <--x 3
12 --- 21
12 <--x 4
12 <--x 5
12 --- 22
12 <--x 6
12 --- 23
12 <--x 7
12 --- 24
12 <--x 8
12 --- 25
12 <--x 9
12 --- 26
12 <--x 10
12 --- 27
```

View File

@ -2,4 +2,106 @@
source: kcl-lib/src/simulation_tests.rs
description: Operations executed import_function_not_sketch.kcl
---
[]
[
{
"labeledArgs": {
"planeOrSolid": {
"value": {
"type": "Plane",
"artifact_id": "[uuid]"
},
"sourceRange": []
}
},
"name": "startSketchOn",
"sourceRange": [],
"type": "StdLibCall",
"unlabeledArg": null
},
{
"type": "KclStdLibCall",
"name": "revolve",
"unlabeledArg": {
"value": {
"type": "Sketch",
"value": {
"artifactId": "[uuid]"
}
},
"sourceRange": []
},
"labeledArgs": {
"axis": {
"value": {
"type": "Object",
"value": {
"direction": {
"type": "Array",
"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"
}
}
}
]
},
"origin": {
"type": "Array",
"value": [
{
"type": "Number",
"value": 0.0,
"ty": {
"type": "Default",
"len": {
"type": "Mm"
},
"angle": {
"type": "Degrees"
}
}
},
{
"type": "Number",
"value": 0.0,
"ty": {
"type": "Default",
"len": {
"type": "Mm"
},
"angle": {
"type": "Degrees"
}
}
}
]
}
}
},
"sourceRange": []
}
},
"sourceRange": []
}
]

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 99 KiB

View File

@ -28,5 +28,29 @@ description: Artifact commands import_glob.kcl
"object_id": "[uuid]",
"hidden": true
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
}
]

View File

@ -28,5 +28,130 @@ description: Artifact commands import_side_effect.kcl
"object_id": "[uuid]",
"hidden": true
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "make_plane",
"origin": {
"x": 0.0,
"y": 0.0,
"z": 0.0
},
"x_axis": {
"x": 1.0,
"y": 0.0,
"z": 0.0
},
"y_axis": {
"x": 0.0,
"y": 1.0,
"z": 0.0
},
"size": 60.0,
"clobber": false,
"hide": true
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "enable_sketch_mode",
"entity_id": "[uuid]",
"ortho": false,
"animated": false,
"adjust_camera": false,
"planar_normal": {
"x": 0.0,
"y": 0.0,
"z": 1.0
}
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "start_path"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "move_path_pen",
"path": "[uuid]",
"to": {
"x": 10.0,
"y": 0.0,
"z": 0.0
}
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "sketch_mode_disable"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "extend_path",
"path": "[uuid]",
"segment": {
"type": "arc",
"center": {
"x": 0.0,
"y": 0.0
},
"radius": 10.0,
"start": {
"unit": "degrees",
"value": 0.0
},
"end": {
"unit": "degrees",
"value": 360.0
},
"relative": false
}
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "close_path",
"path_id": "[uuid]"
}
}
]

View File

@ -1,6 +1,5 @@
---
source: kcl/src/simulation_tests.rs
assertion_line: 189
source: kcl-lib/src/simulation_tests.rs
description: Artifact graph flowchart import_side_effect.kcl
extension: md
snapshot_kind: binary

View File

@ -1,3 +1,12 @@
```mermaid
flowchart LR
subgraph path2 [Path]
2["Path<br>[102, 138, 5]"]
3["Segment<br>[102, 138, 5]"]
4[Solid2d]
end
1["Plane<br>[77, 96, 5]"]
1 --- 2
2 --- 3
2 --- 4
```

View File

@ -2,4 +2,20 @@
source: kcl-lib/src/simulation_tests.rs
description: Operations executed import_side_effect.kcl
---
[]
[
{
"labeledArgs": {
"planeOrSolid": {
"value": {
"type": "String",
"value": "XY"
},
"sourceRange": []
}
},
"name": "startSketchOn",
"sourceRange": [],
"type": "StdLibCall",
"unlabeledArg": null
}
]

View File

@ -5571162,5 +5571162,29 @@ description: Artifact commands import_transform.kcl
}
]
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
}
]

View File

@ -37,6 +37,54 @@ description: Artifact commands import_whole.kcl
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_object_transform",
"object_id": "[uuid]",
"transforms": [
{
"translate": {
"property": {
"x": 0.0,
"y": 0.0,
"z": 1.0
},
"set": false,
"is_local": true
},
"rotate_rpy": null,
"rotate_angle_axis": null,
"scale": null
}
]
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
@ -216,26 +264,5 @@ description: Artifact commands import_whole.kcl
"edge_id": "[uuid]",
"face_id": "[uuid]"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "solid3d_shell_face",
"object_id": "[uuid]",
"face_ids": [
"[uuid]"
],
"shell_thickness": 42.0,
"hollow": false
}
}
]

View File

@ -63,61 +63,21 @@ description: Result of parsing import_whole.kcl
"label": {
"commentStart": 0,
"end": 0,
"name": "faces",
"name": "z",
"start": 0,
"type": "Identifier"
},
"arg": {
"commentStart": 0,
"elements": [
{
"commentStart": 0,
"end": 0,
"raw": "'end'",
"raw": "1",
"start": 0,
"type": "Literal",
"type": "Literal",
"value": "end"
"value": {
"value": 1.0,
"suffix": "None"
}
],
"end": 0,
"start": 0,
"type": "ArrayExpression",
"type": "ArrayExpression"
}
},
{
"type": "LabeledArg",
"label": {
"commentStart": 0,
"end": 0,
"name": "thickness",
"start": 0,
"type": "Identifier"
},
"arg": {
"abs_path": false,
"commentStart": 0,
"end": 0,
"name": {
"commentStart": 0,
"end": 0,
"name": "thickness",
"start": 0,
"type": "Identifier"
},
"path": [
{
"commentStart": 0,
"end": 0,
"name": "foo",
"start": 0,
"type": "Identifier"
}
],
"start": 0,
"type": "Name",
"type": "Name"
}
}
],
@ -128,7 +88,7 @@ description: Result of parsing import_whole.kcl
"name": {
"commentStart": 0,
"end": 0,
"name": "shell",
"name": "translate",
"start": 0,
"type": "Identifier"
},

View File

@ -3,4 +3,4 @@
import "exported_mod.kcl" as foo
bar = foo
|> shell(faces = ['end'], thickness = foo::thickness)
|> translate(z=1)

View File

@ -61,49 +61,5 @@ description: Operations executed import_whole.kcl
},
{
"type": "GroupEnd"
},
{
"labeledArgs": {
"faces": {
"value": {
"type": "Array",
"value": [
{
"type": "String",
"value": "end"
}
]
},
"sourceRange": []
},
"thickness": {
"value": {
"type": "Number",
"value": 42.0,
"ty": {
"type": "Default",
"len": {
"type": "Inches"
},
"angle": {
"type": "Degrees"
}
}
},
"sourceRange": []
}
},
"name": "shell",
"sourceRange": [],
"type": "StdLibCall",
"unlabeledArg": {
"value": {
"type": "Solid",
"value": {
"artifactId": "[uuid]"
}
},
"sourceRange": []
}
}
]

View File

@ -7,4 +7,4 @@ description: Result of unparsing import_whole.kcl
import "exported_mod.kcl" as foo
bar = foo
|> shell(faces = [END], thickness = foo::thickness)
|> translate(z = 1)

View File

@ -28,5 +28,29 @@ description: Artifact commands index_of_array.kcl
"object_id": "[uuid]",
"hidden": true
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
}
]

View File

@ -580,5 +580,29 @@ description: Artifact commands intersect_cubes.kcl
],
"tolerance": 0.0000001
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
}
]

View File

@ -28,5 +28,29 @@ description: Artifact commands invalid_index_fractional.kcl
"object_id": "[uuid]",
"hidden": true
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
}
]

View File

@ -28,5 +28,29 @@ description: Artifact commands invalid_index_negative.kcl
"object_id": "[uuid]",
"hidden": true
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
}
]

View File

@ -28,5 +28,29 @@ description: Artifact commands invalid_index_str.kcl
"object_id": "[uuid]",
"hidden": true
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
}
]

View File

@ -28,5 +28,29 @@ description: Artifact commands invalid_member_object.kcl
"object_id": "[uuid]",
"hidden": true
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
},
{
"cmdId": "[uuid]",
"range": [],
"command": {
"type": "set_scene_units",
"unit": "mm"
}
}
]

Some files were not shown because too many files have changed in this diff Show More