Fix lazy fillet (#3176)
* WIP: Fix lazy fillet * cleanup Signed-off-by: Jess Frazelle <github@jessfraz.com> --------- Signed-off-by: Jess Frazelle <github@jessfraz.com> Co-authored-by: Jess Frazelle <github@jessfraz.com> Co-authored-by: Jess Frazelle <jessfraz@users.noreply.github.com>
This commit is contained in:
@ -23,8 +23,8 @@ use crate::{
|
|||||||
docs::StdLibFn,
|
docs::StdLibFn,
|
||||||
errors::{KclError, KclErrorDetails},
|
errors::{KclError, KclErrorDetails},
|
||||||
executor::{
|
executor::{
|
||||||
BodyType, ExecutorContext, MemoryItem, Metadata, PipeInfo, ProgramMemory, SourceRange, StatementKind,
|
BodyType, DynamicState, ExecutorContext, MemoryItem, Metadata, PipeInfo, ProgramMemory, SourceRange,
|
||||||
TagEngineInfo, TagIdentifier, UserVal,
|
StatementKind, TagEngineInfo, TagIdentifier, UserVal,
|
||||||
},
|
},
|
||||||
parser::PIPE_OPERATOR,
|
parser::PIPE_OPERATOR,
|
||||||
std::{kcl_stdlib::KclStdLibFn, FunctionKind},
|
std::{kcl_stdlib::KclStdLibFn, FunctionKind},
|
||||||
@ -918,6 +918,7 @@ impl BinaryPart {
|
|||||||
pub async fn get_result(
|
pub async fn get_result(
|
||||||
&self,
|
&self,
|
||||||
memory: &mut ProgramMemory,
|
memory: &mut ProgramMemory,
|
||||||
|
dynamic_state: &DynamicState,
|
||||||
pipe_info: &PipeInfo,
|
pipe_info: &PipeInfo,
|
||||||
ctx: &ExecutorContext,
|
ctx: &ExecutorContext,
|
||||||
) -> Result<MemoryItem, KclError> {
|
) -> Result<MemoryItem, KclError> {
|
||||||
@ -928,10 +929,16 @@ impl BinaryPart {
|
|||||||
Ok(value.clone())
|
Ok(value.clone())
|
||||||
}
|
}
|
||||||
BinaryPart::BinaryExpression(binary_expression) => {
|
BinaryPart::BinaryExpression(binary_expression) => {
|
||||||
binary_expression.get_result(memory, pipe_info, ctx).await
|
binary_expression
|
||||||
|
.get_result(memory, dynamic_state, pipe_info, ctx)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
BinaryPart::CallExpression(call_expression) => {
|
||||||
|
call_expression.execute(memory, dynamic_state, pipe_info, ctx).await
|
||||||
|
}
|
||||||
|
BinaryPart::UnaryExpression(unary_expression) => {
|
||||||
|
unary_expression.get_result(memory, dynamic_state, pipe_info, ctx).await
|
||||||
}
|
}
|
||||||
BinaryPart::CallExpression(call_expression) => call_expression.execute(memory, pipe_info, ctx).await,
|
|
||||||
BinaryPart::UnaryExpression(unary_expression) => unary_expression.get_result(memory, pipe_info, ctx).await,
|
|
||||||
BinaryPart::MemberExpression(member_expression) => member_expression.get_result(memory),
|
BinaryPart::MemberExpression(member_expression) => member_expression.get_result(memory),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1311,6 +1318,7 @@ impl CallExpression {
|
|||||||
pub async fn execute(
|
pub async fn execute(
|
||||||
&self,
|
&self,
|
||||||
memory: &mut ProgramMemory,
|
memory: &mut ProgramMemory,
|
||||||
|
dynamic_state: &DynamicState,
|
||||||
pipe_info: &PipeInfo,
|
pipe_info: &PipeInfo,
|
||||||
ctx: &ExecutorContext,
|
ctx: &ExecutorContext,
|
||||||
) -> Result<MemoryItem, KclError> {
|
) -> Result<MemoryItem, KclError> {
|
||||||
@ -1323,7 +1331,14 @@ impl CallExpression {
|
|||||||
source_range: SourceRange([arg.start(), arg.end()]),
|
source_range: SourceRange([arg.start(), arg.end()]),
|
||||||
};
|
};
|
||||||
let result = ctx
|
let result = ctx
|
||||||
.arg_into_mem_item(arg, memory, pipe_info, &metadata, StatementKind::Expression)
|
.arg_into_mem_item(
|
||||||
|
arg,
|
||||||
|
memory,
|
||||||
|
dynamic_state,
|
||||||
|
pipe_info,
|
||||||
|
&metadata,
|
||||||
|
StatementKind::Expression,
|
||||||
|
)
|
||||||
.await?;
|
.await?;
|
||||||
fn_args.push(result);
|
fn_args.push(result);
|
||||||
}
|
}
|
||||||
@ -1331,7 +1346,8 @@ impl CallExpression {
|
|||||||
match ctx.stdlib.get_either(&self.callee.name) {
|
match ctx.stdlib.get_either(&self.callee.name) {
|
||||||
FunctionKind::Core(func) => {
|
FunctionKind::Core(func) => {
|
||||||
// Attempt to call the function.
|
// Attempt to call the function.
|
||||||
let args = crate::std::Args::new(fn_args, self.into(), ctx.clone(), memory.clone());
|
let args =
|
||||||
|
crate::std::Args::new(fn_args, self.into(), ctx.clone(), memory.clone(), dynamic_state.clone());
|
||||||
let mut result = func.std_lib_fn()(args).await?;
|
let mut result = func.std_lib_fn()(args).await?;
|
||||||
|
|
||||||
// If the return result is a sketch group or extrude group, we want to update the
|
// If the return result is a sketch group or extrude group, we want to update the
|
||||||
@ -1433,9 +1449,14 @@ impl CallExpression {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut fn_dynamic_state = dynamic_state.clone();
|
||||||
|
|
||||||
// Call the stdlib function
|
// Call the stdlib function
|
||||||
let p = func.function().clone().body;
|
let p = func.function().clone().body;
|
||||||
let results = match ctx.inner_execute(&p, &mut fn_memory, BodyType::Block).await {
|
let results = match ctx
|
||||||
|
.inner_execute(&p, &mut fn_memory, &mut fn_dynamic_state, BodyType::Block)
|
||||||
|
.await
|
||||||
|
{
|
||||||
Ok(results) => results,
|
Ok(results) => results,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
// We need to override the source ranges so we don't get the embedded kcl
|
// We need to override the source ranges so we don't get the embedded kcl
|
||||||
@ -1456,7 +1477,11 @@ impl CallExpression {
|
|||||||
}
|
}
|
||||||
FunctionKind::UserDefined => {
|
FunctionKind::UserDefined => {
|
||||||
let func = memory.get(&fn_name, self.into())?;
|
let func = memory.get(&fn_name, self.into())?;
|
||||||
let result = func.call_fn(fn_args, ctx.clone()).await.map_err(|e| {
|
let fn_dynamic_state = dynamic_state.merge(memory);
|
||||||
|
let result = func
|
||||||
|
.call_fn(fn_args, &fn_dynamic_state, ctx.clone())
|
||||||
|
.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()])
|
||||||
})?;
|
})?;
|
||||||
@ -2295,6 +2320,7 @@ impl ArrayExpression {
|
|||||||
pub async fn execute(
|
pub async fn execute(
|
||||||
&self,
|
&self,
|
||||||
memory: &mut ProgramMemory,
|
memory: &mut ProgramMemory,
|
||||||
|
dynamic_state: &DynamicState,
|
||||||
pipe_info: &PipeInfo,
|
pipe_info: &PipeInfo,
|
||||||
ctx: &ExecutorContext,
|
ctx: &ExecutorContext,
|
||||||
) -> Result<MemoryItem, KclError> {
|
) -> Result<MemoryItem, KclError> {
|
||||||
@ -2310,13 +2336,29 @@ impl ArrayExpression {
|
|||||||
value.clone()
|
value.clone()
|
||||||
}
|
}
|
||||||
Value::BinaryExpression(binary_expression) => {
|
Value::BinaryExpression(binary_expression) => {
|
||||||
binary_expression.get_result(memory, pipe_info, ctx).await?
|
binary_expression
|
||||||
|
.get_result(memory, dynamic_state, pipe_info, ctx)
|
||||||
|
.await?
|
||||||
|
}
|
||||||
|
Value::CallExpression(call_expression) => {
|
||||||
|
call_expression.execute(memory, dynamic_state, pipe_info, ctx).await?
|
||||||
|
}
|
||||||
|
Value::UnaryExpression(unary_expression) => {
|
||||||
|
unary_expression
|
||||||
|
.get_result(memory, dynamic_state, pipe_info, ctx)
|
||||||
|
.await?
|
||||||
|
}
|
||||||
|
Value::ObjectExpression(object_expression) => {
|
||||||
|
object_expression.execute(memory, dynamic_state, pipe_info, ctx).await?
|
||||||
|
}
|
||||||
|
Value::ArrayExpression(array_expression) => {
|
||||||
|
array_expression.execute(memory, dynamic_state, pipe_info, ctx).await?
|
||||||
|
}
|
||||||
|
Value::PipeExpression(pipe_expression) => {
|
||||||
|
pipe_expression
|
||||||
|
.get_result(memory, dynamic_state, pipe_info, ctx)
|
||||||
|
.await?
|
||||||
}
|
}
|
||||||
Value::CallExpression(call_expression) => call_expression.execute(memory, pipe_info, ctx).await?,
|
|
||||||
Value::UnaryExpression(unary_expression) => unary_expression.get_result(memory, pipe_info, ctx).await?,
|
|
||||||
Value::ObjectExpression(object_expression) => object_expression.execute(memory, pipe_info, ctx).await?,
|
|
||||||
Value::ArrayExpression(array_expression) => array_expression.execute(memory, pipe_info, ctx).await?,
|
|
||||||
Value::PipeExpression(pipe_expression) => pipe_expression.get_result(memory, pipe_info, ctx).await?,
|
|
||||||
Value::PipeSubstitution(pipe_substitution) => {
|
Value::PipeSubstitution(pipe_substitution) => {
|
||||||
return Err(KclError::Semantic(KclErrorDetails {
|
return Err(KclError::Semantic(KclErrorDetails {
|
||||||
message: format!("PipeSubstitution not implemented here: {:?}", pipe_substitution),
|
message: format!("PipeSubstitution not implemented here: {:?}", pipe_substitution),
|
||||||
@ -2465,6 +2507,7 @@ impl ObjectExpression {
|
|||||||
pub async fn execute(
|
pub async fn execute(
|
||||||
&self,
|
&self,
|
||||||
memory: &mut ProgramMemory,
|
memory: &mut ProgramMemory,
|
||||||
|
dynamic_state: &DynamicState,
|
||||||
pipe_info: &PipeInfo,
|
pipe_info: &PipeInfo,
|
||||||
ctx: &ExecutorContext,
|
ctx: &ExecutorContext,
|
||||||
) -> Result<MemoryItem, KclError> {
|
) -> Result<MemoryItem, KclError> {
|
||||||
@ -2479,13 +2522,29 @@ impl ObjectExpression {
|
|||||||
value.clone()
|
value.clone()
|
||||||
}
|
}
|
||||||
Value::BinaryExpression(binary_expression) => {
|
Value::BinaryExpression(binary_expression) => {
|
||||||
binary_expression.get_result(memory, pipe_info, ctx).await?
|
binary_expression
|
||||||
|
.get_result(memory, dynamic_state, pipe_info, ctx)
|
||||||
|
.await?
|
||||||
|
}
|
||||||
|
Value::CallExpression(call_expression) => {
|
||||||
|
call_expression.execute(memory, dynamic_state, pipe_info, ctx).await?
|
||||||
|
}
|
||||||
|
Value::UnaryExpression(unary_expression) => {
|
||||||
|
unary_expression
|
||||||
|
.get_result(memory, dynamic_state, pipe_info, ctx)
|
||||||
|
.await?
|
||||||
|
}
|
||||||
|
Value::ObjectExpression(object_expression) => {
|
||||||
|
object_expression.execute(memory, dynamic_state, pipe_info, ctx).await?
|
||||||
|
}
|
||||||
|
Value::ArrayExpression(array_expression) => {
|
||||||
|
array_expression.execute(memory, dynamic_state, pipe_info, ctx).await?
|
||||||
|
}
|
||||||
|
Value::PipeExpression(pipe_expression) => {
|
||||||
|
pipe_expression
|
||||||
|
.get_result(memory, dynamic_state, pipe_info, ctx)
|
||||||
|
.await?
|
||||||
}
|
}
|
||||||
Value::CallExpression(call_expression) => call_expression.execute(memory, pipe_info, ctx).await?,
|
|
||||||
Value::UnaryExpression(unary_expression) => unary_expression.get_result(memory, pipe_info, ctx).await?,
|
|
||||||
Value::ObjectExpression(object_expression) => object_expression.execute(memory, pipe_info, ctx).await?,
|
|
||||||
Value::ArrayExpression(array_expression) => array_expression.execute(memory, pipe_info, ctx).await?,
|
|
||||||
Value::PipeExpression(pipe_expression) => pipe_expression.get_result(memory, pipe_info, ctx).await?,
|
|
||||||
Value::MemberExpression(member_expression) => member_expression.get_result(memory)?,
|
Value::MemberExpression(member_expression) => member_expression.get_result(memory)?,
|
||||||
Value::PipeSubstitution(pipe_substitution) => {
|
Value::PipeSubstitution(pipe_substitution) => {
|
||||||
return Err(KclError::Semantic(KclErrorDetails {
|
return Err(KclError::Semantic(KclErrorDetails {
|
||||||
@ -2947,11 +3006,20 @@ impl BinaryExpression {
|
|||||||
pub async fn get_result(
|
pub async fn get_result(
|
||||||
&self,
|
&self,
|
||||||
memory: &mut ProgramMemory,
|
memory: &mut ProgramMemory,
|
||||||
|
dynamic_state: &DynamicState,
|
||||||
pipe_info: &PipeInfo,
|
pipe_info: &PipeInfo,
|
||||||
ctx: &ExecutorContext,
|
ctx: &ExecutorContext,
|
||||||
) -> Result<MemoryItem, KclError> {
|
) -> Result<MemoryItem, KclError> {
|
||||||
let left_json_value = self.left.get_result(memory, pipe_info, ctx).await?.get_json_value()?;
|
let left_json_value = self
|
||||||
let right_json_value = self.right.get_result(memory, pipe_info, ctx).await?.get_json_value()?;
|
.left
|
||||||
|
.get_result(memory, dynamic_state, pipe_info, ctx)
|
||||||
|
.await?
|
||||||
|
.get_json_value()?;
|
||||||
|
let right_json_value = self
|
||||||
|
.right
|
||||||
|
.get_result(memory, dynamic_state, pipe_info, ctx)
|
||||||
|
.await?
|
||||||
|
.get_json_value()?;
|
||||||
|
|
||||||
// First check if we are doing string concatenation.
|
// First check if we are doing string concatenation.
|
||||||
if self.operator == BinaryOperator::Add {
|
if self.operator == BinaryOperator::Add {
|
||||||
@ -3156,13 +3224,14 @@ impl UnaryExpression {
|
|||||||
pub async fn get_result(
|
pub async fn get_result(
|
||||||
&self,
|
&self,
|
||||||
memory: &mut ProgramMemory,
|
memory: &mut ProgramMemory,
|
||||||
|
dynamic_state: &DynamicState,
|
||||||
pipe_info: &PipeInfo,
|
pipe_info: &PipeInfo,
|
||||||
ctx: &ExecutorContext,
|
ctx: &ExecutorContext,
|
||||||
) -> Result<MemoryItem, KclError> {
|
) -> Result<MemoryItem, KclError> {
|
||||||
let num = parse_json_number_as_f64(
|
let num = parse_json_number_as_f64(
|
||||||
&self
|
&self
|
||||||
.argument
|
.argument
|
||||||
.get_result(memory, pipe_info, ctx)
|
.get_result(memory, dynamic_state, pipe_info, ctx)
|
||||||
.await?
|
.await?
|
||||||
.get_json_value()?,
|
.get_json_value()?,
|
||||||
self.into(),
|
self.into(),
|
||||||
@ -3333,10 +3402,11 @@ impl PipeExpression {
|
|||||||
pub async fn get_result(
|
pub async fn get_result(
|
||||||
&self,
|
&self,
|
||||||
memory: &mut ProgramMemory,
|
memory: &mut ProgramMemory,
|
||||||
|
dynamic_state: &DynamicState,
|
||||||
pipe_info: &PipeInfo,
|
pipe_info: &PipeInfo,
|
||||||
ctx: &ExecutorContext,
|
ctx: &ExecutorContext,
|
||||||
) -> Result<MemoryItem, KclError> {
|
) -> Result<MemoryItem, KclError> {
|
||||||
execute_pipe_body(memory, &self.body, pipe_info, self.into(), ctx).await
|
execute_pipe_body(memory, dynamic_state, &self.body, pipe_info, self.into(), ctx).await
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Rename all identifiers that have the old name to the new given name.
|
/// Rename all identifiers that have the old name to the new given name.
|
||||||
@ -3350,6 +3420,7 @@ impl PipeExpression {
|
|||||||
#[async_recursion::async_recursion]
|
#[async_recursion::async_recursion]
|
||||||
async fn execute_pipe_body(
|
async fn execute_pipe_body(
|
||||||
memory: &mut ProgramMemory,
|
memory: &mut ProgramMemory,
|
||||||
|
dynamic_state: &DynamicState,
|
||||||
body: &[Value],
|
body: &[Value],
|
||||||
pipe_info: &PipeInfo,
|
pipe_info: &PipeInfo,
|
||||||
source_range: SourceRange,
|
source_range: SourceRange,
|
||||||
@ -3370,7 +3441,14 @@ async fn execute_pipe_body(
|
|||||||
source_range: SourceRange([first.start(), first.end()]),
|
source_range: SourceRange([first.start(), first.end()]),
|
||||||
};
|
};
|
||||||
let output = ctx
|
let output = ctx
|
||||||
.arg_into_mem_item(first, memory, pipe_info, &meta, StatementKind::Expression)
|
.arg_into_mem_item(
|
||||||
|
first,
|
||||||
|
memory,
|
||||||
|
dynamic_state,
|
||||||
|
pipe_info,
|
||||||
|
&meta,
|
||||||
|
StatementKind::Expression,
|
||||||
|
)
|
||||||
.await?;
|
.await?;
|
||||||
// Now that we've evaluated the first child expression in the pipeline, following child expressions
|
// Now that we've evaluated the first child expression in the pipeline, following child expressions
|
||||||
// should use the previous child expression for %.
|
// should use the previous child expression for %.
|
||||||
@ -3381,9 +3459,15 @@ async fn execute_pipe_body(
|
|||||||
for expression in body {
|
for expression in body {
|
||||||
let output = match expression {
|
let output = match expression {
|
||||||
Value::BinaryExpression(binary_expression) => {
|
Value::BinaryExpression(binary_expression) => {
|
||||||
binary_expression.get_result(memory, &new_pipe_info, ctx).await?
|
binary_expression
|
||||||
|
.get_result(memory, dynamic_state, &new_pipe_info, ctx)
|
||||||
|
.await?
|
||||||
|
}
|
||||||
|
Value::CallExpression(call_expression) => {
|
||||||
|
call_expression
|
||||||
|
.execute(memory, dynamic_state, &new_pipe_info, ctx)
|
||||||
|
.await?
|
||||||
}
|
}
|
||||||
Value::CallExpression(call_expression) => call_expression.execute(memory, &new_pipe_info, ctx).await?,
|
|
||||||
Value::Identifier(identifier) => memory.get(&identifier.name, identifier.into())?.clone(),
|
Value::Identifier(identifier) => memory.get(&identifier.name, identifier.into())?.clone(),
|
||||||
_ => {
|
_ => {
|
||||||
// Return an error this should not happen.
|
// Return an error this should not happen.
|
||||||
|
@ -195,6 +195,50 @@ impl Environment {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Dynamic state that depends on the dynamic flow of the program, like the call
|
||||||
|
/// stack. If the language had exceptions, for example, you could store the
|
||||||
|
/// stack of exception handlers here.
|
||||||
|
#[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, ts_rs::TS, JsonSchema)]
|
||||||
|
pub struct DynamicState {
|
||||||
|
pub extrude_group_ids: Vec<ExtrudeGroupLazyIds>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DynamicState {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self::default()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn merge(&self, memory: &ProgramMemory) -> Self {
|
||||||
|
let mut merged = self.clone();
|
||||||
|
merged.append(memory);
|
||||||
|
merged
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn append(&mut self, memory: &ProgramMemory) {
|
||||||
|
for env in &memory.environments {
|
||||||
|
for item in env.bindings.values() {
|
||||||
|
if let MemoryItem::ExtrudeGroup(eg) = item {
|
||||||
|
self.extrude_group_ids.push(ExtrudeGroupLazyIds::from(eg.as_ref()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn fillet_or_chamfer_ids_on_sketch_group(&self, sketch_group_id: uuid::Uuid) -> Vec<uuid::Uuid> {
|
||||||
|
self.extrude_group_ids
|
||||||
|
.iter()
|
||||||
|
.flat_map(|eg| {
|
||||||
|
if eg.sketch_group_id == sketch_group_id {
|
||||||
|
eg.fillet_or_chamfers.clone()
|
||||||
|
} else {
|
||||||
|
Vec::new()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
|
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
|
||||||
#[ts(export)]
|
#[ts(export)]
|
||||||
#[serde(rename_all = "camelCase", untagged)]
|
#[serde(rename_all = "camelCase", untagged)]
|
||||||
@ -623,6 +667,7 @@ pub type MemoryFunction =
|
|||||||
memory: ProgramMemory,
|
memory: ProgramMemory,
|
||||||
expression: Box<FunctionExpression>,
|
expression: Box<FunctionExpression>,
|
||||||
metadata: Vec<Metadata>,
|
metadata: Vec<Metadata>,
|
||||||
|
dynamic_state: DynamicState,
|
||||||
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>, KclError>> + Send>>;
|
||||||
|
|
||||||
@ -632,6 +677,7 @@ fn force_memory_function<
|
|||||||
ProgramMemory,
|
ProgramMemory,
|
||||||
Box<FunctionExpression>,
|
Box<FunctionExpression>,
|
||||||
Vec<Metadata>,
|
Vec<Metadata>,
|
||||||
|
DynamicState,
|
||||||
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>, KclError>> + Send>>,
|
||||||
>(
|
>(
|
||||||
@ -800,6 +846,7 @@ impl MemoryItem {
|
|||||||
pub async fn call_fn(
|
pub async fn call_fn(
|
||||||
&self,
|
&self,
|
||||||
args: Vec<MemoryItem>,
|
args: Vec<MemoryItem>,
|
||||||
|
dynamic_state: &DynamicState,
|
||||||
ctx: ExecutorContext,
|
ctx: ExecutorContext,
|
||||||
) -> Result<Option<ProgramReturn>, KclError> {
|
) -> Result<Option<ProgramReturn>, KclError> {
|
||||||
let MemoryItem::Function {
|
let MemoryItem::Function {
|
||||||
@ -825,6 +872,7 @@ impl MemoryItem {
|
|||||||
closure_memory.as_ref().clone(),
|
closure_memory.as_ref().clone(),
|
||||||
expression.clone(),
|
expression.clone(),
|
||||||
meta.clone(),
|
meta.clone(),
|
||||||
|
dynamic_state.clone(),
|
||||||
ctx,
|
ctx,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
@ -997,6 +1045,27 @@ impl ExtrudeGroup {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An extrude group ID and its fillet and chamfer IDs. This is needed for lazy
|
||||||
|
/// fillet evaluation.
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize, ts_rs::TS, JsonSchema)]
|
||||||
|
pub struct ExtrudeGroupLazyIds {
|
||||||
|
pub extrude_group_id: uuid::Uuid,
|
||||||
|
pub sketch_group_id: uuid::Uuid,
|
||||||
|
/// Chamfers or fillets on this extrude group.
|
||||||
|
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||||
|
pub fillet_or_chamfers: Vec<uuid::Uuid>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&ExtrudeGroup> for ExtrudeGroupLazyIds {
|
||||||
|
fn from(eg: &ExtrudeGroup) -> Self {
|
||||||
|
Self {
|
||||||
|
extrude_group_id: eg.id,
|
||||||
|
sketch_group_id: eg.sketch_group.id,
|
||||||
|
fillet_or_chamfers: eg.fillet_or_chamfers.iter().map(|foc| foc.id()).collect(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A fillet or a chamfer.
|
/// A fillet or a chamfer.
|
||||||
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
|
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
|
||||||
#[ts(export)]
|
#[ts(export)]
|
||||||
@ -1621,7 +1690,13 @@ impl ExecutorContext {
|
|||||||
} else {
|
} else {
|
||||||
Default::default()
|
Default::default()
|
||||||
};
|
};
|
||||||
self.inner_execute(program, &mut memory, crate::executor::BodyType::Root)
|
let mut dynamic_state = DynamicState::default();
|
||||||
|
self.inner_execute(
|
||||||
|
program,
|
||||||
|
&mut memory,
|
||||||
|
&mut dynamic_state,
|
||||||
|
crate::executor::BodyType::Root,
|
||||||
|
)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1631,6 +1706,7 @@ impl ExecutorContext {
|
|||||||
&self,
|
&self,
|
||||||
program: &crate::ast::types::Program,
|
program: &crate::ast::types::Program,
|
||||||
memory: &mut ProgramMemory,
|
memory: &mut ProgramMemory,
|
||||||
|
dynamic_state: &mut DynamicState,
|
||||||
body_type: BodyType,
|
body_type: BodyType,
|
||||||
) -> Result<ProgramMemory, KclError> {
|
) -> Result<ProgramMemory, KclError> {
|
||||||
let pipe_info = PipeInfo::default();
|
let pipe_info = PipeInfo::default();
|
||||||
@ -1640,9 +1716,9 @@ impl ExecutorContext {
|
|||||||
match statement {
|
match statement {
|
||||||
BodyItem::ExpressionStatement(expression_statement) => {
|
BodyItem::ExpressionStatement(expression_statement) => {
|
||||||
if let Value::PipeExpression(pipe_expr) = &expression_statement.expression {
|
if let Value::PipeExpression(pipe_expr) = &expression_statement.expression {
|
||||||
pipe_expr.get_result(memory, &pipe_info, self).await?;
|
pipe_expr.get_result(memory, dynamic_state, &pipe_info, self).await?;
|
||||||
} else if let Value::CallExpression(call_expr) = &expression_statement.expression {
|
} else if let Value::CallExpression(call_expr) = &expression_statement.expression {
|
||||||
call_expr.execute(memory, &pipe_info, self).await?;
|
call_expr.execute(memory, dynamic_state, &pipe_info, self).await?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BodyItem::VariableDeclaration(variable_declaration) => {
|
BodyItem::VariableDeclaration(variable_declaration) => {
|
||||||
@ -1655,6 +1731,7 @@ impl ExecutorContext {
|
|||||||
.arg_into_mem_item(
|
.arg_into_mem_item(
|
||||||
&declaration.init,
|
&declaration.init,
|
||||||
memory,
|
memory,
|
||||||
|
dynamic_state,
|
||||||
&pipe_info,
|
&pipe_info,
|
||||||
&metadata,
|
&metadata,
|
||||||
StatementKind::Declaration { name: &var_name },
|
StatementKind::Declaration { name: &var_name },
|
||||||
@ -1665,11 +1742,11 @@ impl ExecutorContext {
|
|||||||
}
|
}
|
||||||
BodyItem::ReturnStatement(return_statement) => match &return_statement.argument {
|
BodyItem::ReturnStatement(return_statement) => match &return_statement.argument {
|
||||||
Value::BinaryExpression(bin_expr) => {
|
Value::BinaryExpression(bin_expr) => {
|
||||||
let result = bin_expr.get_result(memory, &pipe_info, self).await?;
|
let result = bin_expr.get_result(memory, dynamic_state, &pipe_info, self).await?;
|
||||||
memory.return_ = Some(ProgramReturn::Value(result));
|
memory.return_ = Some(ProgramReturn::Value(result));
|
||||||
}
|
}
|
||||||
Value::UnaryExpression(unary_expr) => {
|
Value::UnaryExpression(unary_expr) => {
|
||||||
let result = unary_expr.get_result(memory, &pipe_info, self).await?;
|
let result = unary_expr.get_result(memory, dynamic_state, &pipe_info, self).await?;
|
||||||
memory.return_ = Some(ProgramReturn::Value(result));
|
memory.return_ = Some(ProgramReturn::Value(result));
|
||||||
}
|
}
|
||||||
Value::Identifier(identifier) => {
|
Value::Identifier(identifier) => {
|
||||||
@ -1683,15 +1760,15 @@ impl ExecutorContext {
|
|||||||
memory.return_ = Some(ProgramReturn::Value(tag.into()));
|
memory.return_ = Some(ProgramReturn::Value(tag.into()));
|
||||||
}
|
}
|
||||||
Value::ArrayExpression(array_expr) => {
|
Value::ArrayExpression(array_expr) => {
|
||||||
let result = array_expr.execute(memory, &pipe_info, self).await?;
|
let result = array_expr.execute(memory, dynamic_state, &pipe_info, self).await?;
|
||||||
memory.return_ = Some(ProgramReturn::Value(result));
|
memory.return_ = Some(ProgramReturn::Value(result));
|
||||||
}
|
}
|
||||||
Value::ObjectExpression(obj_expr) => {
|
Value::ObjectExpression(obj_expr) => {
|
||||||
let result = obj_expr.execute(memory, &pipe_info, self).await?;
|
let result = obj_expr.execute(memory, dynamic_state, &pipe_info, self).await?;
|
||||||
memory.return_ = Some(ProgramReturn::Value(result));
|
memory.return_ = Some(ProgramReturn::Value(result));
|
||||||
}
|
}
|
||||||
Value::CallExpression(call_expr) => {
|
Value::CallExpression(call_expr) => {
|
||||||
let result = call_expr.execute(memory, &pipe_info, self).await?;
|
let result = call_expr.execute(memory, dynamic_state, &pipe_info, self).await?;
|
||||||
memory.return_ = Some(ProgramReturn::Value(result));
|
memory.return_ = Some(ProgramReturn::Value(result));
|
||||||
}
|
}
|
||||||
Value::MemberExpression(member_expr) => {
|
Value::MemberExpression(member_expr) => {
|
||||||
@ -1699,7 +1776,7 @@ impl ExecutorContext {
|
|||||||
memory.return_ = Some(ProgramReturn::Value(result));
|
memory.return_ = Some(ProgramReturn::Value(result));
|
||||||
}
|
}
|
||||||
Value::PipeExpression(pipe_expr) => {
|
Value::PipeExpression(pipe_expr) => {
|
||||||
let result = pipe_expr.get_result(memory, &pipe_info, self).await?;
|
let result = pipe_expr.get_result(memory, dynamic_state, &pipe_info, self).await?;
|
||||||
memory.return_ = Some(ProgramReturn::Value(result));
|
memory.return_ = Some(ProgramReturn::Value(result));
|
||||||
}
|
}
|
||||||
Value::PipeSubstitution(_) => {}
|
Value::PipeSubstitution(_) => {}
|
||||||
@ -1730,6 +1807,7 @@ impl ExecutorContext {
|
|||||||
&self,
|
&self,
|
||||||
init: &Value,
|
init: &Value,
|
||||||
memory: &mut ProgramMemory,
|
memory: &mut ProgramMemory,
|
||||||
|
dynamic_state: &DynamicState,
|
||||||
pipe_info: &PipeInfo,
|
pipe_info: &PipeInfo,
|
||||||
metadata: &Metadata,
|
metadata: &Metadata,
|
||||||
statement_kind: StatementKind<'a>,
|
statement_kind: StatementKind<'a>,
|
||||||
@ -1742,13 +1820,18 @@ impl ExecutorContext {
|
|||||||
let value = memory.get(&identifier.name, identifier.into())?;
|
let value = memory.get(&identifier.name, identifier.into())?;
|
||||||
value.clone()
|
value.clone()
|
||||||
}
|
}
|
||||||
Value::BinaryExpression(binary_expression) => binary_expression.get_result(memory, pipe_info, self).await?,
|
Value::BinaryExpression(binary_expression) => {
|
||||||
|
binary_expression
|
||||||
|
.get_result(memory, dynamic_state, pipe_info, self)
|
||||||
|
.await?
|
||||||
|
}
|
||||||
Value::FunctionExpression(function_expression) => {
|
Value::FunctionExpression(function_expression) => {
|
||||||
let mem_func = force_memory_function(
|
let mem_func = force_memory_function(
|
||||||
|args: Vec<MemoryItem>,
|
|args: Vec<MemoryItem>,
|
||||||
memory: ProgramMemory,
|
memory: ProgramMemory,
|
||||||
function_expression: Box<FunctionExpression>,
|
function_expression: Box<FunctionExpression>,
|
||||||
_metadata: Vec<Metadata>,
|
_metadata: Vec<Metadata>,
|
||||||
|
mut dynamic_state: DynamicState,
|
||||||
ctx: ExecutorContext| {
|
ctx: ExecutorContext| {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
// Create a new environment to execute the function
|
// Create a new environment to execute the function
|
||||||
@ -1762,7 +1845,12 @@ impl ExecutorContext {
|
|||||||
let mut fn_memory = assign_args_to_params(&function_expression, args, body_memory)?;
|
let mut fn_memory = assign_args_to_params(&function_expression, args, body_memory)?;
|
||||||
|
|
||||||
let result = ctx
|
let result = ctx
|
||||||
.inner_execute(&function_expression.body, &mut fn_memory, BodyType::Block)
|
.inner_execute(
|
||||||
|
&function_expression.body,
|
||||||
|
&mut fn_memory,
|
||||||
|
&mut dynamic_state,
|
||||||
|
BodyType::Block,
|
||||||
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
Ok(result.return_)
|
Ok(result.return_)
|
||||||
@ -1779,8 +1867,14 @@ impl ExecutorContext {
|
|||||||
memory: Box::new(memory.clone()),
|
memory: Box::new(memory.clone()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Value::CallExpression(call_expression) => call_expression.execute(memory, pipe_info, self).await?,
|
Value::CallExpression(call_expression) => {
|
||||||
Value::PipeExpression(pipe_expression) => pipe_expression.get_result(memory, pipe_info, self).await?,
|
call_expression.execute(memory, dynamic_state, pipe_info, self).await?
|
||||||
|
}
|
||||||
|
Value::PipeExpression(pipe_expression) => {
|
||||||
|
pipe_expression
|
||||||
|
.get_result(memory, dynamic_state, pipe_info, self)
|
||||||
|
.await?
|
||||||
|
}
|
||||||
Value::PipeSubstitution(pipe_substitution) => match statement_kind {
|
Value::PipeSubstitution(pipe_substitution) => match statement_kind {
|
||||||
StatementKind::Declaration { name } => {
|
StatementKind::Declaration { name } => {
|
||||||
let message = format!(
|
let message = format!(
|
||||||
@ -1802,10 +1896,20 @@ impl ExecutorContext {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Value::ArrayExpression(array_expression) => array_expression.execute(memory, pipe_info, self).await?,
|
Value::ArrayExpression(array_expression) => {
|
||||||
Value::ObjectExpression(object_expression) => object_expression.execute(memory, pipe_info, self).await?,
|
array_expression.execute(memory, dynamic_state, pipe_info, self).await?
|
||||||
|
}
|
||||||
|
Value::ObjectExpression(object_expression) => {
|
||||||
|
object_expression
|
||||||
|
.execute(memory, dynamic_state, pipe_info, self)
|
||||||
|
.await?
|
||||||
|
}
|
||||||
Value::MemberExpression(member_expression) => member_expression.get_result(memory)?,
|
Value::MemberExpression(member_expression) => member_expression.get_result(memory)?,
|
||||||
Value::UnaryExpression(unary_expression) => unary_expression.get_result(memory, pipe_info, self).await?,
|
Value::UnaryExpression(unary_expression) => {
|
||||||
|
unary_expression
|
||||||
|
.get_result(memory, dynamic_state, pipe_info, self)
|
||||||
|
.await?
|
||||||
|
}
|
||||||
};
|
};
|
||||||
Ok(item)
|
Ok(item)
|
||||||
}
|
}
|
||||||
|
@ -3,13 +3,14 @@ use schemars::JsonSchema;
|
|||||||
use crate::{
|
use crate::{
|
||||||
ast::types::FunctionExpression,
|
ast::types::FunctionExpression,
|
||||||
errors::KclError,
|
errors::KclError,
|
||||||
executor::{ExecutorContext, MemoryFunction, MemoryItem, Metadata, ProgramMemory, ProgramReturn},
|
executor::{DynamicState, ExecutorContext, MemoryFunction, MemoryItem, Metadata, ProgramMemory, ProgramReturn},
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A function being used as a parameter into a stdlib function.
|
/// A function being used as a parameter into a stdlib function.
|
||||||
pub struct FunctionParam<'a> {
|
pub struct FunctionParam<'a> {
|
||||||
pub inner: &'a MemoryFunction,
|
pub inner: &'a MemoryFunction,
|
||||||
pub memory: ProgramMemory,
|
pub memory: ProgramMemory,
|
||||||
|
pub dynamic_state: DynamicState,
|
||||||
pub fn_expr: Box<FunctionExpression>,
|
pub fn_expr: Box<FunctionExpression>,
|
||||||
pub meta: Vec<Metadata>,
|
pub meta: Vec<Metadata>,
|
||||||
pub ctx: ExecutorContext,
|
pub ctx: ExecutorContext,
|
||||||
@ -22,6 +23,7 @@ impl<'a> FunctionParam<'a> {
|
|||||||
self.memory.clone(),
|
self.memory.clone(),
|
||||||
self.fn_expr.clone(),
|
self.fn_expr.clone(),
|
||||||
self.meta.clone(),
|
self.meta.clone(),
|
||||||
|
self.dynamic_state.clone(),
|
||||||
self.ctx.clone(),
|
self.ctx.clone(),
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
|
@ -8,8 +8,8 @@ use crate::{
|
|||||||
ast::types::{parse_json_number_as_f64, TagDeclarator},
|
ast::types::{parse_json_number_as_f64, TagDeclarator},
|
||||||
errors::{KclError, KclErrorDetails},
|
errors::{KclError, KclErrorDetails},
|
||||||
executor::{
|
executor::{
|
||||||
ExecutorContext, ExtrudeGroup, ExtrudeGroupSet, ExtrudeSurface, MemoryItem, Metadata, ProgramMemory,
|
DynamicState, ExecutorContext, ExtrudeGroup, ExtrudeGroupSet, ExtrudeSurface, MemoryItem, Metadata,
|
||||||
SketchGroup, SketchGroupSet, SketchSurface, SourceRange, TagIdentifier,
|
ProgramMemory, SketchGroup, SketchGroupSet, SketchSurface, SourceRange, TagIdentifier,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -19,6 +19,7 @@ pub struct Args {
|
|||||||
pub source_range: SourceRange,
|
pub source_range: SourceRange,
|
||||||
pub ctx: ExecutorContext,
|
pub ctx: ExecutorContext,
|
||||||
pub current_program_memory: ProgramMemory,
|
pub current_program_memory: ProgramMemory,
|
||||||
|
pub dynamic_state: DynamicState,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Args {
|
impl Args {
|
||||||
@ -27,12 +28,14 @@ impl Args {
|
|||||||
source_range: SourceRange,
|
source_range: SourceRange,
|
||||||
ctx: ExecutorContext,
|
ctx: ExecutorContext,
|
||||||
current_program_memory: ProgramMemory,
|
current_program_memory: ProgramMemory,
|
||||||
|
dynamic_state: DynamicState,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
args,
|
args,
|
||||||
source_range,
|
source_range,
|
||||||
ctx,
|
ctx,
|
||||||
current_program_memory,
|
current_program_memory,
|
||||||
|
dynamic_state,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,6 +133,10 @@ impl Args {
|
|||||||
.iter()
|
.iter()
|
||||||
.flat_map(|eg| eg.get_all_fillet_or_chamfer_ids()),
|
.flat_map(|eg| eg.get_all_fillet_or_chamfer_ids()),
|
||||||
);
|
);
|
||||||
|
ids.extend(
|
||||||
|
self.dynamic_state
|
||||||
|
.fillet_or_chamfer_ids_on_sketch_group(sketch_group_id),
|
||||||
|
);
|
||||||
traversed_sketch_groups.push(sketch_group_id);
|
traversed_sketch_groups.push(sketch_group_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,6 +88,7 @@ pub async fn pattern_transform(args: Args) -> Result<MemoryItem, KclError> {
|
|||||||
meta: vec![args.source_range.into()],
|
meta: vec![args.source_range.into()],
|
||||||
ctx: args.ctx.clone(),
|
ctx: args.ctx.clone(),
|
||||||
memory: *transform.memory,
|
memory: *transform.memory,
|
||||||
|
dynamic_state: args.dynamic_state.clone(),
|
||||||
},
|
},
|
||||||
extr,
|
extr,
|
||||||
&args,
|
&args,
|
||||||
|
@ -24,7 +24,7 @@ const plumbus1 =
|
|||||||
|> extrude(plumbusLen, %)
|
|> extrude(plumbusLen, %)
|
||||||
|> fillet({
|
|> fillet({
|
||||||
radius: 5,
|
radius: 5,
|
||||||
tags: [c1.tags.arc_tag, getOppositeEdge(c1.tags.arc_tag)]
|
tags: [c1.tags.arc_tag]
|
||||||
}, %)
|
}, %)
|
||||||
const c2 = circl(200, a)
|
const c2 = circl(200, a)
|
||||||
const plumbus0 =
|
const plumbus0 =
|
||||||
@ -32,7 +32,7 @@ const plumbus0 =
|
|||||||
|> extrude(plumbusLen, %)
|
|> extrude(plumbusLen, %)
|
||||||
|> fillet({
|
|> fillet({
|
||||||
radius: 5,
|
radius: 5,
|
||||||
tags: [c2.tags.arc_tag, getOppositeEdge(c2.tags.arc_tag)]
|
tags: [c2.tags.arc_tag]
|
||||||
}, %)
|
}, %)
|
||||||
|
|
||||||
|
|
||||||
|
@ -97,7 +97,6 @@ async fn serial_test_pipe_as_arg() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
#[ignore] // We need to figure out why this broke even using scoped tags isn't working.
|
|
||||||
async fn serial_test_pentagon_fillet_sugar() {
|
async fn serial_test_pentagon_fillet_sugar() {
|
||||||
let code = include_str!("inputs/pentagon_fillet_sugar.kcl");
|
let code = include_str!("inputs/pentagon_fillet_sugar.kcl");
|
||||||
let result = execute_and_snapshot(code, UnitLength::Cm).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Cm).await.unwrap();
|
||||||
@ -1701,7 +1700,6 @@ const part002 = startSketchOn(part001, 'end')
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
#[ignore] // We need to figure out why this broke even using scoped tags isn't working.
|
|
||||||
async fn serial_test_plumbus_fillets() {
|
async fn serial_test_plumbus_fillets() {
|
||||||
let code = r#"fn make_circle = (ext, face, pos, radius) => {
|
let code = r#"fn make_circle = (ext, face, pos, radius) => {
|
||||||
const sg = startSketchOn(ext, face)
|
const sg = startSketchOn(ext, face)
|
||||||
@ -1748,7 +1746,7 @@ const plumbus0 = circle0
|
|||||||
|> extrude(10, %)
|
|> extrude(10, %)
|
||||||
|> fillet({
|
|> fillet({
|
||||||
radius: 0.5,
|
radius: 0.5,
|
||||||
tags: [circle0.tags.arc1, getOppositeEdge(circle0.tags.arc1)]
|
tags: [circle0.tags.arc1]
|
||||||
}, %)
|
}, %)
|
||||||
|
|
||||||
const circle1 = make_circle(p, p.sketchGroup.tags.b, [0, 0], 2.5)
|
const circle1 = make_circle(p, p.sketchGroup.tags.b, [0, 0], 2.5)
|
||||||
@ -1756,7 +1754,7 @@ const plumbus1 = circle1
|
|||||||
|> extrude(10, %)
|
|> extrude(10, %)
|
||||||
|> fillet({
|
|> fillet({
|
||||||
radius: 0.5,
|
radius: 0.5,
|
||||||
tags: [circle1.tags.arc1, getOppositeEdge(circle1.tags.arc1)]
|
tags: [circle1.tags.arc1]
|
||||||
}, %)
|
}, %)
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 95 KiB After Width: | Height: | Size: 95 KiB |
Binary file not shown.
Before Width: | Height: | Size: 132 KiB After Width: | Height: | Size: 131 KiB |
Reference in New Issue
Block a user