tags are globals (#2795)
* tags are globals Signed-off-by: Jess Frazelle <github@jessfraz.com> * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * empty * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> --------- Signed-off-by: Jess Frazelle <github@jessfraz.com> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 42 KiB |
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 44 KiB |
Before Width: | Height: | Size: 71 KiB After Width: | Height: | Size: 42 KiB |
Before Width: | Height: | Size: 75 KiB After Width: | Height: | Size: 60 KiB |
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 29 KiB |
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 33 KiB |
Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 27 KiB |
2
src/wasm-lib/Cargo.lock
generated
@ -1383,7 +1383,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kcl-lib"
|
||||
version = "0.1.66"
|
||||
version = "0.1.67"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"approx",
|
||||
|
@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "kcl-lib"
|
||||
description = "KittyCAD Language implementation and tools"
|
||||
version = "0.1.66"
|
||||
version = "0.1.67"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
repository = "https://github.com/KittyCAD/modeling-app"
|
||||
|
@ -1232,28 +1232,34 @@ impl CallExpression {
|
||||
source_ranges: vec![self.into()],
|
||||
})
|
||||
})?;
|
||||
let result = result.get_value()?;
|
||||
|
||||
let result = result.get_value()?;
|
||||
Ok(result)
|
||||
}
|
||||
FunctionKind::UserDefined => {
|
||||
let func = memory.get(&fn_name, self.into())?;
|
||||
let result = func
|
||||
.call_fn(fn_args, memory.clone(), ctx.clone())
|
||||
.await
|
||||
.map_err(|e| {
|
||||
let (result, global_memory_items) =
|
||||
func.call_fn(fn_args, memory.clone(), ctx.clone()).await.map_err(|e| {
|
||||
// Add the call expression to the source ranges.
|
||||
e.add_source_ranges(vec![self.into()])
|
||||
})?
|
||||
.ok_or_else(|| {
|
||||
KclError::UndefinedValue(KclErrorDetails {
|
||||
message: format!("Result of user-defined function {} is undefined", fn_name),
|
||||
source_ranges: vec![self.into()],
|
||||
})
|
||||
})?;
|
||||
|
||||
let result = result.ok_or_else(|| {
|
||||
KclError::UndefinedValue(KclErrorDetails {
|
||||
message: format!("Result of user-defined function {} is undefined", fn_name),
|
||||
source_ranges: vec![self.into()],
|
||||
})
|
||||
})?;
|
||||
let result = result.get_value()?;
|
||||
|
||||
// Add the global memory items to the memory.
|
||||
for (key, item) in global_memory_items {
|
||||
// We don't care about errors here because any collisions
|
||||
// would happened in the function call itself and already
|
||||
// errored out.
|
||||
memory.add(&key, item, self.into()).unwrap_or_default();
|
||||
}
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
|
@ -100,6 +100,18 @@ impl ProgramMemory {
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Get all TagDeclarators and TagIdentifiers in the memory.
|
||||
pub fn get_tags(&self) -> HashMap<String, MemoryItem> {
|
||||
self.root
|
||||
.values()
|
||||
.filter_map(|item| match item {
|
||||
MemoryItem::TagDeclarator(t) => Some((t.name.to_string(), item.clone())),
|
||||
MemoryItem::TagIdentifier(t) => Some((t.value.to_string(), item.clone())),
|
||||
_ => None,
|
||||
})
|
||||
.collect::<HashMap<String, MemoryItem>>()
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for ProgramMemory {
|
||||
@ -525,14 +537,17 @@ impl std::hash::Hash for TagIdentifier {
|
||||
}
|
||||
}
|
||||
|
||||
pub type MemoryFunction =
|
||||
fn(
|
||||
s: Vec<MemoryItem>,
|
||||
memory: ProgramMemory,
|
||||
expression: Box<FunctionExpression>,
|
||||
metadata: Vec<Metadata>,
|
||||
ctx: ExecutorContext,
|
||||
) -> std::pin::Pin<Box<dyn std::future::Future<Output = Result<Option<ProgramReturn>, KclError>> + Send>>;
|
||||
pub type MemoryFunction = fn(
|
||||
s: Vec<MemoryItem>,
|
||||
memory: ProgramMemory,
|
||||
expression: Box<FunctionExpression>,
|
||||
metadata: Vec<Metadata>,
|
||||
ctx: ExecutorContext,
|
||||
) -> std::pin::Pin<
|
||||
Box<
|
||||
dyn std::future::Future<Output = Result<(Option<ProgramReturn>, HashMap<String, MemoryItem>), KclError>> + Send,
|
||||
>,
|
||||
>;
|
||||
|
||||
fn force_memory_function<
|
||||
F: Fn(
|
||||
@ -541,7 +556,12 @@ fn force_memory_function<
|
||||
Box<FunctionExpression>,
|
||||
Vec<Metadata>,
|
||||
ExecutorContext,
|
||||
) -> std::pin::Pin<Box<dyn std::future::Future<Output = Result<Option<ProgramReturn>, KclError>> + Send>>,
|
||||
) -> std::pin::Pin<
|
||||
Box<
|
||||
dyn std::future::Future<Output = Result<(Option<ProgramReturn>, HashMap<String, MemoryItem>), KclError>>
|
||||
+ Send,
|
||||
>,
|
||||
>,
|
||||
>(
|
||||
f: F,
|
||||
) -> F {
|
||||
@ -686,7 +706,7 @@ impl MemoryItem {
|
||||
args: Vec<MemoryItem>,
|
||||
memory: ProgramMemory,
|
||||
ctx: ExecutorContext,
|
||||
) -> Result<Option<ProgramReturn>, KclError> {
|
||||
) -> Result<(Option<ProgramReturn>, HashMap<String, MemoryItem>), KclError> {
|
||||
let MemoryItem::Function { func, expression, meta } = &self else {
|
||||
return Err(KclError::Semantic(KclErrorDetails {
|
||||
message: "not a in memory function".to_string(),
|
||||
@ -1500,7 +1520,16 @@ impl ExecutorContext {
|
||||
}
|
||||
FunctionKind::UserDefined => {
|
||||
if let Some(func) = memory.clone().root.get(&fn_name) {
|
||||
let result = func.call_fn(args.clone(), memory.clone(), self.clone()).await?;
|
||||
let (result, global_memory_items) =
|
||||
func.call_fn(args.clone(), memory.clone(), self.clone()).await?;
|
||||
|
||||
// Add the global memory items to the memory.
|
||||
for (key, item) in global_memory_items {
|
||||
// We don't care about errors here because any collisions
|
||||
// would happened in the function call itself and already
|
||||
// errored out.
|
||||
memory.add(&key, item, call_expr.into()).unwrap_or_default();
|
||||
}
|
||||
|
||||
memory.return_ = result;
|
||||
} else {
|
||||
@ -1625,7 +1654,7 @@ impl ExecutorContext {
|
||||
.inner_execute(function_expression.body.clone(), &mut fn_memory, BodyType::Block)
|
||||
.await?;
|
||||
|
||||
Ok(result.return_)
|
||||
Ok((result.return_, fn_memory.get_tags()))
|
||||
})
|
||||
},
|
||||
);
|
||||
|
149
src/wasm-lib/tests/executor/inputs/global-tags.kcl
Normal file
@ -0,0 +1,149 @@
|
||||
// A mounting bracket for the Focusrite Scarlett Solo audio interface
|
||||
// This is a bracket that holds an audio device underneath a desk or shelf. The audio device has dimensions of 144mm wide, 80mm length and 45mm depth with fillets of 6mm. This mounting bracket is designed to be 3D printed with PLA material
|
||||
|
||||
// define constants in mm
|
||||
const radius = 6.0
|
||||
const width = 144.0
|
||||
const length = 80.0
|
||||
const depth = 45.0
|
||||
const thk = 4
|
||||
const holeDiam = 5
|
||||
const tabLength = 25
|
||||
const tabWidth = 12
|
||||
const tabThk = 4
|
||||
|
||||
// define a rectangular shape func
|
||||
fn rectShape = (pos, w, l) => {
|
||||
const rr = startSketchOn('xy')
|
||||
|> startProfileAt([pos[0] - (w / 2), pos[1] - (l / 2)], %)
|
||||
|> lineTo([pos[0] + w / 2, pos[1] - (l / 2)], %, "edge01")
|
||||
|> lineTo([pos[0] + w / 2, pos[1] + l / 2], %, "edge02")
|
||||
|> lineTo([pos[0] - (w / 2), pos[1] + l / 2], %, "edge03")
|
||||
|> close(%, "edge04")
|
||||
return rr
|
||||
}
|
||||
|
||||
// define the bracket plane
|
||||
const bracketPlane = {
|
||||
plane: {
|
||||
origin: { x: 0, y: length / 2 + thk, z: 0 },
|
||||
x_axis: { x: 1, y: 0, z: 0 },
|
||||
y_axis: { x: 0, y: 0, z: 1 },
|
||||
z_axis: { x: 0, y: -1, z: 0 }
|
||||
}
|
||||
}
|
||||
|
||||
// build the bracket sketch around the body
|
||||
fn bracketSketch = (w, d, t) => {
|
||||
const s = startSketchOn(bracketPlane)
|
||||
|> startProfileAt([-w / 2 - t, d + t], %)
|
||||
|> lineTo([-w / 2 - t, -t], %, "edge1")
|
||||
|> lineTo([w / 2 + t, -t], %, "edge2")
|
||||
|> lineTo([w / 2 + t, d + t], %, "edge3")
|
||||
|> lineTo([w / 2, d + t], %, "edge4")
|
||||
|> lineTo([w / 2, 0], %, "edge5")
|
||||
|> lineTo([-w / 2, 0], %, "edge6")
|
||||
|> lineTo([-w / 2, d + t], %, "edge7")
|
||||
|> close(%, "edge8")
|
||||
return s
|
||||
}
|
||||
|
||||
// build the body of the bracket
|
||||
const bracketBody = bracketSketch(width, depth, thk)
|
||||
|> extrude(length + 2 * thk, %)
|
||||
|> fillet({
|
||||
radius: radius,
|
||||
tags: [
|
||||
getNextAdjacentEdge("edge7", %),
|
||||
getNextAdjacentEdge("edge2", %),
|
||||
getNextAdjacentEdge("edge3", %),
|
||||
getNextAdjacentEdge("edge6", %)
|
||||
]
|
||||
}, %)
|
||||
|
||||
// define the tab plane
|
||||
const tabPlane = {
|
||||
plane: {
|
||||
origin: { x: 0, y: 0, z: depth + thk },
|
||||
x_axis: { x: 1, y: 0, z: 0 },
|
||||
y_axis: { x: 0, y: 1, z: 0 },
|
||||
z_axis: { x: 0, y: 0, z: 1 }
|
||||
}
|
||||
}
|
||||
|
||||
// build the tabs of the mounting bracket (right side)
|
||||
const tabsR = startSketchOn(tabPlane)
|
||||
|> startProfileAt([width / 2 + thk, length / 2 + thk], %)
|
||||
|> line([tabWidth, -tabLength / 3], %, "edge11")
|
||||
|> line([0, -tabLength / 3 * 2], %, "edge12")
|
||||
|> line([-tabWidth, -tabLength / 3], %, "edge13")
|
||||
|> close(%, "edge14")
|
||||
|> hole(circle([
|
||||
width / 2 + thk + tabWidth / 2,
|
||||
length / 2 + thk - (tabLength / (3 / 2))
|
||||
], holeDiam / 2, %), %)
|
||||
|> extrude(-tabThk, %)
|
||||
|> fillet({
|
||||
radius: holeDiam / 2,
|
||||
tags: [
|
||||
getNextAdjacentEdge("edge12", %),
|
||||
getNextAdjacentEdge("edge13", %)
|
||||
]
|
||||
}, %)
|
||||
|> patternLinear3d({
|
||||
axis: [0, -1, 0],
|
||||
repetitions: 1,
|
||||
distance: length + 2 * thk - (tabLength * 4 / 3)
|
||||
}, %)
|
||||
|
||||
// build the tabs of the mounting bracket (left side)
|
||||
const tabsL = startSketchOn(tabPlane)
|
||||
|> startProfileAt([-width / 2 - thk, length / 2 + thk], %)
|
||||
|> line([-tabWidth, -tabLength / 3], %, "edge21")
|
||||
|> line([0, -tabLength / 3 * 2], %, "edge22")
|
||||
|> line([tabWidth, -tabLength / 3], %, "edge23")
|
||||
|> close(%, "edge24")
|
||||
|> hole(circle([
|
||||
-width / 2 - thk - (tabWidth / 2),
|
||||
length / 2 + thk - (tabLength / (3 / 2))
|
||||
], holeDiam / 2, %), %)
|
||||
|> extrude(-tabThk, %)
|
||||
|> fillet({
|
||||
radius: holeDiam / 2,
|
||||
tags: [
|
||||
getNextAdjacentEdge("edge21", %),
|
||||
getNextAdjacentEdge("edge22", %)
|
||||
]
|
||||
}, %)
|
||||
|> patternLinear3d({
|
||||
axis: [0, -1, 0],
|
||||
repetitions: 1,
|
||||
distance: length + 2 * thk - (tabLength * 4 / 3)
|
||||
}, %)
|
||||
|
||||
// define a plane for retention bumps
|
||||
const retPlane = {
|
||||
plane: {
|
||||
origin: { x: -width / 2 + 20, y: 0, z: 0 },
|
||||
x_axis: { x: 0, y: 1, z: 0 },
|
||||
y_axis: { x: 0, y: 0, z: 1 },
|
||||
z_axis: { x: 1, y: 0, z: 0 }
|
||||
}
|
||||
}
|
||||
|
||||
// build the retention bump in the front
|
||||
const retFront = startSketchOn(retPlane)
|
||||
|> startProfileAt([-length / 2 - thk, 0], %)
|
||||
|> line([0, thk], %)
|
||||
|> line([thk, -thk], %)
|
||||
|> close(%)
|
||||
|> extrude(width - 40, %)
|
||||
|
||||
// build the retention bump in the back
|
||||
const retBack = startSketchOn(retPlane)
|
||||
|> startProfileAt([length / 2 + thk, 0], %)
|
||||
|> line([0, thk], %)
|
||||
|> line([-thk, 0], %)
|
||||
|> line([0, -thk], %)
|
||||
|> close(%)
|
||||
|> extrude(width - 40, %)
|
@ -2457,3 +2457,10 @@ let p = triangle(200)
|
||||
r#"value already defined: KclErrorDetails { source_ranges: [SourceRange([317, 319]), SourceRange([332, 345])], message: "Cannot redefine `a`" }"#
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
async fn serial_test_global_tags() {
|
||||
let code = include_str!("inputs/global-tags.kcl");
|
||||
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||
twenty_twenty::assert_image("tests/executor/outputs/global_tags.png", &result, 0.999);
|
||||
}
|
||||
|
BIN
src/wasm-lib/tests/executor/outputs/global_tags.png
Normal file
After Width: | Height: | Size: 137 KiB |