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>
This commit is contained in:
Jess Frazelle
2024-06-25 10:35:48 -07:00
committed by GitHub
parent d7e36eed24
commit 8fe2d33063
17 changed files with 216 additions and 25 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 71 KiB

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 75 KiB

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 27 KiB

View File

@ -1383,7 +1383,7 @@ dependencies = [
[[package]] [[package]]
name = "kcl-lib" name = "kcl-lib"
version = "0.1.66" version = "0.1.67"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"approx", "approx",

View File

@ -1,7 +1,7 @@
[package] [package]
name = "kcl-lib" name = "kcl-lib"
description = "KittyCAD Language implementation and tools" description = "KittyCAD Language implementation and tools"
version = "0.1.66" version = "0.1.67"
edition = "2021" edition = "2021"
license = "MIT" license = "MIT"
repository = "https://github.com/KittyCAD/modeling-app" repository = "https://github.com/KittyCAD/modeling-app"

View File

@ -1232,28 +1232,34 @@ impl CallExpression {
source_ranges: vec![self.into()], source_ranges: vec![self.into()],
}) })
})?; })?;
let result = result.get_value()?;
let result = result.get_value()?;
Ok(result) Ok(result)
} }
FunctionKind::UserDefined => { FunctionKind::UserDefined => {
let func = memory.get(&fn_name, self.into())?; let func = memory.get(&fn_name, self.into())?;
let result = func let (result, global_memory_items) =
.call_fn(fn_args, memory.clone(), ctx.clone()) func.call_fn(fn_args, memory.clone(), ctx.clone()).await.map_err(|e| {
.await
.map_err(|e| {
// Add the call expression to the source ranges. // Add the call expression to the source ranges.
e.add_source_ranges(vec![self.into()]) e.add_source_ranges(vec![self.into()])
})? })?;
.ok_or_else(|| {
let result = result.ok_or_else(|| {
KclError::UndefinedValue(KclErrorDetails { KclError::UndefinedValue(KclErrorDetails {
message: format!("Result of user-defined function {} is undefined", fn_name), message: format!("Result of user-defined function {} is undefined", fn_name),
source_ranges: vec![self.into()], source_ranges: vec![self.into()],
}) })
})?; })?;
let result = result.get_value()?; 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) Ok(result)
} }
} }

View File

@ -100,6 +100,18 @@ impl ProgramMemory {
}) })
.collect() .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 { impl Default for ProgramMemory {
@ -525,14 +537,17 @@ impl std::hash::Hash for TagIdentifier {
} }
} }
pub type MemoryFunction = pub type MemoryFunction = fn(
fn(
s: Vec<MemoryItem>, s: Vec<MemoryItem>,
memory: ProgramMemory, memory: ProgramMemory,
expression: Box<FunctionExpression>, expression: Box<FunctionExpression>,
metadata: Vec<Metadata>, metadata: Vec<Metadata>,
ctx: ExecutorContext, ctx: 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,
>,
>;
fn force_memory_function< fn force_memory_function<
F: Fn( F: Fn(
@ -541,7 +556,12 @@ fn force_memory_function<
Box<FunctionExpression>, Box<FunctionExpression>,
Vec<Metadata>, Vec<Metadata>,
ExecutorContext, 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: F,
) -> F { ) -> F {
@ -686,7 +706,7 @@ impl MemoryItem {
args: Vec<MemoryItem>, args: Vec<MemoryItem>,
memory: ProgramMemory, memory: ProgramMemory,
ctx: ExecutorContext, ctx: ExecutorContext,
) -> Result<Option<ProgramReturn>, KclError> { ) -> Result<(Option<ProgramReturn>, HashMap<String, MemoryItem>), KclError> {
let MemoryItem::Function { func, expression, meta } = &self else { let MemoryItem::Function { func, expression, meta } = &self else {
return Err(KclError::Semantic(KclErrorDetails { return Err(KclError::Semantic(KclErrorDetails {
message: "not a in memory function".to_string(), message: "not a in memory function".to_string(),
@ -1500,7 +1520,16 @@ impl ExecutorContext {
} }
FunctionKind::UserDefined => { FunctionKind::UserDefined => {
if let Some(func) = memory.clone().root.get(&fn_name) { 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; memory.return_ = result;
} else { } else {
@ -1625,7 +1654,7 @@ impl ExecutorContext {
.inner_execute(function_expression.body.clone(), &mut fn_memory, BodyType::Block) .inner_execute(function_expression.body.clone(), &mut fn_memory, BodyType::Block)
.await?; .await?;
Ok(result.return_) Ok((result.return_, fn_memory.get_tags()))
}) })
}, },
); );

View 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, %)

View File

@ -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`" }"# 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);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 137 KiB