Unify execution state into a single struct (#3877)
* Add ExecState that combines ProgramMemory and DynamicState * Remove unneeded clones * Add exec_state parameter to all KCL stdlib functions * Move pipe value into ExecState * Add test for pipe substitution not leaking into function calls * KCL: Better message on assertEqual function Also add a new no-visual test for performance testing. * Fix new array module to use ExecState --------- Co-authored-by: Adam Chalmers <adam.chalmers@zoo.dev>
This commit is contained in:
@ -269,7 +269,7 @@ fn do_stdlib_inner(
|
||||
let ty_string = rust_type_to_openapi_type(&ty_string);
|
||||
let required = !ty_ident.to_string().starts_with("Option <");
|
||||
|
||||
if ty_string != "Args" {
|
||||
if ty_string != "ExecState" && ty_string != "Args" {
|
||||
let schema = if ty_ident.to_string().starts_with("Vec < ")
|
||||
|| ty_ident.to_string().starts_with("Option <")
|
||||
|| ty_ident.to_string().starts_with('[')
|
||||
@ -387,11 +387,12 @@ fn do_stdlib_inner(
|
||||
#const_struct
|
||||
|
||||
fn #boxed_fn_name_ident(
|
||||
exec_state: &mut crate::executor::ExecState,
|
||||
args: crate::std::Args,
|
||||
) -> std::pin::Pin<
|
||||
Box<dyn std::future::Future<Output = anyhow::Result<crate::executor::KclValue, crate::errors::KclError>> + Send>,
|
||||
Box<dyn std::future::Future<Output = anyhow::Result<crate::executor::KclValue, crate::errors::KclError>> + Send + '_>,
|
||||
> {
|
||||
Box::pin(#fn_name_ident(args))
|
||||
Box::pin(#fn_name_ident(exec_state, args))
|
||||
}
|
||||
|
||||
impl #docs_crate::StdLibFn for #name_ident
|
||||
@ -662,6 +663,9 @@ fn clean_ty_string(t: &str) -> (String, proc_macro2::TokenStream) {
|
||||
.replace("mut", "")
|
||||
.replace("< 'a >", "")
|
||||
.replace(' ', "");
|
||||
if ty_string.starts_with("ExecState") {
|
||||
ty_string = "ExecState".to_string();
|
||||
}
|
||||
if ty_string.starts_with("Args") {
|
||||
ty_string = "Args".to_string();
|
||||
}
|
||||
|
@ -85,6 +85,32 @@ fn test_args_with_lifetime() {
|
||||
expectorate::assert_contents("tests/args_with_lifetime.gen", &get_text_fmt(&item).unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_args_with_exec_state() {
|
||||
let (item, mut errors) = do_stdlib(
|
||||
quote! {
|
||||
name = "someFunction",
|
||||
},
|
||||
quote! {
|
||||
/// Docs
|
||||
/// ```
|
||||
/// someFunction()
|
||||
/// ```
|
||||
fn inner_some_function<'a>(
|
||||
exec_state: &mut ExecState,
|
||||
args: &Args,
|
||||
) -> i32 {
|
||||
3
|
||||
}
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
if let Some(e) = errors.pop() {
|
||||
panic!("{e}");
|
||||
}
|
||||
expectorate::assert_contents("tests/test_args_with_exec_state.gen", &get_text_fmt(&item).unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_stdlib_line_to() {
|
||||
let (item, errors) = do_stdlib(
|
||||
|
@ -44,15 +44,17 @@ pub(crate) struct SomeFn {}
|
||||
#[doc = "Std lib function: someFn\nDocs"]
|
||||
pub(crate) const SomeFn: SomeFn = SomeFn {};
|
||||
fn boxed_someFn(
|
||||
exec_state: &mut crate::executor::ExecState,
|
||||
args: crate::std::Args,
|
||||
) -> std::pin::Pin<
|
||||
Box<
|
||||
dyn std::future::Future<
|
||||
Output = anyhow::Result<crate::executor::KclValue, crate::errors::KclError>,
|
||||
> + Send,
|
||||
> + Send
|
||||
+ '_,
|
||||
>,
|
||||
> {
|
||||
Box::pin(someFn(args))
|
||||
Box::pin(someFn(exec_state, args))
|
||||
}
|
||||
|
||||
impl crate::docs::StdLibFn for SomeFn {
|
||||
|
@ -44,15 +44,17 @@ pub(crate) struct SomeFn {}
|
||||
#[doc = "Std lib function: someFn\nDocs"]
|
||||
pub(crate) const SomeFn: SomeFn = SomeFn {};
|
||||
fn boxed_someFn(
|
||||
exec_state: &mut crate::executor::ExecState,
|
||||
args: crate::std::Args,
|
||||
) -> std::pin::Pin<
|
||||
Box<
|
||||
dyn std::future::Future<
|
||||
Output = anyhow::Result<crate::executor::KclValue, crate::errors::KclError>,
|
||||
> + Send,
|
||||
> + Send
|
||||
+ '_,
|
||||
>,
|
||||
> {
|
||||
Box::pin(someFn(args))
|
||||
Box::pin(someFn(exec_state, args))
|
||||
}
|
||||
|
||||
impl crate::docs::StdLibFn for SomeFn {
|
||||
|
@ -77,15 +77,17 @@ pub(crate) struct Show {}
|
||||
#[doc = "Std lib function: show\nThis is some function.\nIt does shit."]
|
||||
pub(crate) const Show: Show = Show {};
|
||||
fn boxed_show(
|
||||
exec_state: &mut crate::executor::ExecState,
|
||||
args: crate::std::Args,
|
||||
) -> std::pin::Pin<
|
||||
Box<
|
||||
dyn std::future::Future<
|
||||
Output = anyhow::Result<crate::executor::KclValue, crate::errors::KclError>,
|
||||
> + Send,
|
||||
> + Send
|
||||
+ '_,
|
||||
>,
|
||||
> {
|
||||
Box::pin(show(args))
|
||||
Box::pin(show(exec_state, args))
|
||||
}
|
||||
|
||||
impl crate::docs::StdLibFn for Show {
|
||||
|
@ -44,15 +44,17 @@ pub(crate) struct Show {}
|
||||
#[doc = "Std lib function: show\nThis is some function.\nIt does shit."]
|
||||
pub(crate) const Show: Show = Show {};
|
||||
fn boxed_show(
|
||||
exec_state: &mut crate::executor::ExecState,
|
||||
args: crate::std::Args,
|
||||
) -> std::pin::Pin<
|
||||
Box<
|
||||
dyn std::future::Future<
|
||||
Output = anyhow::Result<crate::executor::KclValue, crate::errors::KclError>,
|
||||
> + Send,
|
||||
> + Send
|
||||
+ '_,
|
||||
>,
|
||||
> {
|
||||
Box::pin(show(args))
|
||||
Box::pin(show(exec_state, args))
|
||||
}
|
||||
|
||||
impl crate::docs::StdLibFn for Show {
|
||||
|
@ -78,15 +78,17 @@ pub(crate) struct MyFunc {}
|
||||
#[doc = "Std lib function: myFunc\nThis is some function.\nIt does shit."]
|
||||
pub(crate) const MyFunc: MyFunc = MyFunc {};
|
||||
fn boxed_my_func(
|
||||
exec_state: &mut crate::executor::ExecState,
|
||||
args: crate::std::Args,
|
||||
) -> std::pin::Pin<
|
||||
Box<
|
||||
dyn std::future::Future<
|
||||
Output = anyhow::Result<crate::executor::KclValue, crate::errors::KclError>,
|
||||
> + Send,
|
||||
> + Send
|
||||
+ '_,
|
||||
>,
|
||||
> {
|
||||
Box::pin(my_func(args))
|
||||
Box::pin(my_func(exec_state, args))
|
||||
}
|
||||
|
||||
impl crate::docs::StdLibFn for MyFunc {
|
||||
|
@ -78,15 +78,17 @@ pub(crate) struct LineTo {}
|
||||
#[doc = "Std lib function: lineTo\nThis is some function.\nIt does shit."]
|
||||
pub(crate) const LineTo: LineTo = LineTo {};
|
||||
fn boxed_line_to(
|
||||
exec_state: &mut crate::executor::ExecState,
|
||||
args: crate::std::Args,
|
||||
) -> std::pin::Pin<
|
||||
Box<
|
||||
dyn std::future::Future<
|
||||
Output = anyhow::Result<crate::executor::KclValue, crate::errors::KclError>,
|
||||
> + Send,
|
||||
> + Send
|
||||
+ '_,
|
||||
>,
|
||||
> {
|
||||
Box::pin(line_to(args))
|
||||
Box::pin(line_to(exec_state, args))
|
||||
}
|
||||
|
||||
impl crate::docs::StdLibFn for LineTo {
|
||||
|
@ -77,15 +77,17 @@ pub(crate) struct Min {}
|
||||
#[doc = "Std lib function: min\nThis is some function.\nIt does shit."]
|
||||
pub(crate) const Min: Min = Min {};
|
||||
fn boxed_min(
|
||||
exec_state: &mut crate::executor::ExecState,
|
||||
args: crate::std::Args,
|
||||
) -> std::pin::Pin<
|
||||
Box<
|
||||
dyn std::future::Future<
|
||||
Output = anyhow::Result<crate::executor::KclValue, crate::errors::KclError>,
|
||||
> + Send,
|
||||
> + Send
|
||||
+ '_,
|
||||
>,
|
||||
> {
|
||||
Box::pin(min(args))
|
||||
Box::pin(min(exec_state, args))
|
||||
}
|
||||
|
||||
impl crate::docs::StdLibFn for Min {
|
||||
|
@ -44,15 +44,17 @@ pub(crate) struct Show {}
|
||||
#[doc = "Std lib function: show\nThis is some function.\nIt does shit."]
|
||||
pub(crate) const Show: Show = Show {};
|
||||
fn boxed_show(
|
||||
exec_state: &mut crate::executor::ExecState,
|
||||
args: crate::std::Args,
|
||||
) -> std::pin::Pin<
|
||||
Box<
|
||||
dyn std::future::Future<
|
||||
Output = anyhow::Result<crate::executor::KclValue, crate::errors::KclError>,
|
||||
> + Send,
|
||||
> + Send
|
||||
+ '_,
|
||||
>,
|
||||
> {
|
||||
Box::pin(show(args))
|
||||
Box::pin(show(exec_state, args))
|
||||
}
|
||||
|
||||
impl crate::docs::StdLibFn for Show {
|
||||
|
@ -44,15 +44,17 @@ pub(crate) struct Import {}
|
||||
#[doc = "Std lib function: import\nThis is some function.\nIt does shit."]
|
||||
pub(crate) const Import: Import = Import {};
|
||||
fn boxed_import(
|
||||
exec_state: &mut crate::executor::ExecState,
|
||||
args: crate::std::Args,
|
||||
) -> std::pin::Pin<
|
||||
Box<
|
||||
dyn std::future::Future<
|
||||
Output = anyhow::Result<crate::executor::KclValue, crate::errors::KclError>,
|
||||
> + Send,
|
||||
> + Send
|
||||
+ '_,
|
||||
>,
|
||||
> {
|
||||
Box::pin(import(args))
|
||||
Box::pin(import(exec_state, args))
|
||||
}
|
||||
|
||||
impl crate::docs::StdLibFn for Import {
|
||||
|
@ -44,15 +44,17 @@ pub(crate) struct Import {}
|
||||
#[doc = "Std lib function: import\nThis is some function.\nIt does shit."]
|
||||
pub(crate) const Import: Import = Import {};
|
||||
fn boxed_import(
|
||||
exec_state: &mut crate::executor::ExecState,
|
||||
args: crate::std::Args,
|
||||
) -> std::pin::Pin<
|
||||
Box<
|
||||
dyn std::future::Future<
|
||||
Output = anyhow::Result<crate::executor::KclValue, crate::errors::KclError>,
|
||||
> + Send,
|
||||
> + Send
|
||||
+ '_,
|
||||
>,
|
||||
> {
|
||||
Box::pin(import(args))
|
||||
Box::pin(import(exec_state, args))
|
||||
}
|
||||
|
||||
impl crate::docs::StdLibFn for Import {
|
||||
|
@ -44,15 +44,17 @@ pub(crate) struct Import {}
|
||||
#[doc = "Std lib function: import\nThis is some function.\nIt does shit."]
|
||||
pub(crate) const Import: Import = Import {};
|
||||
fn boxed_import(
|
||||
exec_state: &mut crate::executor::ExecState,
|
||||
args: crate::std::Args,
|
||||
) -> std::pin::Pin<
|
||||
Box<
|
||||
dyn std::future::Future<
|
||||
Output = anyhow::Result<crate::executor::KclValue, crate::errors::KclError>,
|
||||
> + Send,
|
||||
> + Send
|
||||
+ '_,
|
||||
>,
|
||||
> {
|
||||
Box::pin(import(args))
|
||||
Box::pin(import(exec_state, args))
|
||||
}
|
||||
|
||||
impl crate::docs::StdLibFn for Import {
|
||||
|
@ -44,15 +44,17 @@ pub(crate) struct Show {}
|
||||
#[doc = "Std lib function: show\nThis is some function.\nIt does shit."]
|
||||
pub(crate) const Show: Show = Show {};
|
||||
fn boxed_show(
|
||||
exec_state: &mut crate::executor::ExecState,
|
||||
args: crate::std::Args,
|
||||
) -> std::pin::Pin<
|
||||
Box<
|
||||
dyn std::future::Future<
|
||||
Output = anyhow::Result<crate::executor::KclValue, crate::errors::KclError>,
|
||||
> + Send,
|
||||
> + Send
|
||||
+ '_,
|
||||
>,
|
||||
> {
|
||||
Box::pin(show(args))
|
||||
Box::pin(show(exec_state, args))
|
||||
}
|
||||
|
||||
impl crate::docs::StdLibFn for Show {
|
||||
|
134
src/wasm-lib/derive-docs/tests/test_args_with_exec_state.gen
Normal file
134
src/wasm-lib/derive-docs/tests/test_args_with_exec_state.gen
Normal file
@ -0,0 +1,134 @@
|
||||
#[cfg(test)]
|
||||
mod test_examples_some_function {
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
async fn test_mock_example_some_function0() {
|
||||
let tokens = crate::token::lexer("someFunction()").unwrap();
|
||||
let parser = crate::parser::Parser::new(tokens);
|
||||
let program = parser.ast().unwrap();
|
||||
let ctx = crate::executor::ExecutorContext {
|
||||
engine: std::sync::Arc::new(Box::new(
|
||||
crate::engine::conn_mock::EngineConnection::new()
|
||||
.await
|
||||
.unwrap(),
|
||||
)),
|
||||
fs: std::sync::Arc::new(crate::fs::FileManager::new()),
|
||||
stdlib: std::sync::Arc::new(crate::std::StdLib::new()),
|
||||
settings: Default::default(),
|
||||
is_mock: true,
|
||||
};
|
||||
ctx.run(&program, None).await.unwrap();
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 5)]
|
||||
async fn kcl_test_example_some_function0() {
|
||||
let code = "someFunction()";
|
||||
let result =
|
||||
crate::test_server::execute_and_snapshot(code, crate::settings::types::UnitLength::Mm)
|
||||
.await
|
||||
.unwrap();
|
||||
twenty_twenty::assert_image(
|
||||
&format!("tests/outputs/{}.png", "serial_test_example_some_function0"),
|
||||
&result,
|
||||
0.99,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(non_camel_case_types, missing_docs)]
|
||||
#[doc = "Std lib function: someFunction\nDocs"]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, schemars :: JsonSchema, ts_rs :: TS)]
|
||||
#[ts(export)]
|
||||
pub(crate) struct SomeFunction {}
|
||||
|
||||
#[allow(non_upper_case_globals, missing_docs)]
|
||||
#[doc = "Std lib function: someFunction\nDocs"]
|
||||
pub(crate) const SomeFunction: SomeFunction = SomeFunction {};
|
||||
fn boxed_some_function(
|
||||
exec_state: &mut crate::executor::ExecState,
|
||||
args: crate::std::Args,
|
||||
) -> std::pin::Pin<
|
||||
Box<
|
||||
dyn std::future::Future<
|
||||
Output = anyhow::Result<crate::executor::KclValue, crate::errors::KclError>,
|
||||
> + Send
|
||||
+ '_,
|
||||
>,
|
||||
> {
|
||||
Box::pin(some_function(exec_state, args))
|
||||
}
|
||||
|
||||
impl crate::docs::StdLibFn for SomeFunction {
|
||||
fn name(&self) -> String {
|
||||
"someFunction".to_string()
|
||||
}
|
||||
|
||||
fn summary(&self) -> String {
|
||||
"Docs".to_string()
|
||||
}
|
||||
|
||||
fn description(&self) -> String {
|
||||
"".to_string()
|
||||
}
|
||||
|
||||
fn tags(&self) -> Vec<String> {
|
||||
vec![]
|
||||
}
|
||||
|
||||
fn args(&self) -> Vec<crate::docs::StdLibFnArg> {
|
||||
let mut settings = schemars::gen::SchemaSettings::openapi3();
|
||||
settings.inline_subschemas = true;
|
||||
let mut generator = schemars::gen::SchemaGenerator::new(settings);
|
||||
vec![]
|
||||
}
|
||||
|
||||
fn return_value(&self) -> Option<crate::docs::StdLibFnArg> {
|
||||
let mut settings = schemars::gen::SchemaSettings::openapi3();
|
||||
settings.inline_subschemas = true;
|
||||
let mut generator = schemars::gen::SchemaGenerator::new(settings);
|
||||
Some(crate::docs::StdLibFnArg {
|
||||
name: "".to_string(),
|
||||
type_: "i32".to_string(),
|
||||
schema: <i32>::json_schema(&mut generator),
|
||||
required: true,
|
||||
})
|
||||
}
|
||||
|
||||
fn unpublished(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn deprecated(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<String> {
|
||||
let code_blocks = vec!["someFunction()"];
|
||||
code_blocks
|
||||
.iter()
|
||||
.map(|cb| {
|
||||
let tokens = crate::token::lexer(cb).unwrap();
|
||||
let parser = crate::parser::Parser::new(tokens);
|
||||
let program = parser.ast().unwrap();
|
||||
let mut options: crate::ast::types::FormatOptions = Default::default();
|
||||
options.insert_final_newline = false;
|
||||
program.recast(&options, 0)
|
||||
})
|
||||
.collect::<Vec<String>>()
|
||||
}
|
||||
|
||||
fn std_lib_fn(&self) -> crate::std::StdFn {
|
||||
boxed_some_function
|
||||
}
|
||||
|
||||
fn clone_box(&self) -> Box<dyn crate::docs::StdLibFn> {
|
||||
Box::new(self.clone())
|
||||
}
|
||||
}
|
||||
|
||||
#[doc = r" Docs"]
|
||||
#[doc = r" ```"]
|
||||
#[doc = r" someFunction()"]
|
||||
#[doc = r" ```"]
|
||||
fn inner_some_function<'a>(exec_state: &mut ExecState, args: &Args) -> i32 {
|
||||
3
|
||||
}
|
@ -7,6 +7,7 @@ use std::{
|
||||
};
|
||||
|
||||
use anyhow::Result;
|
||||
use async_recursion::async_recursion;
|
||||
use databake::*;
|
||||
use parse_display::{Display, FromStr};
|
||||
use schemars::JsonSchema;
|
||||
@ -22,8 +23,8 @@ use crate::{
|
||||
docs::StdLibFn,
|
||||
errors::{KclError, KclErrorDetails},
|
||||
executor::{
|
||||
BodyType, DynamicState, ExecutorContext, KclValue, Metadata, PipeInfo, ProgramMemory, SketchGroup, SourceRange,
|
||||
StatementKind, TagEngineInfo, TagIdentifier, UserVal,
|
||||
BodyType, ExecState, ExecutorContext, KclValue, Metadata, SketchGroup, SourceRange, StatementKind,
|
||||
TagEngineInfo, TagIdentifier, UserVal,
|
||||
},
|
||||
parser::PIPE_OPERATOR,
|
||||
std::{kcl_stdlib::KclStdLibFn, FunctionKind},
|
||||
@ -797,31 +798,17 @@ impl BinaryPart {
|
||||
}
|
||||
|
||||
#[async_recursion::async_recursion]
|
||||
pub async fn get_result(
|
||||
&self,
|
||||
memory: &mut ProgramMemory,
|
||||
dynamic_state: &DynamicState,
|
||||
pipe_info: &PipeInfo,
|
||||
ctx: &ExecutorContext,
|
||||
) -> Result<KclValue, KclError> {
|
||||
pub async fn get_result(&self, exec_state: &mut ExecState, ctx: &ExecutorContext) -> Result<KclValue, KclError> {
|
||||
match self {
|
||||
BinaryPart::Literal(literal) => Ok(literal.into()),
|
||||
BinaryPart::Identifier(identifier) => {
|
||||
let value = memory.get(&identifier.name, identifier.into())?;
|
||||
let value = exec_state.memory.get(&identifier.name, identifier.into())?;
|
||||
Ok(value.clone())
|
||||
}
|
||||
BinaryPart::BinaryExpression(binary_expression) => {
|
||||
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::MemberExpression(member_expression) => member_expression.get_result(memory),
|
||||
BinaryPart::BinaryExpression(binary_expression) => binary_expression.get_result(exec_state, ctx).await,
|
||||
BinaryPart::CallExpression(call_expression) => call_expression.execute(exec_state, ctx).await,
|
||||
BinaryPart::UnaryExpression(unary_expression) => unary_expression.get_result(exec_state, ctx).await,
|
||||
BinaryPart::MemberExpression(member_expression) => member_expression.get_result(exec_state),
|
||||
}
|
||||
}
|
||||
|
||||
@ -1192,30 +1179,17 @@ impl CallExpression {
|
||||
}
|
||||
|
||||
#[async_recursion::async_recursion]
|
||||
pub async fn execute(
|
||||
&self,
|
||||
memory: &mut ProgramMemory,
|
||||
dynamic_state: &DynamicState,
|
||||
pipe_info: &PipeInfo,
|
||||
ctx: &ExecutorContext,
|
||||
) -> Result<KclValue, KclError> {
|
||||
let fn_name = self.callee.name.clone();
|
||||
pub async fn execute(&self, exec_state: &mut ExecState, ctx: &ExecutorContext) -> Result<KclValue, KclError> {
|
||||
let fn_name = &self.callee.name;
|
||||
|
||||
let mut fn_args: Vec<KclValue> = Vec::with_capacity(self.arguments.len());
|
||||
|
||||
for arg in &self.arguments {
|
||||
let metadata = Metadata {
|
||||
source_range: SourceRange([arg.start(), arg.end()]),
|
||||
source_range: SourceRange::from(arg),
|
||||
};
|
||||
let result = ctx
|
||||
.execute_expr(
|
||||
arg,
|
||||
memory,
|
||||
dynamic_state,
|
||||
pipe_info,
|
||||
&metadata,
|
||||
StatementKind::Expression,
|
||||
)
|
||||
.execute_expr(arg, exec_state, &metadata, StatementKind::Expression)
|
||||
.await?;
|
||||
fn_args.push(result);
|
||||
}
|
||||
@ -1223,9 +1197,8 @@ impl CallExpression {
|
||||
match ctx.stdlib.get_either(&self.callee.name) {
|
||||
FunctionKind::Core(func) => {
|
||||
// Attempt to call the function.
|
||||
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 args = crate::std::Args::new(fn_args, self.into(), ctx.clone());
|
||||
let mut result = func.std_lib_fn()(exec_state, args).await?;
|
||||
|
||||
// If the return result is a sketch group or extrude group, we want to update the
|
||||
// memory for the tags of the group.
|
||||
@ -1235,7 +1208,7 @@ impl CallExpression {
|
||||
KclValue::UserVal(ref mut uval) => {
|
||||
uval.mutate(|sketch_group: &mut SketchGroup| {
|
||||
for (_, tag) in sketch_group.tags.iter() {
|
||||
memory.update_tag(&tag.value, tag.clone())?;
|
||||
exec_state.memory.update_tag(&tag.value, tag.clone())?;
|
||||
}
|
||||
Ok::<_, KclError>(())
|
||||
})?;
|
||||
@ -1275,7 +1248,7 @@ impl CallExpression {
|
||||
info.sketch_group = extrude_group.id;
|
||||
t.info = Some(info);
|
||||
|
||||
memory.update_tag(&tag.name, t.clone())?;
|
||||
exec_state.memory.update_tag(&tag.name, t.clone())?;
|
||||
|
||||
// update the sketch group tags.
|
||||
extrude_group.sketch_group.tags.insert(tag.name.clone(), t);
|
||||
@ -1283,7 +1256,11 @@ impl CallExpression {
|
||||
}
|
||||
|
||||
// Find the stale sketch group in memory and update it.
|
||||
if let Some(current_env) = memory.environments.get_mut(memory.current_env.index()) {
|
||||
if let Some(current_env) = exec_state
|
||||
.memory
|
||||
.environments
|
||||
.get_mut(exec_state.memory.current_env.index())
|
||||
{
|
||||
current_env.update_sketch_group_tags(&extrude_group.sketch_group);
|
||||
}
|
||||
}
|
||||
@ -1294,17 +1271,18 @@ impl CallExpression {
|
||||
}
|
||||
FunctionKind::Std(func) => {
|
||||
let function_expression = func.function();
|
||||
let parts = function_expression.clone().into_parts().map_err(|e| {
|
||||
let (required_params, optional_params) =
|
||||
function_expression.required_and_optional_params().map_err(|e| {
|
||||
KclError::Semantic(KclErrorDetails {
|
||||
message: format!("Error getting parts of function: {}", e),
|
||||
source_ranges: vec![self.into()],
|
||||
})
|
||||
})?;
|
||||
if fn_args.len() < parts.params_required.len() || fn_args.len() > function_expression.params.len() {
|
||||
if fn_args.len() < required_params.len() || fn_args.len() > function_expression.params.len() {
|
||||
return Err(KclError::Semantic(KclErrorDetails {
|
||||
message: format!(
|
||||
"this function expected {} arguments, got {}",
|
||||
parts.params_required.len(),
|
||||
required_params.len(),
|
||||
fn_args.len(),
|
||||
),
|
||||
source_ranges: vec![self.into()],
|
||||
@ -1312,8 +1290,8 @@ impl CallExpression {
|
||||
}
|
||||
|
||||
// Add the arguments to the memory.
|
||||
let mut fn_memory = memory.clone();
|
||||
for (index, param) in parts.params_required.iter().enumerate() {
|
||||
let mut fn_memory = exec_state.memory.clone();
|
||||
for (index, param) in required_params.iter().enumerate() {
|
||||
fn_memory.add(
|
||||
¶m.identifier.name,
|
||||
fn_args.get(index).unwrap().clone(),
|
||||
@ -1321,8 +1299,8 @@ impl CallExpression {
|
||||
)?;
|
||||
}
|
||||
// Add the optional arguments to the memory.
|
||||
for (index, param) in parts.params_optional.iter().enumerate() {
|
||||
if let Some(arg) = fn_args.get(index + parts.params_required.len()) {
|
||||
for (index, param) in optional_params.iter().enumerate() {
|
||||
if let Some(arg) = fn_args.get(index + required_params.len()) {
|
||||
fn_memory.add(¶m.identifier.name, arg.clone(), param.identifier.clone().into())?;
|
||||
} else {
|
||||
fn_memory.add(
|
||||
@ -1336,22 +1314,31 @@ impl CallExpression {
|
||||
}
|
||||
}
|
||||
|
||||
let mut fn_dynamic_state = dynamic_state.clone();
|
||||
let fn_dynamic_state = exec_state.dynamic_state.clone();
|
||||
// TODO: Shouldn't we merge program memory into fn_dynamic_state
|
||||
// here?
|
||||
|
||||
// Call the stdlib function
|
||||
let p = func.function().clone().body;
|
||||
let results = match ctx
|
||||
.inner_execute(&p, &mut fn_memory, &mut fn_dynamic_state, BodyType::Block)
|
||||
.await
|
||||
{
|
||||
Ok(results) => results,
|
||||
let p = &func.function().body;
|
||||
|
||||
let (exec_result, fn_memory) = {
|
||||
let previous_memory = std::mem::replace(&mut exec_state.memory, fn_memory);
|
||||
let previous_dynamic_state = std::mem::replace(&mut exec_state.dynamic_state, fn_dynamic_state);
|
||||
let result = ctx.inner_execute(p, exec_state, BodyType::Block).await;
|
||||
exec_state.dynamic_state = previous_dynamic_state;
|
||||
let fn_memory = std::mem::replace(&mut exec_state.memory, previous_memory);
|
||||
(result, fn_memory)
|
||||
};
|
||||
|
||||
match exec_result {
|
||||
Ok(()) => {}
|
||||
Err(err) => {
|
||||
// We need to override the source ranges so we don't get the embedded kcl
|
||||
// function from the stdlib.
|
||||
return Err(err.override_source_ranges(vec![self.into()]));
|
||||
}
|
||||
};
|
||||
let out = results.return_;
|
||||
let out = fn_memory.return_;
|
||||
let result = out.ok_or_else(|| {
|
||||
KclError::UndefinedValue(KclErrorDetails {
|
||||
message: format!("Result of stdlib function {} is undefined", fn_name),
|
||||
@ -1361,18 +1348,24 @@ impl CallExpression {
|
||||
Ok(result)
|
||||
}
|
||||
FunctionKind::UserDefined => {
|
||||
let func = memory.get(&fn_name, self.into())?;
|
||||
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.
|
||||
e.add_source_ranges(vec![self.into()])
|
||||
})?;
|
||||
let source_range = SourceRange::from(self);
|
||||
// Clone the function so that we can use a mutable reference to
|
||||
// exec_state.
|
||||
let func = exec_state.memory.get(fn_name, source_range)?.clone();
|
||||
let fn_dynamic_state = exec_state.dynamic_state.merge(&exec_state.memory);
|
||||
|
||||
let result = result.ok_or_else(|| {
|
||||
let mut source_ranges: Vec<SourceRange> = vec![self.into()];
|
||||
let return_value = {
|
||||
let previous_dynamic_state = std::mem::replace(&mut exec_state.dynamic_state, fn_dynamic_state);
|
||||
let result = func.call_fn(fn_args, exec_state, ctx.clone()).await.map_err(|e| {
|
||||
// Add the call expression to the source ranges.
|
||||
e.add_source_ranges(vec![source_range])
|
||||
});
|
||||
exec_state.dynamic_state = previous_dynamic_state;
|
||||
result?
|
||||
};
|
||||
|
||||
let result = return_value.ok_or_else(move || {
|
||||
let mut source_ranges: Vec<SourceRange> = vec![source_range];
|
||||
// We want to send the source range of the original function.
|
||||
if let KclValue::Function { meta, .. } = func {
|
||||
source_ranges = meta.iter().map(|m| m.source_range).collect();
|
||||
@ -1990,7 +1983,7 @@ impl TagDeclarator {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn execute(&self, memory: &mut ProgramMemory) -> Result<KclValue, KclError> {
|
||||
pub async fn execute(&self, exec_state: &mut ExecState) -> Result<KclValue, KclError> {
|
||||
let memory_item = KclValue::TagIdentifier(Box::new(TagIdentifier {
|
||||
value: self.name.clone(),
|
||||
info: None,
|
||||
@ -1999,7 +1992,7 @@ impl TagDeclarator {
|
||||
}],
|
||||
}));
|
||||
|
||||
memory.add(&self.name, memory_item.clone(), self.into())?;
|
||||
exec_state.memory.add(&self.name, memory_item.clone(), self.into())?;
|
||||
|
||||
Ok(self.into())
|
||||
}
|
||||
@ -2136,65 +2129,18 @@ impl ArrayExpression {
|
||||
}
|
||||
|
||||
#[async_recursion::async_recursion]
|
||||
pub async fn execute(
|
||||
&self,
|
||||
memory: &mut ProgramMemory,
|
||||
dynamic_state: &DynamicState,
|
||||
pipe_info: &PipeInfo,
|
||||
ctx: &ExecutorContext,
|
||||
) -> Result<KclValue, KclError> {
|
||||
pub async fn execute(&self, exec_state: &mut ExecState, ctx: &ExecutorContext) -> Result<KclValue, KclError> {
|
||||
let mut results = Vec::with_capacity(self.elements.len());
|
||||
|
||||
for element in &self.elements {
|
||||
let result = match element {
|
||||
Expr::Literal(literal) => literal.into(),
|
||||
Expr::TagDeclarator(tag) => tag.execute(memory).await?,
|
||||
Expr::None(none) => none.into(),
|
||||
Expr::Identifier(identifier) => {
|
||||
let value = memory.get(&identifier.name, identifier.into())?;
|
||||
value.clone()
|
||||
}
|
||||
Expr::BinaryExpression(binary_expression) => {
|
||||
binary_expression
|
||||
.get_result(memory, dynamic_state, pipe_info, ctx)
|
||||
.await?
|
||||
}
|
||||
Expr::CallExpression(call_expression) => {
|
||||
call_expression.execute(memory, dynamic_state, pipe_info, ctx).await?
|
||||
}
|
||||
Expr::UnaryExpression(unary_expression) => {
|
||||
unary_expression
|
||||
.get_result(memory, dynamic_state, pipe_info, ctx)
|
||||
.await?
|
||||
}
|
||||
Expr::ObjectExpression(object_expression) => {
|
||||
object_expression.execute(memory, dynamic_state, pipe_info, ctx).await?
|
||||
}
|
||||
Expr::ArrayExpression(array_expression) => {
|
||||
array_expression.execute(memory, dynamic_state, pipe_info, ctx).await?
|
||||
}
|
||||
Expr::PipeExpression(pipe_expression) => {
|
||||
pipe_expression
|
||||
.get_result(memory, dynamic_state, pipe_info, ctx)
|
||||
.await?
|
||||
}
|
||||
Expr::PipeSubstitution(pipe_substitution) => {
|
||||
return Err(KclError::Semantic(KclErrorDetails {
|
||||
message: format!("PipeSubstitution not implemented here: {:?}", pipe_substitution),
|
||||
source_ranges: vec![pipe_substitution.into()],
|
||||
}));
|
||||
}
|
||||
Expr::MemberExpression(member_expression) => member_expression.get_result(memory)?,
|
||||
Expr::FunctionExpression(function_expression) => {
|
||||
return Err(KclError::Semantic(KclErrorDetails {
|
||||
message: format!("FunctionExpression not implemented here: {:?}", function_expression),
|
||||
source_ranges: vec![function_expression.into()],
|
||||
}));
|
||||
}
|
||||
}
|
||||
.get_json_value()?;
|
||||
let metadata = Metadata::from(element);
|
||||
// TODO: Carry statement kind here so that we know if we're
|
||||
// inside a variable declaration.
|
||||
let value = ctx
|
||||
.execute_expr(element, exec_state, &metadata, StatementKind::Expression)
|
||||
.await?;
|
||||
|
||||
results.push(result);
|
||||
results.push(value.get_json_value()?);
|
||||
}
|
||||
|
||||
Ok(KclValue::UserVal(UserVal {
|
||||
@ -2279,61 +2225,13 @@ impl ObjectExpression {
|
||||
}
|
||||
|
||||
#[async_recursion::async_recursion]
|
||||
pub async fn execute(
|
||||
&self,
|
||||
memory: &mut ProgramMemory,
|
||||
dynamic_state: &DynamicState,
|
||||
pipe_info: &PipeInfo,
|
||||
ctx: &ExecutorContext,
|
||||
) -> Result<KclValue, KclError> {
|
||||
pub async fn execute(&self, exec_state: &mut ExecState, ctx: &ExecutorContext) -> Result<KclValue, KclError> {
|
||||
let mut object = Map::new();
|
||||
for property in &self.properties {
|
||||
let result = match &property.value {
|
||||
Expr::Literal(literal) => literal.into(),
|
||||
Expr::TagDeclarator(tag) => tag.execute(memory).await?,
|
||||
Expr::None(none) => none.into(),
|
||||
Expr::Identifier(identifier) => {
|
||||
let value = memory.get(&identifier.name, identifier.into())?;
|
||||
value.clone()
|
||||
}
|
||||
Expr::BinaryExpression(binary_expression) => {
|
||||
binary_expression
|
||||
.get_result(memory, dynamic_state, pipe_info, ctx)
|
||||
.await?
|
||||
}
|
||||
Expr::CallExpression(call_expression) => {
|
||||
call_expression.execute(memory, dynamic_state, pipe_info, ctx).await?
|
||||
}
|
||||
Expr::UnaryExpression(unary_expression) => {
|
||||
unary_expression
|
||||
.get_result(memory, dynamic_state, pipe_info, ctx)
|
||||
.await?
|
||||
}
|
||||
Expr::ObjectExpression(object_expression) => {
|
||||
object_expression.execute(memory, dynamic_state, pipe_info, ctx).await?
|
||||
}
|
||||
Expr::ArrayExpression(array_expression) => {
|
||||
array_expression.execute(memory, dynamic_state, pipe_info, ctx).await?
|
||||
}
|
||||
Expr::PipeExpression(pipe_expression) => {
|
||||
pipe_expression
|
||||
.get_result(memory, dynamic_state, pipe_info, ctx)
|
||||
.await?
|
||||
}
|
||||
Expr::MemberExpression(member_expression) => member_expression.get_result(memory)?,
|
||||
Expr::PipeSubstitution(pipe_substitution) => {
|
||||
return Err(KclError::Semantic(KclErrorDetails {
|
||||
message: format!("PipeSubstitution not implemented here: {:?}", pipe_substitution),
|
||||
source_ranges: vec![pipe_substitution.into()],
|
||||
}));
|
||||
}
|
||||
Expr::FunctionExpression(function_expression) => {
|
||||
return Err(KclError::Semantic(KclErrorDetails {
|
||||
message: format!("FunctionExpression not implemented here: {:?}", function_expression),
|
||||
source_ranges: vec![function_expression.into()],
|
||||
}));
|
||||
}
|
||||
};
|
||||
let metadata = Metadata::from(&property.value);
|
||||
let result = ctx
|
||||
.execute_expr(&property.value, exec_state, &metadata, StatementKind::Expression)
|
||||
.await?;
|
||||
|
||||
object.insert(property.key.name.clone(), result.get_json_value()?);
|
||||
}
|
||||
@ -2545,11 +2443,11 @@ impl MemberExpression {
|
||||
None
|
||||
}
|
||||
|
||||
pub fn get_result_array(&self, memory: &mut ProgramMemory, index: usize) -> Result<KclValue, KclError> {
|
||||
pub fn get_result_array(&self, exec_state: &mut ExecState, index: usize) -> Result<KclValue, KclError> {
|
||||
let array = match &self.object {
|
||||
MemberObject::MemberExpression(member_expr) => member_expr.get_result(memory)?,
|
||||
MemberObject::MemberExpression(member_expr) => member_expr.get_result(exec_state)?,
|
||||
MemberObject::Identifier(identifier) => {
|
||||
let value = memory.get(&identifier.name, identifier.into())?;
|
||||
let value = exec_state.memory.get(&identifier.name, identifier.into())?;
|
||||
value.clone()
|
||||
}
|
||||
};
|
||||
@ -2578,7 +2476,7 @@ impl MemberExpression {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_result(&self, memory: &mut ProgramMemory) -> Result<KclValue, KclError> {
|
||||
pub fn get_result(&self, exec_state: &mut ExecState) -> Result<KclValue, KclError> {
|
||||
#[derive(Debug)]
|
||||
enum Property {
|
||||
Number(usize),
|
||||
@ -2605,7 +2503,7 @@ impl MemberExpression {
|
||||
Property::String(name.to_string())
|
||||
} else {
|
||||
// Actually evaluate memory to compute the property.
|
||||
let prop = memory.get(&name, property_src)?;
|
||||
let prop = exec_state.memory.get(&name, property_src)?;
|
||||
let KclValue::UserVal(prop) = prop else {
|
||||
return Err(KclError::Semantic(KclErrorDetails {
|
||||
source_ranges: property_sr,
|
||||
@ -2667,9 +2565,9 @@ impl MemberExpression {
|
||||
|
||||
let object = match &self.object {
|
||||
// TODO: Don't use recursion here, use a loop.
|
||||
MemberObject::MemberExpression(member_expr) => member_expr.get_result(memory)?,
|
||||
MemberObject::MemberExpression(member_expr) => member_expr.get_result(exec_state)?,
|
||||
MemberObject::Identifier(identifier) => {
|
||||
let value = memory.get(&identifier.name, identifier.into())?;
|
||||
let value = exec_state.memory.get(&identifier.name, identifier.into())?;
|
||||
value.clone()
|
||||
}
|
||||
};
|
||||
@ -2827,23 +2725,9 @@ impl BinaryExpression {
|
||||
}
|
||||
|
||||
#[async_recursion::async_recursion]
|
||||
pub async fn get_result(
|
||||
&self,
|
||||
memory: &mut ProgramMemory,
|
||||
dynamic_state: &DynamicState,
|
||||
pipe_info: &PipeInfo,
|
||||
ctx: &ExecutorContext,
|
||||
) -> Result<KclValue, KclError> {
|
||||
let left_json_value = self
|
||||
.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()?;
|
||||
pub async fn get_result(&self, exec_state: &mut ExecState, ctx: &ExecutorContext) -> Result<KclValue, KclError> {
|
||||
let left_json_value = self.left.get_result(exec_state, ctx).await?.get_json_value()?;
|
||||
let right_json_value = self.right.get_result(exec_state, ctx).await?.get_json_value()?;
|
||||
|
||||
// First check if we are doing string concatenation.
|
||||
if self.operator == BinaryOperator::Add {
|
||||
@ -3043,19 +2927,9 @@ impl UnaryExpression {
|
||||
self.argument.get_constraint_level()
|
||||
}
|
||||
|
||||
pub async fn get_result(
|
||||
&self,
|
||||
memory: &mut ProgramMemory,
|
||||
dynamic_state: &DynamicState,
|
||||
pipe_info: &PipeInfo,
|
||||
ctx: &ExecutorContext,
|
||||
) -> Result<KclValue, KclError> {
|
||||
pub async fn get_result(&self, exec_state: &mut ExecState, ctx: &ExecutorContext) -> Result<KclValue, KclError> {
|
||||
if self.operator == UnaryOperator::Not {
|
||||
let value = self
|
||||
.argument
|
||||
.get_result(memory, dynamic_state, pipe_info, ctx)
|
||||
.await?
|
||||
.get_json_value()?;
|
||||
let value = self.argument.get_result(exec_state, ctx).await?.get_json_value()?;
|
||||
let Some(bool_value) = json_as_bool(&value) else {
|
||||
return Err(KclError::Semantic(KclErrorDetails {
|
||||
message: format!("Cannot apply unary operator ! to non-boolean value: {}", value),
|
||||
@ -3072,11 +2946,7 @@ impl UnaryExpression {
|
||||
}
|
||||
|
||||
let num = parse_json_number_as_f64(
|
||||
&self
|
||||
.argument
|
||||
.get_result(memory, dynamic_state, pipe_info, ctx)
|
||||
.await?
|
||||
.get_json_value()?,
|
||||
&self.argument.get_result(exec_state, ctx).await?.get_json_value()?,
|
||||
self.into(),
|
||||
)?;
|
||||
Ok(KclValue::UserVal(UserVal {
|
||||
@ -3204,14 +3074,9 @@ impl PipeExpression {
|
||||
None
|
||||
}
|
||||
|
||||
pub async fn get_result(
|
||||
&self,
|
||||
memory: &mut ProgramMemory,
|
||||
dynamic_state: &DynamicState,
|
||||
pipe_info: &PipeInfo,
|
||||
ctx: &ExecutorContext,
|
||||
) -> Result<KclValue, KclError> {
|
||||
execute_pipe_body(memory, dynamic_state, &self.body, pipe_info, self.into(), ctx).await
|
||||
#[async_recursion]
|
||||
pub async fn get_result(&self, exec_state: &mut ExecState, ctx: &ExecutorContext) -> Result<KclValue, KclError> {
|
||||
execute_pipe_body(exec_state, &self.body, self.into(), ctx).await
|
||||
}
|
||||
|
||||
/// Rename all identifiers that have the old name to the new given name.
|
||||
@ -3222,45 +3087,49 @@ impl PipeExpression {
|
||||
}
|
||||
}
|
||||
|
||||
#[async_recursion::async_recursion]
|
||||
async fn execute_pipe_body(
|
||||
memory: &mut ProgramMemory,
|
||||
dynamic_state: &DynamicState,
|
||||
exec_state: &mut ExecState,
|
||||
body: &[Expr],
|
||||
pipe_info: &PipeInfo,
|
||||
source_range: SourceRange,
|
||||
ctx: &ExecutorContext,
|
||||
) -> Result<KclValue, KclError> {
|
||||
let mut body = body.iter();
|
||||
let first = body.next().ok_or_else(|| {
|
||||
KclError::Semantic(KclErrorDetails {
|
||||
let Some((first, body)) = body.split_first() else {
|
||||
return Err(KclError::Semantic(KclErrorDetails {
|
||||
message: "Pipe expressions cannot be empty".to_owned(),
|
||||
source_ranges: vec![source_range],
|
||||
})
|
||||
})?;
|
||||
}));
|
||||
};
|
||||
// Evaluate the first element in the pipeline.
|
||||
// They use the `pipe_info` from some AST node above this, so that if pipe expression is nested in a larger pipe expression,
|
||||
// They use the pipe_value from some AST node above this, so that if pipe expression is nested in a larger pipe expression,
|
||||
// they use the % from the parent. After all, this pipe expression hasn't been executed yet, so it doesn't have any % value
|
||||
// of its own.
|
||||
let meta = Metadata {
|
||||
source_range: SourceRange([first.start(), first.end()]),
|
||||
};
|
||||
let output = ctx
|
||||
.execute_expr(
|
||||
first,
|
||||
memory,
|
||||
dynamic_state,
|
||||
pipe_info,
|
||||
&meta,
|
||||
StatementKind::Expression,
|
||||
)
|
||||
.execute_expr(first, exec_state, &meta, StatementKind::Expression)
|
||||
.await?;
|
||||
|
||||
// Now that we've evaluated the first child expression in the pipeline, following child expressions
|
||||
// should use the previous child expression for %.
|
||||
// This means there's no more need for the previous `pipe_info` from the parent AST node above this one.
|
||||
let mut new_pipe_info = PipeInfo::new();
|
||||
new_pipe_info.previous_results = Some(output);
|
||||
// This means there's no more need for the previous pipe_value from the parent AST node above this one.
|
||||
let previous_pipe_value = std::mem::replace(&mut exec_state.pipe_value, Some(output));
|
||||
// Evaluate remaining elements.
|
||||
let result = inner_execute_pipe_body(exec_state, body, ctx).await;
|
||||
// Restore the previous pipe value.
|
||||
exec_state.pipe_value = previous_pipe_value;
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
/// Execute the tail of a pipe expression. exec_state.pipe_value must be set by
|
||||
/// the caller.
|
||||
#[async_recursion]
|
||||
async fn inner_execute_pipe_body(
|
||||
exec_state: &mut ExecState,
|
||||
body: &[Expr],
|
||||
ctx: &ExecutorContext,
|
||||
) -> Result<KclValue, KclError> {
|
||||
for expression in body {
|
||||
match expression {
|
||||
Expr::TagDeclarator(_) => {
|
||||
@ -3286,19 +3155,12 @@ async fn execute_pipe_body(
|
||||
source_range: SourceRange([expression.start(), expression.end()]),
|
||||
};
|
||||
let output = ctx
|
||||
.execute_expr(
|
||||
expression,
|
||||
memory,
|
||||
dynamic_state,
|
||||
&new_pipe_info,
|
||||
&metadata,
|
||||
StatementKind::Expression,
|
||||
)
|
||||
.execute_expr(expression, exec_state, &metadata, StatementKind::Expression)
|
||||
.await?;
|
||||
new_pipe_info.previous_results = Some(output);
|
||||
exec_state.pipe_value = Some(output);
|
||||
}
|
||||
// Safe to unwrap here, because `newpipe_info` always has something pushed in when the `match first` executes.
|
||||
let final_output = new_pipe_info.previous_results.unwrap();
|
||||
// Safe to unwrap here, because pipe_value always has something pushed in when the `match first` executes.
|
||||
let final_output = exec_state.pipe_value.take().unwrap();
|
||||
Ok(final_output)
|
||||
}
|
||||
|
||||
@ -3430,14 +3292,6 @@ pub struct FunctionExpression {
|
||||
|
||||
impl_value_meta!(FunctionExpression);
|
||||
|
||||
pub struct FunctionExpressionParts {
|
||||
pub start: usize,
|
||||
pub end: usize,
|
||||
pub params_required: Vec<Parameter>,
|
||||
pub params_optional: Vec<Parameter>,
|
||||
pub body: Program,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub struct RequiredParamAfterOptionalParam(pub Parameter);
|
||||
|
||||
@ -3472,36 +3326,28 @@ impl FunctionExpression {
|
||||
}
|
||||
});
|
||||
|
||||
pub fn into_parts(self) -> Result<FunctionExpressionParts, RequiredParamAfterOptionalParam> {
|
||||
pub fn required_and_optional_params(
|
||||
&self,
|
||||
) -> Result<(&[Parameter], &[Parameter]), RequiredParamAfterOptionalParam> {
|
||||
let Self {
|
||||
start,
|
||||
end,
|
||||
start: _,
|
||||
end: _,
|
||||
params,
|
||||
body,
|
||||
body: _,
|
||||
digest: _,
|
||||
return_type: _,
|
||||
} = self;
|
||||
let mut params_required = Vec::with_capacity(params.len());
|
||||
let mut params_optional = Vec::with_capacity(params.len());
|
||||
let mut found_optional = false;
|
||||
for param in params {
|
||||
if param.optional {
|
||||
params_optional.push(param);
|
||||
} else {
|
||||
if !params_optional.is_empty() {
|
||||
return Err(RequiredParamAfterOptionalParam(param));
|
||||
}
|
||||
params_required.push(param);
|
||||
found_optional = true;
|
||||
} else if found_optional {
|
||||
return Err(RequiredParamAfterOptionalParam(param.clone()));
|
||||
}
|
||||
}
|
||||
params_required.shrink_to_fit();
|
||||
params_optional.shrink_to_fit();
|
||||
Ok(FunctionExpressionParts {
|
||||
start,
|
||||
end,
|
||||
params_required,
|
||||
params_optional,
|
||||
body,
|
||||
})
|
||||
let boundary = self.params.partition_point(|param| !param.optional);
|
||||
// SAFETY: split_at panics if the boundary is greater than the length.
|
||||
Ok(self.params.split_at(boundary))
|
||||
}
|
||||
|
||||
/// Required parameters must be declared before optional parameters.
|
||||
|
@ -23,6 +23,20 @@ use crate::{
|
||||
std::{FnAsArg, StdLib},
|
||||
};
|
||||
|
||||
/// State for executing a program.
|
||||
#[derive(Debug, Default, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
|
||||
#[ts(export)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ExecState {
|
||||
/// Program variable bindings.
|
||||
pub memory: ProgramMemory,
|
||||
/// Dynamic state that follows dynamic flow of the program.
|
||||
pub dynamic_state: DynamicState,
|
||||
/// The current value of the pipe operator returned from the previous
|
||||
/// expression. If we're not currently in a pipeline, this will be None.
|
||||
pub pipe_value: Option<KclValue>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
|
||||
#[ts(export)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
@ -227,7 +241,7 @@ 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)]
|
||||
#[derive(Debug, Default, Clone, PartialEq, Eq, Deserialize, Serialize, ts_rs::TS, JsonSchema)]
|
||||
pub struct DynamicState {
|
||||
pub extrude_group_ids: Vec<ExtrudeGroupLazyIds>,
|
||||
}
|
||||
@ -730,25 +744,10 @@ pub type MemoryFunction =
|
||||
memory: ProgramMemory,
|
||||
expression: Box<FunctionExpression>,
|
||||
metadata: Vec<Metadata>,
|
||||
dynamic_state: DynamicState,
|
||||
exec_state: &ExecState,
|
||||
ctx: ExecutorContext,
|
||||
) -> std::pin::Pin<Box<dyn std::future::Future<Output = Result<Option<KclValue>, KclError>> + Send>>;
|
||||
|
||||
fn force_memory_function<
|
||||
F: Fn(
|
||||
Vec<KclValue>,
|
||||
ProgramMemory,
|
||||
Box<FunctionExpression>,
|
||||
Vec<Metadata>,
|
||||
DynamicState,
|
||||
ExecutorContext,
|
||||
) -> std::pin::Pin<Box<dyn std::future::Future<Output = Result<Option<KclValue>, KclError>> + Send>>,
|
||||
>(
|
||||
f: F,
|
||||
) -> F {
|
||||
f
|
||||
}
|
||||
|
||||
impl From<KclValue> for Vec<SourceRange> {
|
||||
fn from(item: KclValue) -> Self {
|
||||
match item {
|
||||
@ -848,9 +847,8 @@ impl KclValue {
|
||||
else {
|
||||
return None;
|
||||
};
|
||||
let func = func.as_ref()?;
|
||||
Some(FnAsArg {
|
||||
func,
|
||||
func: func.as_ref(),
|
||||
expr: expression.to_owned(),
|
||||
memory: memory.to_owned(),
|
||||
})
|
||||
@ -904,7 +902,7 @@ impl KclValue {
|
||||
pub async fn call_fn(
|
||||
&self,
|
||||
args: Vec<KclValue>,
|
||||
dynamic_state: &DynamicState,
|
||||
exec_state: &mut ExecState,
|
||||
ctx: ExecutorContext,
|
||||
) -> Result<Option<KclValue>, KclError> {
|
||||
let KclValue::Function {
|
||||
@ -919,21 +917,19 @@ impl KclValue {
|
||||
source_ranges: vec![],
|
||||
}));
|
||||
};
|
||||
let Some(func) = func else {
|
||||
return Err(KclError::Semantic(KclErrorDetails {
|
||||
message: format!("Not a function: {:?}", expression),
|
||||
source_ranges: vec![],
|
||||
}));
|
||||
};
|
||||
if let Some(func) = func {
|
||||
func(
|
||||
args,
|
||||
closure_memory.as_ref().clone(),
|
||||
expression.clone(),
|
||||
meta.clone(),
|
||||
dynamic_state.clone(),
|
||||
exec_state,
|
||||
ctx,
|
||||
)
|
||||
.await
|
||||
} else {
|
||||
call_user_defined_function(args, closure_memory.as_ref(), expression.as_ref(), exec_state, &ctx).await
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1356,6 +1352,14 @@ impl From<&ReturnStatement> for Metadata {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&Expr> for Metadata {
|
||||
fn from(expr: &Expr) -> Self {
|
||||
Self {
|
||||
source_range: SourceRange::from(expr),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A base path.
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
|
||||
#[ts(export)]
|
||||
@ -1573,25 +1577,6 @@ impl ExtrudeSurface {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
|
||||
#[ts(export)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct PipeInfo {
|
||||
pub previous_results: Option<KclValue>,
|
||||
}
|
||||
|
||||
impl PipeInfo {
|
||||
pub fn new() -> Self {
|
||||
Self { previous_results: None }
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for PipeInfo {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
/// The executor context.
|
||||
/// Cloning will return another handle to the same engine connection/session,
|
||||
/// as this uses `Arc` under the hood.
|
||||
@ -1773,7 +1758,7 @@ impl ExecutorContext {
|
||||
&self,
|
||||
program: &crate::ast::types::Program,
|
||||
memory: Option<ProgramMemory>,
|
||||
) -> Result<ProgramMemory, KclError> {
|
||||
) -> Result<ExecState, KclError> {
|
||||
self.run_with_session_data(program, memory).await.map(|x| x.0)
|
||||
}
|
||||
/// Perform the execution of a program.
|
||||
@ -1783,7 +1768,7 @@ impl ExecutorContext {
|
||||
&self,
|
||||
program: &crate::ast::types::Program,
|
||||
memory: Option<ProgramMemory>,
|
||||
) -> Result<(ProgramMemory, Option<ModelingSessionData>), KclError> {
|
||||
) -> Result<(ExecState, Option<ModelingSessionData>), KclError> {
|
||||
// Before we even start executing the program, set the units.
|
||||
self.engine
|
||||
.batch_modeling_cmd(
|
||||
@ -1794,22 +1779,19 @@ impl ExecutorContext {
|
||||
},
|
||||
)
|
||||
.await?;
|
||||
let mut memory = if let Some(memory) = memory {
|
||||
let memory = if let Some(memory) = memory {
|
||||
memory.clone()
|
||||
} else {
|
||||
Default::default()
|
||||
};
|
||||
let mut dynamic_state = DynamicState::default();
|
||||
let final_memory = self
|
||||
.inner_execute(
|
||||
program,
|
||||
&mut memory,
|
||||
&mut dynamic_state,
|
||||
crate::executor::BodyType::Root,
|
||||
)
|
||||
let mut exec_state = ExecState {
|
||||
memory,
|
||||
..Default::default()
|
||||
};
|
||||
self.inner_execute(program, &mut exec_state, crate::executor::BodyType::Root)
|
||||
.await?;
|
||||
let session_data = self.engine.get_session_data();
|
||||
Ok((final_memory, session_data))
|
||||
Ok((exec_state, session_data))
|
||||
}
|
||||
|
||||
/// Execute an AST's program.
|
||||
@ -1817,12 +1799,9 @@ impl ExecutorContext {
|
||||
pub(crate) async fn inner_execute(
|
||||
&self,
|
||||
program: &crate::ast::types::Program,
|
||||
memory: &mut ProgramMemory,
|
||||
dynamic_state: &mut DynamicState,
|
||||
exec_state: &mut ExecState,
|
||||
body_type: BodyType,
|
||||
) -> Result<ProgramMemory, KclError> {
|
||||
let pipe_info = PipeInfo::default();
|
||||
|
||||
) -> Result<(), KclError> {
|
||||
// Iterate over the body of the program.
|
||||
for statement in &program.body {
|
||||
match statement {
|
||||
@ -1831,9 +1810,7 @@ impl ExecutorContext {
|
||||
// Discard return value.
|
||||
self.execute_expr(
|
||||
&expression_statement.expression,
|
||||
memory,
|
||||
dynamic_state,
|
||||
&pipe_info,
|
||||
exec_state,
|
||||
&metadata,
|
||||
StatementKind::Expression,
|
||||
)
|
||||
@ -1848,14 +1825,12 @@ impl ExecutorContext {
|
||||
let memory_item = self
|
||||
.execute_expr(
|
||||
&declaration.init,
|
||||
memory,
|
||||
dynamic_state,
|
||||
&pipe_info,
|
||||
exec_state,
|
||||
&metadata,
|
||||
StatementKind::Declaration { name: &var_name },
|
||||
)
|
||||
.await?;
|
||||
memory.add(&var_name, memory_item, source_range)?;
|
||||
exec_state.memory.add(&var_name, memory_item, source_range)?;
|
||||
}
|
||||
}
|
||||
BodyItem::ReturnStatement(return_statement) => {
|
||||
@ -1863,14 +1838,12 @@ impl ExecutorContext {
|
||||
let value = self
|
||||
.execute_expr(
|
||||
&return_statement.argument,
|
||||
memory,
|
||||
dynamic_state,
|
||||
&pipe_info,
|
||||
exec_state,
|
||||
&metadata,
|
||||
StatementKind::Expression,
|
||||
)
|
||||
.await?;
|
||||
memory.return_ = Some(value);
|
||||
exec_state.memory.return_ = Some(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1887,81 +1860,38 @@ impl ExecutorContext {
|
||||
.await?;
|
||||
}
|
||||
|
||||
Ok(memory.clone())
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn execute_expr<'a>(
|
||||
&self,
|
||||
init: &Expr,
|
||||
memory: &mut ProgramMemory,
|
||||
dynamic_state: &DynamicState,
|
||||
pipe_info: &PipeInfo,
|
||||
exec_state: &mut ExecState,
|
||||
metadata: &Metadata,
|
||||
statement_kind: StatementKind<'a>,
|
||||
) -> Result<KclValue, KclError> {
|
||||
let item = match init {
|
||||
Expr::None(none) => KclValue::from(none),
|
||||
Expr::Literal(literal) => KclValue::from(literal),
|
||||
Expr::TagDeclarator(tag) => tag.execute(memory).await?,
|
||||
Expr::TagDeclarator(tag) => tag.execute(exec_state).await?,
|
||||
Expr::Identifier(identifier) => {
|
||||
let value = memory.get(&identifier.name, identifier.into())?;
|
||||
let value = exec_state.memory.get(&identifier.name, identifier.into())?;
|
||||
value.clone()
|
||||
}
|
||||
Expr::BinaryExpression(binary_expression) => {
|
||||
binary_expression
|
||||
.get_result(memory, dynamic_state, pipe_info, self)
|
||||
.await?
|
||||
}
|
||||
Expr::BinaryExpression(binary_expression) => binary_expression.get_result(exec_state, self).await?,
|
||||
Expr::FunctionExpression(function_expression) => {
|
||||
let mem_func = force_memory_function(
|
||||
|args: Vec<KclValue>,
|
||||
memory: ProgramMemory,
|
||||
function_expression: Box<FunctionExpression>,
|
||||
_metadata: Vec<Metadata>,
|
||||
mut dynamic_state: DynamicState,
|
||||
ctx: ExecutorContext| {
|
||||
Box::pin(async move {
|
||||
// Create a new environment to execute the function
|
||||
// body in so that local variables shadow variables
|
||||
// in the parent scope. The new environment's
|
||||
// parent should be the environment of the closure.
|
||||
let mut body_memory = memory.clone();
|
||||
let closure_env = memory.current_env;
|
||||
let body_env = body_memory.new_env_for_call(closure_env);
|
||||
body_memory.current_env = body_env;
|
||||
let mut fn_memory = assign_args_to_params(&function_expression, args, body_memory)?;
|
||||
|
||||
let result = ctx
|
||||
.inner_execute(
|
||||
&function_expression.body,
|
||||
&mut fn_memory,
|
||||
&mut dynamic_state,
|
||||
BodyType::Block,
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(result.return_)
|
||||
})
|
||||
},
|
||||
);
|
||||
// Cloning memory here is crucial for semantics so that we close
|
||||
// over variables. Variables defined lexically later shouldn't
|
||||
// be available to the function body.
|
||||
KclValue::Function {
|
||||
expression: function_expression.clone(),
|
||||
meta: vec![metadata.to_owned()],
|
||||
func: Some(mem_func),
|
||||
memory: Box::new(memory.clone()),
|
||||
func: None,
|
||||
memory: Box::new(exec_state.memory.clone()),
|
||||
}
|
||||
}
|
||||
Expr::CallExpression(call_expression) => {
|
||||
call_expression.execute(memory, dynamic_state, pipe_info, self).await?
|
||||
}
|
||||
Expr::PipeExpression(pipe_expression) => {
|
||||
pipe_expression
|
||||
.get_result(memory, dynamic_state, pipe_info, self)
|
||||
.await?
|
||||
}
|
||||
Expr::CallExpression(call_expression) => call_expression.execute(exec_state, self).await?,
|
||||
Expr::PipeExpression(pipe_expression) => pipe_expression.get_result(exec_state, self).await?,
|
||||
Expr::PipeSubstitution(pipe_substitution) => match statement_kind {
|
||||
StatementKind::Declaration { name } => {
|
||||
let message = format!(
|
||||
@ -1973,7 +1903,7 @@ impl ExecutorContext {
|
||||
source_ranges: vec![pipe_substitution.into()],
|
||||
}));
|
||||
}
|
||||
StatementKind::Expression => match pipe_info.previous_results.clone() {
|
||||
StatementKind::Expression => match exec_state.pipe_value.clone() {
|
||||
Some(x) => x,
|
||||
None => {
|
||||
return Err(KclError::Semantic(KclErrorDetails {
|
||||
@ -1983,20 +1913,10 @@ impl ExecutorContext {
|
||||
}
|
||||
},
|
||||
},
|
||||
Expr::ArrayExpression(array_expression) => {
|
||||
array_expression.execute(memory, dynamic_state, pipe_info, self).await?
|
||||
}
|
||||
Expr::ObjectExpression(object_expression) => {
|
||||
object_expression
|
||||
.execute(memory, dynamic_state, pipe_info, self)
|
||||
.await?
|
||||
}
|
||||
Expr::MemberExpression(member_expression) => member_expression.get_result(memory)?,
|
||||
Expr::UnaryExpression(unary_expression) => {
|
||||
unary_expression
|
||||
.get_result(memory, dynamic_state, pipe_info, self)
|
||||
.await?
|
||||
}
|
||||
Expr::ArrayExpression(array_expression) => array_expression.execute(exec_state, self).await?,
|
||||
Expr::ObjectExpression(object_expression) => object_expression.execute(exec_state, self).await?,
|
||||
Expr::MemberExpression(member_expression) => member_expression.get_result(exec_state)?,
|
||||
Expr::UnaryExpression(unary_expression) => unary_expression.get_result(exec_state, self).await?,
|
||||
};
|
||||
Ok(item)
|
||||
}
|
||||
@ -2097,6 +2017,36 @@ fn assign_args_to_params(
|
||||
Ok(fn_memory)
|
||||
}
|
||||
|
||||
pub(crate) async fn call_user_defined_function(
|
||||
args: Vec<KclValue>,
|
||||
memory: &ProgramMemory,
|
||||
function_expression: &FunctionExpression,
|
||||
exec_state: &mut ExecState,
|
||||
ctx: &ExecutorContext,
|
||||
) -> Result<Option<KclValue>, KclError> {
|
||||
// Create a new environment to execute the function body in so that local
|
||||
// variables shadow variables in the parent scope. The new environment's
|
||||
// parent should be the environment of the closure.
|
||||
let mut body_memory = memory.clone();
|
||||
let body_env = body_memory.new_env_for_call(memory.current_env);
|
||||
body_memory.current_env = body_env;
|
||||
let fn_memory = assign_args_to_params(function_expression, args, body_memory)?;
|
||||
|
||||
// Execute the function body using the memory we just created.
|
||||
let (result, fn_memory) = {
|
||||
let previous_memory = std::mem::replace(&mut exec_state.memory, fn_memory);
|
||||
let result = ctx
|
||||
.inner_execute(&function_expression.body, exec_state, BodyType::Block)
|
||||
.await;
|
||||
// Restore the previous memory.
|
||||
let fn_memory = std::mem::replace(&mut exec_state.memory, previous_memory);
|
||||
|
||||
(result, fn_memory)
|
||||
};
|
||||
|
||||
result.map(|()| fn_memory.return_)
|
||||
}
|
||||
|
||||
pub enum StatementKind<'a> {
|
||||
Declaration { name: &'a str },
|
||||
Expression,
|
||||
@ -2122,9 +2072,9 @@ mod tests {
|
||||
settings: Default::default(),
|
||||
is_mock: true,
|
||||
};
|
||||
let memory = ctx.run(&program, None).await?;
|
||||
let exec_state = ctx.run(&program, None).await?;
|
||||
|
||||
Ok(memory)
|
||||
Ok(exec_state.memory)
|
||||
}
|
||||
|
||||
/// Convenience function to get a JSON value from memory and unwrap.
|
||||
|
@ -3,30 +3,36 @@ use schemars::JsonSchema;
|
||||
use crate::{
|
||||
ast::types::FunctionExpression,
|
||||
errors::KclError,
|
||||
executor::{DynamicState, ExecutorContext, KclValue, MemoryFunction, Metadata, ProgramMemory},
|
||||
executor::{
|
||||
call_user_defined_function, ExecState, ExecutorContext, KclValue, MemoryFunction, Metadata, ProgramMemory,
|
||||
},
|
||||
};
|
||||
|
||||
/// A function being used as a parameter into a stdlib function.
|
||||
/// A function being used as a parameter into a stdlib function. This is a
|
||||
/// closure, plus everything needed to execute it.
|
||||
pub struct FunctionParam<'a> {
|
||||
pub inner: &'a MemoryFunction,
|
||||
pub inner: Option<&'a MemoryFunction>,
|
||||
pub memory: ProgramMemory,
|
||||
pub dynamic_state: DynamicState,
|
||||
pub fn_expr: Box<FunctionExpression>,
|
||||
pub meta: Vec<Metadata>,
|
||||
pub ctx: ExecutorContext,
|
||||
}
|
||||
|
||||
impl<'a> FunctionParam<'a> {
|
||||
pub async fn call(&self, args: Vec<KclValue>) -> Result<Option<KclValue>, KclError> {
|
||||
(self.inner)(
|
||||
pub async fn call(&self, exec_state: &mut ExecState, args: Vec<KclValue>) -> Result<Option<KclValue>, KclError> {
|
||||
if let Some(inner) = self.inner {
|
||||
inner(
|
||||
args,
|
||||
self.memory.clone(),
|
||||
self.fn_expr.clone(),
|
||||
self.meta.clone(),
|
||||
self.dynamic_state.clone(),
|
||||
exec_state,
|
||||
self.ctx.clone(),
|
||||
)
|
||||
.await
|
||||
} else {
|
||||
call_user_defined_function(args, &self.memory, self.fn_expr.as_ref(), exec_state, &self.ctx).await
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -591,8 +591,8 @@ impl Backend {
|
||||
// Clear the scene, before we execute so it's not fugly as shit.
|
||||
executor_ctx.engine.clear_scene(SourceRange::default()).await?;
|
||||
|
||||
let memory = match executor_ctx.run(ast, None).await {
|
||||
Ok(memory) => memory,
|
||||
let exec_state = match executor_ctx.run(ast, None).await {
|
||||
Ok(exec_state) => exec_state,
|
||||
Err(err) => {
|
||||
self.memory_map.remove(params.uri.as_str());
|
||||
self.add_to_diagnostics(params, &[err], false).await;
|
||||
@ -603,11 +603,12 @@ impl Backend {
|
||||
}
|
||||
};
|
||||
|
||||
self.memory_map.insert(params.uri.to_string(), memory.clone());
|
||||
self.memory_map
|
||||
.insert(params.uri.to_string(), exec_state.memory.clone());
|
||||
|
||||
// Send the notification to the client that the memory was updated.
|
||||
self.client
|
||||
.send_notification::<custom_notifications::MemoryUpdated>(memory)
|
||||
.send_notification::<custom_notifications::MemoryUpdated>(exec_state.memory)
|
||||
.await;
|
||||
|
||||
Ok(())
|
||||
|
@ -8,8 +8,8 @@ use crate::{
|
||||
ast::types::{parse_json_number_as_f64, TagDeclarator},
|
||||
errors::{KclError, KclErrorDetails},
|
||||
executor::{
|
||||
DynamicState, ExecutorContext, ExtrudeGroup, ExtrudeGroupSet, ExtrudeSurface, KclValue, Metadata,
|
||||
ProgramMemory, SketchGroup, SketchGroupSet, SketchSurface, SourceRange, TagIdentifier,
|
||||
ExecState, ExecutorContext, ExtrudeGroup, ExtrudeGroupSet, ExtrudeSurface, KclValue, Metadata, SketchGroup,
|
||||
SketchGroupSet, SketchSurface, SourceRange, TagIdentifier,
|
||||
},
|
||||
std::{shapes::SketchSurfaceOrGroup, sketch::FaceTag, FnAsArg},
|
||||
};
|
||||
@ -19,24 +19,14 @@ pub struct Args {
|
||||
pub args: Vec<KclValue>,
|
||||
pub source_range: SourceRange,
|
||||
pub ctx: ExecutorContext,
|
||||
pub current_program_memory: ProgramMemory,
|
||||
pub dynamic_state: DynamicState,
|
||||
}
|
||||
|
||||
impl Args {
|
||||
pub fn new(
|
||||
args: Vec<KclValue>,
|
||||
source_range: SourceRange,
|
||||
ctx: ExecutorContext,
|
||||
current_program_memory: ProgramMemory,
|
||||
dynamic_state: DynamicState,
|
||||
) -> Self {
|
||||
pub fn new(args: Vec<KclValue>, source_range: SourceRange, ctx: ExecutorContext) -> Self {
|
||||
Self {
|
||||
args,
|
||||
source_range,
|
||||
ctx,
|
||||
current_program_memory,
|
||||
dynamic_state,
|
||||
}
|
||||
}
|
||||
|
||||
@ -54,8 +44,6 @@ impl Args {
|
||||
settings: Default::default(),
|
||||
is_mock: true,
|
||||
},
|
||||
current_program_memory: ProgramMemory::default(),
|
||||
dynamic_state: DynamicState::default(),
|
||||
})
|
||||
}
|
||||
|
||||
@ -88,11 +76,12 @@ impl Args {
|
||||
self.ctx.engine.send_modeling_cmd(id, self.source_range, cmd).await
|
||||
}
|
||||
|
||||
fn get_tag_info_from_memory<'a>(
|
||||
fn get_tag_info_from_memory<'a, 'e>(
|
||||
&'a self,
|
||||
exec_state: &'e mut ExecState,
|
||||
tag: &'a TagIdentifier,
|
||||
) -> Result<&'a crate::executor::TagEngineInfo, KclError> {
|
||||
if let KclValue::TagIdentifier(t) = self.current_program_memory.get(&tag.value, self.source_range)? {
|
||||
) -> Result<&'e crate::executor::TagEngineInfo, KclError> {
|
||||
if let KclValue::TagIdentifier(t) = exec_state.memory.get(&tag.value, self.source_range)? {
|
||||
Ok(t.info.as_ref().ok_or_else(|| {
|
||||
KclError::Type(KclErrorDetails {
|
||||
message: format!("Tag `{}` does not have engine info", tag.value),
|
||||
@ -107,34 +96,43 @@ impl Args {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn get_tag_engine_info<'a>(
|
||||
pub(crate) fn get_tag_engine_info<'a, 'e>(
|
||||
&'a self,
|
||||
exec_state: &'e mut ExecState,
|
||||
tag: &'a TagIdentifier,
|
||||
) -> Result<&'a crate::executor::TagEngineInfo, KclError> {
|
||||
) -> Result<&'a crate::executor::TagEngineInfo, KclError>
|
||||
where
|
||||
'e: 'a,
|
||||
{
|
||||
if let Some(info) = &tag.info {
|
||||
return Ok(info);
|
||||
}
|
||||
|
||||
self.get_tag_info_from_memory(tag)
|
||||
self.get_tag_info_from_memory(exec_state, tag)
|
||||
}
|
||||
|
||||
fn get_tag_engine_info_check_surface<'a>(
|
||||
fn get_tag_engine_info_check_surface<'a, 'e>(
|
||||
&'a self,
|
||||
exec_state: &'e mut ExecState,
|
||||
tag: &'a TagIdentifier,
|
||||
) -> Result<&'a crate::executor::TagEngineInfo, KclError> {
|
||||
) -> Result<&'a crate::executor::TagEngineInfo, KclError>
|
||||
where
|
||||
'e: 'a,
|
||||
{
|
||||
if let Some(info) = &tag.info {
|
||||
if info.surface.is_some() {
|
||||
return Ok(info);
|
||||
}
|
||||
}
|
||||
|
||||
self.get_tag_info_from_memory(tag)
|
||||
self.get_tag_info_from_memory(exec_state, tag)
|
||||
}
|
||||
|
||||
/// Flush just the fillets and chamfers for this specific ExtrudeGroupSet.
|
||||
#[allow(clippy::vec_box)]
|
||||
pub(crate) async fn flush_batch_for_extrude_group_set(
|
||||
&self,
|
||||
exec_state: &mut ExecState,
|
||||
extrude_groups: Vec<Box<ExtrudeGroup>>,
|
||||
) -> Result<(), KclError> {
|
||||
// Make sure we don't traverse sketch_groups more than once.
|
||||
@ -148,12 +146,13 @@ impl Args {
|
||||
if !traversed_sketch_groups.contains(&sketch_group_id) {
|
||||
// Find all the extrude groups on the same shared sketch group.
|
||||
ids.extend(
|
||||
self.current_program_memory
|
||||
exec_state
|
||||
.memory
|
||||
.find_extrude_groups_on_sketch_group(extrude_group.sketch_group.id)
|
||||
.iter()
|
||||
.flat_map(|eg| eg.get_all_edge_cut_ids()),
|
||||
);
|
||||
ids.extend(self.dynamic_state.edge_cut_ids_on_sketch_group(sketch_group_id));
|
||||
ids.extend(exec_state.dynamic_state.edge_cut_ids_on_sketch_group(sketch_group_id));
|
||||
traversed_sketch_groups.push(sketch_group_id);
|
||||
}
|
||||
|
||||
@ -380,6 +379,7 @@ impl Args {
|
||||
|
||||
pub(crate) async fn get_adjacent_face_to_tag(
|
||||
&self,
|
||||
exec_state: &mut ExecState,
|
||||
tag: &TagIdentifier,
|
||||
must_be_planar: bool,
|
||||
) -> Result<uuid::Uuid, KclError> {
|
||||
@ -390,7 +390,7 @@ impl Args {
|
||||
}));
|
||||
}
|
||||
|
||||
let engine_info = self.get_tag_engine_info_check_surface(tag)?;
|
||||
let engine_info = self.get_tag_engine_info_check_surface(exec_state, tag)?;
|
||||
|
||||
let surface = engine_info.surface.as_ref().ok_or_else(|| {
|
||||
KclError::Type(KclErrorDetails {
|
||||
|
@ -3,14 +3,14 @@ use schemars::JsonSchema;
|
||||
|
||||
use crate::{
|
||||
errors::{KclError, KclErrorDetails},
|
||||
executor::{KclValue, SketchGroup, SourceRange, UserVal},
|
||||
executor::{ExecState, KclValue, SketchGroup, SourceRange, UserVal},
|
||||
function_param::FunctionParam,
|
||||
};
|
||||
|
||||
use super::{args::FromArgs, Args, FnAsArg};
|
||||
|
||||
/// For each item in an array, update a value.
|
||||
pub async fn array_reduce(args: Args) -> Result<KclValue, KclError> {
|
||||
pub async fn array_reduce(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let (array, start, f): (Vec<u64>, SketchGroup, FnAsArg<'_>) = FromArgs::from_args(&args, 0)?;
|
||||
let reduce_fn = FunctionParam {
|
||||
inner: f.func,
|
||||
@ -18,9 +18,8 @@ pub async fn array_reduce(args: Args) -> Result<KclValue, KclError> {
|
||||
meta: vec![args.source_range.into()],
|
||||
ctx: args.ctx.clone(),
|
||||
memory: *f.memory,
|
||||
dynamic_state: args.dynamic_state.clone(),
|
||||
};
|
||||
inner_array_reduce(array, start, reduce_fn, &args)
|
||||
inner_array_reduce(array, start, reduce_fn, exec_state, &args)
|
||||
.await
|
||||
.map(|sg| KclValue::UserVal(UserVal::set(sg.meta.clone(), sg)))
|
||||
}
|
||||
@ -46,11 +45,12 @@ async fn inner_array_reduce<'a>(
|
||||
array: Vec<u64>,
|
||||
start: SketchGroup,
|
||||
reduce_fn: FunctionParam<'a>,
|
||||
exec_state: &mut ExecState,
|
||||
args: &'a Args,
|
||||
) -> Result<SketchGroup, KclError> {
|
||||
let mut reduced = start;
|
||||
for i in array {
|
||||
reduced = call_reduce_closure(i, reduced, &reduce_fn, args.source_range).await?;
|
||||
reduced = call_reduce_closure(i, reduced, &reduce_fn, args.source_range, exec_state).await?;
|
||||
}
|
||||
|
||||
Ok(reduced)
|
||||
@ -61,6 +61,7 @@ async fn call_reduce_closure<'a>(
|
||||
start: SketchGroup,
|
||||
reduce_fn: &FunctionParam<'a>,
|
||||
source_range: SourceRange,
|
||||
exec_state: &mut ExecState,
|
||||
) -> Result<SketchGroup, KclError> {
|
||||
// Call the reduce fn for this repetition.
|
||||
let reduce_fn_args = vec![
|
||||
@ -70,7 +71,7 @@ async fn call_reduce_closure<'a>(
|
||||
}),
|
||||
KclValue::new_user_val(start.meta.clone(), start),
|
||||
];
|
||||
let transform_fn_return = reduce_fn.call(reduce_fn_args).await?;
|
||||
let transform_fn_return = reduce_fn.call(exec_state, reduce_fn_args).await?;
|
||||
|
||||
// Unpack the returned transform object.
|
||||
let source_ranges = vec![source_range];
|
||||
|
@ -6,7 +6,7 @@ use schemars::JsonSchema;
|
||||
|
||||
use crate::{
|
||||
errors::{KclError, KclErrorDetails},
|
||||
executor::KclValue,
|
||||
executor::{ExecState, KclValue},
|
||||
std::Args,
|
||||
};
|
||||
|
||||
@ -22,7 +22,7 @@ async fn _assert(value: bool, message: &str, args: &Args) -> Result<(), KclError
|
||||
|
||||
/// Check that the provided value is true, or raise a [KclError]
|
||||
/// with the provided description.
|
||||
pub async fn assert(args: Args) -> Result<KclValue, KclError> {
|
||||
pub async fn assert(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let (data, description): (bool, String) = args.get_data()?;
|
||||
inner_assert(data, &description, &args).await?;
|
||||
args.make_null_user_val()
|
||||
@ -42,7 +42,7 @@ async fn inner_assert(data: bool, message: &str, args: &Args) -> Result<(), KclE
|
||||
_assert(data, message, args).await
|
||||
}
|
||||
|
||||
pub async fn assert_lt(args: Args) -> Result<KclValue, KclError> {
|
||||
pub async fn assert_lt(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let (left, right, description): (f64, f64, String) = args.get_data()?;
|
||||
inner_assert_lt(left, right, &description, &args).await?;
|
||||
args.make_null_user_val()
|
||||
@ -61,7 +61,7 @@ async fn inner_assert_lt(left: f64, right: f64, message: &str, args: &Args) -> R
|
||||
_assert(left < right, message, args).await
|
||||
}
|
||||
|
||||
pub async fn assert_gt(args: Args) -> Result<KclValue, KclError> {
|
||||
pub async fn assert_gt(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let (left, right, description): (f64, f64, String) = args.get_data()?;
|
||||
inner_assert_gt(left, right, &description, &args).await?;
|
||||
args.make_null_user_val()
|
||||
@ -89,7 +89,7 @@ async fn inner_assert_equal(left: f64, right: f64, epsilon: f64, message: &str,
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn assert_equal(args: Args) -> Result<KclValue, KclError> {
|
||||
pub async fn assert_equal(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let (left, right, epsilon, description): (f64, f64, f64, String) = args.get_data()?;
|
||||
inner_assert_equal(left, right, epsilon, &description, &args).await?;
|
||||
args.make_null_user_val()
|
||||
@ -108,7 +108,7 @@ async fn inner_assert_gt(left: f64, right: f64, message: &str, args: &Args) -> R
|
||||
_assert(left > right, message, args).await
|
||||
}
|
||||
|
||||
pub async fn assert_lte(args: Args) -> Result<KclValue, KclError> {
|
||||
pub async fn assert_lte(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let (left, right, description): (f64, f64, String) = args.get_data()?;
|
||||
inner_assert_lte(left, right, &description, &args).await?;
|
||||
args.make_null_user_val()
|
||||
@ -128,7 +128,7 @@ async fn inner_assert_lte(left: f64, right: f64, message: &str, args: &Args) ->
|
||||
_assert(left <= right, message, args).await
|
||||
}
|
||||
|
||||
pub async fn assert_gte(args: Args) -> Result<KclValue, KclError> {
|
||||
pub async fn assert_gte(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let (left, right, description): (f64, f64, String) = args.get_data()?;
|
||||
inner_assert_gte(left, right, &description, &args).await?;
|
||||
args.make_null_user_val()
|
||||
|
@ -9,7 +9,7 @@ use serde::{Deserialize, Serialize};
|
||||
use crate::{
|
||||
ast::types::TagDeclarator,
|
||||
errors::{KclError, KclErrorDetails},
|
||||
executor::{ChamferSurface, EdgeCut, ExtrudeGroup, ExtrudeSurface, GeoMeta, KclValue},
|
||||
executor::{ChamferSurface, EdgeCut, ExecState, ExtrudeGroup, ExtrudeSurface, GeoMeta, KclValue},
|
||||
std::{fillet::EdgeReference, Args},
|
||||
};
|
||||
|
||||
@ -27,11 +27,11 @@ pub struct ChamferData {
|
||||
}
|
||||
|
||||
/// Create chamfers on tagged paths.
|
||||
pub async fn chamfer(args: Args) -> Result<KclValue, KclError> {
|
||||
pub async fn chamfer(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let (data, extrude_group, tag): (ChamferData, Box<ExtrudeGroup>, Option<TagDeclarator>) =
|
||||
args.get_data_and_extrude_group_and_tag()?;
|
||||
|
||||
let extrude_group = inner_chamfer(data, extrude_group, tag, args).await?;
|
||||
let extrude_group = inner_chamfer(data, extrude_group, tag, exec_state, args).await?;
|
||||
Ok(KclValue::ExtrudeGroup(extrude_group))
|
||||
}
|
||||
|
||||
@ -103,6 +103,7 @@ async fn inner_chamfer(
|
||||
data: ChamferData,
|
||||
extrude_group: Box<ExtrudeGroup>,
|
||||
tag: Option<TagDeclarator>,
|
||||
exec_state: &mut ExecState,
|
||||
args: Args,
|
||||
) -> Result<Box<ExtrudeGroup>, KclError> {
|
||||
// Check if tags contains any duplicate values.
|
||||
@ -130,7 +131,7 @@ async fn inner_chamfer(
|
||||
for edge_tag in data.tags {
|
||||
let edge_id = match edge_tag {
|
||||
EdgeReference::Uuid(uuid) => uuid,
|
||||
EdgeReference::Tag(edge_tag) => args.get_tag_engine_info(&edge_tag)?.id,
|
||||
EdgeReference::Tag(edge_tag) => args.get_tag_engine_info(exec_state, &edge_tag)?.id,
|
||||
};
|
||||
|
||||
let id = uuid::Uuid::new_v4();
|
||||
|
@ -5,7 +5,7 @@ use schemars::JsonSchema;
|
||||
|
||||
use crate::{
|
||||
errors::{KclError, KclErrorDetails},
|
||||
executor::{KclValue, SourceRange},
|
||||
executor::{ExecState, KclValue, SourceRange},
|
||||
std::Args,
|
||||
};
|
||||
|
||||
@ -31,7 +31,7 @@ impl ConversionError {
|
||||
}
|
||||
|
||||
/// Converts a number to integer.
|
||||
pub async fn int(args: Args) -> Result<KclValue, KclError> {
|
||||
pub async fn int(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let num = args.get_number()?;
|
||||
let converted = inner_int(num).map_err(|err| err.into_kcl_error(args.source_range))?;
|
||||
|
||||
|
@ -11,14 +11,14 @@ use uuid::Uuid;
|
||||
use crate::{
|
||||
errors::{KclError, KclErrorDetails},
|
||||
executor::{
|
||||
ExtrudeGroup, ExtrudeGroupSet, ExtrudeSurface, GeoMeta, KclValue, Path, SketchGroup, SketchGroupSet,
|
||||
ExecState, ExtrudeGroup, ExtrudeGroupSet, ExtrudeSurface, GeoMeta, KclValue, Path, SketchGroup, SketchGroupSet,
|
||||
SketchSurface,
|
||||
},
|
||||
std::Args,
|
||||
};
|
||||
|
||||
/// Extrudes by a given amount.
|
||||
pub async fn extrude(args: Args) -> Result<KclValue, KclError> {
|
||||
pub async fn extrude(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let (length, sketch_group_set) = args.get_number_sketch_group_set()?;
|
||||
|
||||
let result = inner_extrude(length, sketch_group_set, args).await?;
|
||||
|
@ -10,7 +10,9 @@ use uuid::Uuid;
|
||||
use crate::{
|
||||
ast::types::TagDeclarator,
|
||||
errors::{KclError, KclErrorDetails},
|
||||
executor::{EdgeCut, ExtrudeGroup, ExtrudeSurface, FilletSurface, GeoMeta, KclValue, TagIdentifier, UserVal},
|
||||
executor::{
|
||||
EdgeCut, ExecState, ExtrudeGroup, ExtrudeSurface, FilletSurface, GeoMeta, KclValue, TagIdentifier, UserVal,
|
||||
},
|
||||
settings::types::UnitLength,
|
||||
std::Args,
|
||||
};
|
||||
@ -41,11 +43,11 @@ pub enum EdgeReference {
|
||||
}
|
||||
|
||||
/// Create fillets on tagged paths.
|
||||
pub async fn fillet(args: Args) -> Result<KclValue, KclError> {
|
||||
pub async fn fillet(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let (data, extrude_group, tag): (FilletData, Box<ExtrudeGroup>, Option<TagDeclarator>) =
|
||||
args.get_data_and_extrude_group_and_tag()?;
|
||||
|
||||
let extrude_group = inner_fillet(data, extrude_group, tag, args).await?;
|
||||
let extrude_group = inner_fillet(data, extrude_group, tag, exec_state, args).await?;
|
||||
Ok(KclValue::ExtrudeGroup(extrude_group))
|
||||
}
|
||||
|
||||
@ -112,6 +114,7 @@ async fn inner_fillet(
|
||||
data: FilletData,
|
||||
extrude_group: Box<ExtrudeGroup>,
|
||||
tag: Option<TagDeclarator>,
|
||||
exec_state: &mut ExecState,
|
||||
args: Args,
|
||||
) -> Result<Box<ExtrudeGroup>, KclError> {
|
||||
// Check if tags contains any duplicate values.
|
||||
@ -130,7 +133,7 @@ async fn inner_fillet(
|
||||
for edge_tag in data.tags {
|
||||
let edge_id = match edge_tag {
|
||||
EdgeReference::Uuid(uuid) => uuid,
|
||||
EdgeReference::Tag(edge_tag) => args.get_tag_engine_info(&edge_tag)?.id,
|
||||
EdgeReference::Tag(edge_tag) => args.get_tag_engine_info(exec_state, &edge_tag)?.id,
|
||||
};
|
||||
|
||||
let id = uuid::Uuid::new_v4();
|
||||
@ -172,10 +175,10 @@ async fn inner_fillet(
|
||||
}
|
||||
|
||||
/// Get the opposite edge to the edge given.
|
||||
pub async fn get_opposite_edge(args: Args) -> Result<KclValue, KclError> {
|
||||
pub async fn get_opposite_edge(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let tag: TagIdentifier = args.get_data()?;
|
||||
|
||||
let edge = inner_get_opposite_edge(tag, args.clone()).await?;
|
||||
let edge = inner_get_opposite_edge(tag, exec_state, args.clone()).await?;
|
||||
Ok(KclValue::UserVal(UserVal {
|
||||
value: serde_json::to_value(edge).map_err(|e| {
|
||||
KclError::Type(KclErrorDetails {
|
||||
@ -217,13 +220,13 @@ pub async fn get_opposite_edge(args: Args) -> Result<KclValue, KclError> {
|
||||
#[stdlib {
|
||||
name = "getOppositeEdge",
|
||||
}]
|
||||
async fn inner_get_opposite_edge(tag: TagIdentifier, args: Args) -> Result<Uuid, KclError> {
|
||||
async fn inner_get_opposite_edge(tag: TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<Uuid, KclError> {
|
||||
if args.ctx.is_mock {
|
||||
return Ok(Uuid::new_v4());
|
||||
}
|
||||
let tagged_path = args.get_tag_engine_info(&tag)?;
|
||||
let face_id = args.get_adjacent_face_to_tag(exec_state, &tag, false).await?;
|
||||
|
||||
let face_id = args.get_adjacent_face_to_tag(&tag, false).await?;
|
||||
let tagged_path = args.get_tag_engine_info(exec_state, &tag)?;
|
||||
|
||||
let resp = args
|
||||
.send_modeling_cmd(
|
||||
@ -249,10 +252,10 @@ async fn inner_get_opposite_edge(tag: TagIdentifier, args: Args) -> Result<Uuid,
|
||||
}
|
||||
|
||||
/// Get the next adjacent edge to the edge given.
|
||||
pub async fn get_next_adjacent_edge(args: Args) -> Result<KclValue, KclError> {
|
||||
pub async fn get_next_adjacent_edge(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let tag: TagIdentifier = args.get_data()?;
|
||||
|
||||
let edge = inner_get_next_adjacent_edge(tag, args.clone()).await?;
|
||||
let edge = inner_get_next_adjacent_edge(tag, exec_state, args.clone()).await?;
|
||||
Ok(KclValue::UserVal(UserVal {
|
||||
value: serde_json::to_value(edge).map_err(|e| {
|
||||
KclError::Type(KclErrorDetails {
|
||||
@ -294,13 +297,17 @@ pub async fn get_next_adjacent_edge(args: Args) -> Result<KclValue, KclError> {
|
||||
#[stdlib {
|
||||
name = "getNextAdjacentEdge",
|
||||
}]
|
||||
async fn inner_get_next_adjacent_edge(tag: TagIdentifier, args: Args) -> Result<Uuid, KclError> {
|
||||
async fn inner_get_next_adjacent_edge(
|
||||
tag: TagIdentifier,
|
||||
exec_state: &mut ExecState,
|
||||
args: Args,
|
||||
) -> Result<Uuid, KclError> {
|
||||
if args.ctx.is_mock {
|
||||
return Ok(Uuid::new_v4());
|
||||
}
|
||||
let tagged_path = args.get_tag_engine_info(&tag)?;
|
||||
let face_id = args.get_adjacent_face_to_tag(exec_state, &tag, false).await?;
|
||||
|
||||
let face_id = args.get_adjacent_face_to_tag(&tag, false).await?;
|
||||
let tagged_path = args.get_tag_engine_info(exec_state, &tag)?;
|
||||
|
||||
let resp = args
|
||||
.send_modeling_cmd(
|
||||
@ -331,10 +338,10 @@ async fn inner_get_next_adjacent_edge(tag: TagIdentifier, args: Args) -> Result<
|
||||
}
|
||||
|
||||
/// Get the previous adjacent edge to the edge given.
|
||||
pub async fn get_previous_adjacent_edge(args: Args) -> Result<KclValue, KclError> {
|
||||
pub async fn get_previous_adjacent_edge(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let tag: TagIdentifier = args.get_data()?;
|
||||
|
||||
let edge = inner_get_previous_adjacent_edge(tag, args.clone()).await?;
|
||||
let edge = inner_get_previous_adjacent_edge(tag, exec_state, args.clone()).await?;
|
||||
Ok(KclValue::UserVal(UserVal {
|
||||
value: serde_json::to_value(edge).map_err(|e| {
|
||||
KclError::Type(KclErrorDetails {
|
||||
@ -376,13 +383,17 @@ pub async fn get_previous_adjacent_edge(args: Args) -> Result<KclValue, KclError
|
||||
#[stdlib {
|
||||
name = "getPreviousAdjacentEdge",
|
||||
}]
|
||||
async fn inner_get_previous_adjacent_edge(tag: TagIdentifier, args: Args) -> Result<Uuid, KclError> {
|
||||
async fn inner_get_previous_adjacent_edge(
|
||||
tag: TagIdentifier,
|
||||
exec_state: &mut ExecState,
|
||||
args: Args,
|
||||
) -> Result<Uuid, KclError> {
|
||||
if args.ctx.is_mock {
|
||||
return Ok(Uuid::new_v4());
|
||||
}
|
||||
let tagged_path = args.get_tag_engine_info(&tag)?;
|
||||
let face_id = args.get_adjacent_face_to_tag(exec_state, &tag, false).await?;
|
||||
|
||||
let face_id = args.get_adjacent_face_to_tag(&tag, false).await?;
|
||||
let tagged_path = args.get_tag_engine_info(exec_state, &tag)?;
|
||||
|
||||
let resp = args
|
||||
.send_modeling_cmd(
|
||||
|
@ -8,7 +8,7 @@ use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
errors::KclError,
|
||||
executor::{ExtrudeGroup, KclValue},
|
||||
executor::{ExecState, ExtrudeGroup, KclValue},
|
||||
std::Args,
|
||||
};
|
||||
|
||||
@ -31,7 +31,7 @@ pub struct HelixData {
|
||||
}
|
||||
|
||||
/// Create a helix on a cylinder.
|
||||
pub async fn helix(args: Args) -> Result<KclValue, KclError> {
|
||||
pub async fn helix(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let (data, extrude_group): (HelixData, Box<ExtrudeGroup>) = args.get_data_and_extrude_group()?;
|
||||
|
||||
let extrude_group = inner_helix(data, extrude_group, args).await?;
|
||||
|
@ -9,7 +9,7 @@ use schemars::JsonSchema;
|
||||
|
||||
use crate::{
|
||||
errors::{KclError, KclErrorDetails},
|
||||
executor::{ImportedGeometry, KclValue},
|
||||
executor::{ExecState, ImportedGeometry, KclValue},
|
||||
fs::FileSystem,
|
||||
std::Args,
|
||||
};
|
||||
@ -117,7 +117,7 @@ impl From<ImportFormat> for kittycad::types::InputFormat {
|
||||
///
|
||||
/// Import paths are relative to the current project directory. This only works in the desktop app
|
||||
/// not in browser.
|
||||
pub async fn import(args: Args) -> Result<KclValue, KclError> {
|
||||
pub async fn import(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let (file_path, options): (String, Option<ImportFormat>) = args.get_import_data()?;
|
||||
|
||||
let imported_geometry = inner_import(file_path, options, args).await?;
|
||||
|
@ -8,7 +8,7 @@ use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
errors::{KclError, KclErrorDetails},
|
||||
executor::{ExtrudeGroup, KclValue, SketchGroup},
|
||||
executor::{ExecState, ExtrudeGroup, KclValue, SketchGroup},
|
||||
std::{extrude::do_post_extrude, fillet::default_tolerance, Args},
|
||||
};
|
||||
|
||||
@ -49,7 +49,7 @@ impl Default for LoftData {
|
||||
}
|
||||
|
||||
/// Create a 3D surface or solid by interpolating between two or more sketches.
|
||||
pub async fn loft(args: Args) -> Result<KclValue, KclError> {
|
||||
pub async fn loft(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let (sketch_groups, data): (Vec<SketchGroup>, Option<LoftData>) = args.get_sketch_groups_and_data()?;
|
||||
|
||||
let extrude_group = inner_loft(sketch_groups, data, args).await?;
|
||||
|
@ -6,12 +6,12 @@ use schemars::JsonSchema;
|
||||
|
||||
use crate::{
|
||||
errors::{KclError, KclErrorDetails},
|
||||
executor::KclValue,
|
||||
executor::{ExecState, KclValue},
|
||||
std::Args,
|
||||
};
|
||||
|
||||
/// Compute the cosine of a number (in radians).
|
||||
pub async fn cos(args: Args) -> Result<KclValue, KclError> {
|
||||
pub async fn cos(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let num = args.get_number()?;
|
||||
let result = inner_cos(num)?;
|
||||
|
||||
@ -41,7 +41,7 @@ fn inner_cos(num: f64) -> Result<f64, KclError> {
|
||||
}
|
||||
|
||||
/// Compute the sine of a number (in radians).
|
||||
pub async fn sin(args: Args) -> Result<KclValue, KclError> {
|
||||
pub async fn sin(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let num = args.get_number()?;
|
||||
let result = inner_sin(num)?;
|
||||
|
||||
@ -71,7 +71,7 @@ fn inner_sin(num: f64) -> Result<f64, KclError> {
|
||||
}
|
||||
|
||||
/// Compute the tangent of a number (in radians).
|
||||
pub async fn tan(args: Args) -> Result<KclValue, KclError> {
|
||||
pub async fn tan(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let num = args.get_number()?;
|
||||
let result = inner_tan(num)?;
|
||||
|
||||
@ -101,7 +101,7 @@ fn inner_tan(num: f64) -> Result<f64, KclError> {
|
||||
}
|
||||
|
||||
/// Return the value of `pi`. Archimedes’ constant (π).
|
||||
pub async fn pi(args: Args) -> Result<KclValue, KclError> {
|
||||
pub async fn pi(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let result = inner_pi()?;
|
||||
|
||||
args.make_user_val_from_f64(result)
|
||||
@ -126,7 +126,7 @@ fn inner_pi() -> Result<f64, KclError> {
|
||||
}
|
||||
|
||||
/// Compute the square root of a number.
|
||||
pub async fn sqrt(args: Args) -> Result<KclValue, KclError> {
|
||||
pub async fn sqrt(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let num = args.get_number()?;
|
||||
let result = inner_sqrt(num)?;
|
||||
|
||||
@ -156,7 +156,7 @@ fn inner_sqrt(num: f64) -> Result<f64, KclError> {
|
||||
}
|
||||
|
||||
/// Compute the absolute value of a number.
|
||||
pub async fn abs(args: Args) -> Result<KclValue, KclError> {
|
||||
pub async fn abs(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let num = args.get_number()?;
|
||||
let result = inner_abs(num)?;
|
||||
|
||||
@ -193,7 +193,7 @@ fn inner_abs(num: f64) -> Result<f64, KclError> {
|
||||
}
|
||||
|
||||
/// Compute the largest integer less than or equal to a number.
|
||||
pub async fn floor(args: Args) -> Result<KclValue, KclError> {
|
||||
pub async fn floor(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let num = args.get_number()?;
|
||||
let result = inner_floor(num)?;
|
||||
|
||||
@ -221,7 +221,7 @@ fn inner_floor(num: f64) -> Result<f64, KclError> {
|
||||
}
|
||||
|
||||
/// Compute the smallest integer greater than or equal to a number.
|
||||
pub async fn ceil(args: Args) -> Result<KclValue, KclError> {
|
||||
pub async fn ceil(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let num = args.get_number()?;
|
||||
let result = inner_ceil(num)?;
|
||||
|
||||
@ -249,7 +249,7 @@ fn inner_ceil(num: f64) -> Result<f64, KclError> {
|
||||
}
|
||||
|
||||
/// Compute the minimum of the given arguments.
|
||||
pub async fn min(args: Args) -> Result<KclValue, KclError> {
|
||||
pub async fn min(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let nums = args.get_number_array()?;
|
||||
let result = inner_min(nums);
|
||||
|
||||
@ -286,7 +286,7 @@ fn inner_min(args: Vec<f64>) -> f64 {
|
||||
}
|
||||
|
||||
/// Compute the maximum of the given arguments.
|
||||
pub async fn max(args: Args) -> Result<KclValue, KclError> {
|
||||
pub async fn max(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let nums = args.get_number_array()?;
|
||||
let result = inner_max(nums);
|
||||
|
||||
@ -323,7 +323,7 @@ fn inner_max(args: Vec<f64>) -> f64 {
|
||||
}
|
||||
|
||||
/// Compute the number to a power.
|
||||
pub async fn pow(args: Args) -> Result<KclValue, KclError> {
|
||||
pub async fn pow(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let nums = args.get_number_array()?;
|
||||
if nums.len() > 2 {
|
||||
return Err(KclError::Type(KclErrorDetails {
|
||||
@ -367,7 +367,7 @@ fn inner_pow(num: f64, pow: f64) -> Result<f64, KclError> {
|
||||
}
|
||||
|
||||
/// Compute the arccosine of a number (in radians).
|
||||
pub async fn acos(args: Args) -> Result<KclValue, KclError> {
|
||||
pub async fn acos(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let num = args.get_number()?;
|
||||
let result = inner_acos(num)?;
|
||||
|
||||
@ -398,7 +398,7 @@ fn inner_acos(num: f64) -> Result<f64, KclError> {
|
||||
}
|
||||
|
||||
/// Compute the arcsine of a number (in radians).
|
||||
pub async fn asin(args: Args) -> Result<KclValue, KclError> {
|
||||
pub async fn asin(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let num = args.get_number()?;
|
||||
let result = inner_asin(num)?;
|
||||
|
||||
@ -428,7 +428,7 @@ fn inner_asin(num: f64) -> Result<f64, KclError> {
|
||||
}
|
||||
|
||||
/// Compute the arctangent of a number (in radians).
|
||||
pub async fn atan(args: Args) -> Result<KclValue, KclError> {
|
||||
pub async fn atan(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let num = args.get_number()?;
|
||||
let result = inner_atan(num)?;
|
||||
|
||||
@ -462,7 +462,7 @@ fn inner_atan(num: f64) -> Result<f64, KclError> {
|
||||
/// The result might not be correctly rounded owing to implementation
|
||||
/// details; `log2()` can produce more accurate results for base 2,
|
||||
/// and `log10()` can produce more accurate results for base 10.
|
||||
pub async fn log(args: Args) -> Result<KclValue, KclError> {
|
||||
pub async fn log(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let nums = args.get_number_array()?;
|
||||
if nums.len() > 2 {
|
||||
return Err(KclError::Type(KclErrorDetails {
|
||||
@ -507,7 +507,7 @@ fn inner_log(num: f64, base: f64) -> Result<f64, KclError> {
|
||||
}
|
||||
|
||||
/// Compute the base 2 logarithm of the number.
|
||||
pub async fn log2(args: Args) -> Result<KclValue, KclError> {
|
||||
pub async fn log2(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let num = args.get_number()?;
|
||||
let result = inner_log2(num)?;
|
||||
|
||||
@ -535,7 +535,7 @@ fn inner_log2(num: f64) -> Result<f64, KclError> {
|
||||
}
|
||||
|
||||
/// Compute the base 10 logarithm of the number.
|
||||
pub async fn log10(args: Args) -> Result<KclValue, KclError> {
|
||||
pub async fn log10(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let num = args.get_number()?;
|
||||
let result = inner_log10(num)?;
|
||||
|
||||
@ -563,7 +563,7 @@ fn inner_log10(num: f64) -> Result<f64, KclError> {
|
||||
}
|
||||
|
||||
/// Compute the natural logarithm of the number.
|
||||
pub async fn ln(args: Args) -> Result<KclValue, KclError> {
|
||||
pub async fn ln(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let num = args.get_number()?;
|
||||
let result = inner_ln(num)?;
|
||||
|
||||
@ -591,7 +591,7 @@ fn inner_ln(num: f64) -> Result<f64, KclError> {
|
||||
}
|
||||
|
||||
/// Return the value of Euler’s number `e`.
|
||||
pub async fn e(args: Args) -> Result<KclValue, KclError> {
|
||||
pub async fn e(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let result = inner_e()?;
|
||||
|
||||
args.make_user_val_from_f64(result)
|
||||
@ -620,7 +620,7 @@ fn inner_e() -> Result<f64, KclError> {
|
||||
}
|
||||
|
||||
/// Return the value of `tau`. The full circle constant (τ). Equal to 2π.
|
||||
pub async fn tau(args: Args) -> Result<KclValue, KclError> {
|
||||
pub async fn tau(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let result = inner_tau()?;
|
||||
|
||||
args.make_user_val_from_f64(result)
|
||||
@ -649,7 +649,7 @@ fn inner_tau() -> Result<f64, KclError> {
|
||||
}
|
||||
|
||||
/// Converts a number from degrees to radians.
|
||||
pub async fn to_radians(args: Args) -> Result<KclValue, KclError> {
|
||||
pub async fn to_radians(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let num = args.get_number()?;
|
||||
let result = inner_to_radians(num)?;
|
||||
|
||||
@ -679,7 +679,7 @@ fn inner_to_radians(num: f64) -> Result<f64, KclError> {
|
||||
}
|
||||
|
||||
/// Converts a number from radians to degrees.
|
||||
pub async fn to_degrees(args: Args) -> Result<KclValue, KclError> {
|
||||
pub async fn to_degrees(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let num = args.get_number()?;
|
||||
let result = inner_to_degrees(num)?;
|
||||
|
||||
|
@ -38,11 +38,14 @@ use crate::{
|
||||
ast::types::FunctionExpression,
|
||||
docs::StdLibFn,
|
||||
errors::KclError,
|
||||
executor::{KclValue, ProgramMemory, SketchGroup, SketchSurface},
|
||||
executor::{ExecState, KclValue, ProgramMemory, SketchGroup, SketchSurface},
|
||||
std::kcl_stdlib::KclStdLibFn,
|
||||
};
|
||||
|
||||
pub type StdFn = fn(Args) -> std::pin::Pin<Box<dyn std::future::Future<Output = Result<KclValue, KclError>> + Send>>;
|
||||
pub type StdFn = fn(
|
||||
&mut ExecState,
|
||||
Args,
|
||||
) -> std::pin::Pin<Box<dyn std::future::Future<Output = Result<KclValue, KclError>> + Send + '_>>;
|
||||
|
||||
pub type FnMap = HashMap<String, StdFn>;
|
||||
|
||||
@ -228,7 +231,7 @@ pub enum FunctionKind {
|
||||
}
|
||||
|
||||
/// Compute the length of the given leg.
|
||||
pub async fn leg_length(args: Args) -> Result<KclValue, KclError> {
|
||||
pub async fn leg_length(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let (hypotenuse, leg) = args.get_hypotenuse_leg()?;
|
||||
let result = inner_leg_length(hypotenuse, leg);
|
||||
args.make_user_val_from_f64(result)
|
||||
@ -248,7 +251,7 @@ fn inner_leg_length(hypotenuse: f64, leg: f64) -> f64 {
|
||||
}
|
||||
|
||||
/// Compute the angle of the given leg for x.
|
||||
pub async fn leg_angle_x(args: Args) -> Result<KclValue, KclError> {
|
||||
pub async fn leg_angle_x(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let (hypotenuse, leg) = args.get_hypotenuse_leg()?;
|
||||
let result = inner_leg_angle_x(hypotenuse, leg);
|
||||
args.make_user_val_from_f64(result)
|
||||
@ -268,7 +271,7 @@ fn inner_leg_angle_x(hypotenuse: f64, leg: f64) -> f64 {
|
||||
}
|
||||
|
||||
/// Compute the angle of the given leg for y.
|
||||
pub async fn leg_angle_y(args: Args) -> Result<KclValue, KclError> {
|
||||
pub async fn leg_angle_y(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let (hypotenuse, leg) = args.get_hypotenuse_leg()?;
|
||||
let result = inner_leg_angle_y(hypotenuse, leg);
|
||||
args.make_user_val_from_f64(result)
|
||||
@ -302,8 +305,9 @@ pub enum Primitive {
|
||||
Uuid,
|
||||
}
|
||||
|
||||
/// A closure used as an argument to a stdlib function.
|
||||
pub struct FnAsArg<'a> {
|
||||
pub func: &'a crate::executor::MemoryFunction,
|
||||
pub func: Option<&'a crate::executor::MemoryFunction>,
|
||||
pub expr: Box<FunctionExpression>,
|
||||
pub memory: Box<ProgramMemory>,
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ use serde::{Deserialize, Serialize};
|
||||
use crate::{
|
||||
errors::{KclError, KclErrorDetails},
|
||||
executor::{
|
||||
ExtrudeGroup, ExtrudeGroupSet, Geometries, Geometry, KclValue, Point3d, SketchGroup, SketchGroupSet,
|
||||
ExecState, ExtrudeGroup, ExtrudeGroupSet, Geometries, Geometry, KclValue, Point3d, SketchGroup, SketchGroupSet,
|
||||
SourceRange, UserVal,
|
||||
},
|
||||
function_param::FunctionParam,
|
||||
@ -77,7 +77,7 @@ impl LinearPattern {
|
||||
/// A linear pattern
|
||||
/// Each element in the pattern repeats a particular piece of geometry.
|
||||
/// The repetitions can be transformed by the `transform` parameter.
|
||||
pub async fn pattern_transform(args: Args) -> Result<KclValue, KclError> {
|
||||
pub async fn pattern_transform(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let (num_repetitions, transform, extr) = args.get_pattern_transform_args()?;
|
||||
|
||||
let extrude_groups = inner_pattern_transform(
|
||||
@ -88,9 +88,9 @@ pub async fn pattern_transform(args: Args) -> Result<KclValue, KclError> {
|
||||
meta: vec![args.source_range.into()],
|
||||
ctx: args.ctx.clone(),
|
||||
memory: *transform.memory,
|
||||
dynamic_state: args.dynamic_state.clone(),
|
||||
},
|
||||
extr,
|
||||
exec_state,
|
||||
&args,
|
||||
)
|
||||
.await?;
|
||||
@ -131,18 +131,19 @@ async fn inner_pattern_transform<'a>(
|
||||
num_repetitions: u32,
|
||||
transform_function: FunctionParam<'a>,
|
||||
extrude_group_set: ExtrudeGroupSet,
|
||||
exec_state: &mut ExecState,
|
||||
args: &'a Args,
|
||||
) -> Result<Vec<Box<ExtrudeGroup>>, KclError> {
|
||||
// Build the vec of transforms, one for each repetition.
|
||||
let mut transform = Vec::with_capacity(usize::try_from(num_repetitions).unwrap());
|
||||
for i in 0..num_repetitions {
|
||||
let t = make_transform(i, &transform_function, args.source_range).await?;
|
||||
let t = make_transform(i, &transform_function, args.source_range, exec_state).await?;
|
||||
transform.push(t);
|
||||
}
|
||||
// Flush the batch for our fillets/chamfers if there are any.
|
||||
// If we do not flush these, then you won't be able to pattern something with fillets.
|
||||
// Flush just the fillets/chamfers that apply to these extrude groups.
|
||||
args.flush_batch_for_extrude_group_set(extrude_group_set.clone().into())
|
||||
args.flush_batch_for_extrude_group_set(exec_state, extrude_group_set.clone().into())
|
||||
.await?;
|
||||
|
||||
let starting_extrude_groups: Vec<Box<ExtrudeGroup>> = extrude_group_set.into();
|
||||
@ -201,6 +202,7 @@ async fn make_transform<'a>(
|
||||
i: u32,
|
||||
transform_function: &FunctionParam<'a>,
|
||||
source_range: SourceRange,
|
||||
exec_state: &mut ExecState,
|
||||
) -> Result<kittycad::types::Transform, KclError> {
|
||||
// Call the transform fn for this repetition.
|
||||
let repetition_num = KclValue::UserVal(UserVal {
|
||||
@ -208,7 +210,7 @@ async fn make_transform<'a>(
|
||||
meta: vec![source_range.into()],
|
||||
});
|
||||
let transform_fn_args = vec![repetition_num];
|
||||
let transform_fn_return = transform_function.call(transform_fn_args).await?;
|
||||
let transform_fn_return = transform_function.call(exec_state, transform_fn_args).await?;
|
||||
|
||||
// Unpack the returned transform object.
|
||||
let source_ranges = vec![source_range];
|
||||
@ -299,7 +301,7 @@ mod tests {
|
||||
}
|
||||
|
||||
/// A linear pattern on a 2D sketch.
|
||||
pub async fn pattern_linear_2d(args: Args) -> Result<KclValue, KclError> {
|
||||
pub async fn pattern_linear_2d(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let (data, sketch_group_set): (LinearPattern2dData, SketchGroupSet) = args.get_data_and_sketch_group_set()?;
|
||||
|
||||
if data.axis == [0.0, 0.0] {
|
||||
@ -366,7 +368,7 @@ async fn inner_pattern_linear_2d(
|
||||
}
|
||||
|
||||
/// A linear pattern on a 3D model.
|
||||
pub async fn pattern_linear_3d(args: Args) -> Result<KclValue, KclError> {
|
||||
pub async fn pattern_linear_3d(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let (data, extrude_group_set): (LinearPattern3dData, ExtrudeGroupSet) = args.get_data_and_extrude_group_set()?;
|
||||
|
||||
if data.axis == [0.0, 0.0, 0.0] {
|
||||
@ -378,7 +380,7 @@ pub async fn pattern_linear_3d(args: Args) -> Result<KclValue, KclError> {
|
||||
}));
|
||||
}
|
||||
|
||||
let extrude_groups = inner_pattern_linear_3d(data, extrude_group_set, args).await?;
|
||||
let extrude_groups = inner_pattern_linear_3d(data, extrude_group_set, exec_state, args).await?;
|
||||
Ok(extrude_groups.into())
|
||||
}
|
||||
|
||||
@ -406,12 +408,13 @@ pub async fn pattern_linear_3d(args: Args) -> Result<KclValue, KclError> {
|
||||
async fn inner_pattern_linear_3d(
|
||||
data: LinearPattern3dData,
|
||||
extrude_group_set: ExtrudeGroupSet,
|
||||
exec_state: &mut ExecState,
|
||||
args: Args,
|
||||
) -> Result<Vec<Box<ExtrudeGroup>>, KclError> {
|
||||
// Flush the batch for our fillets/chamfers if there are any.
|
||||
// If we do not flush these, then you won't be able to pattern something with fillets.
|
||||
// Flush just the fillets/chamfers that apply to these extrude groups.
|
||||
args.flush_batch_for_extrude_group_set(extrude_group_set.clone().into())
|
||||
args.flush_batch_for_extrude_group_set(exec_state, extrude_group_set.clone().into())
|
||||
.await?;
|
||||
|
||||
let starting_extrude_groups: Vec<Box<ExtrudeGroup>> = extrude_group_set.into();
|
||||
@ -574,7 +577,7 @@ impl CircularPattern {
|
||||
}
|
||||
|
||||
/// A circular pattern on a 2D sketch.
|
||||
pub async fn pattern_circular_2d(args: Args) -> Result<KclValue, KclError> {
|
||||
pub async fn pattern_circular_2d(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let (data, sketch_group_set): (CircularPattern2dData, SketchGroupSet) = args.get_data_and_sketch_group_set()?;
|
||||
|
||||
let sketch_groups = inner_pattern_circular_2d(data, sketch_group_set, args).await?;
|
||||
@ -639,10 +642,10 @@ async fn inner_pattern_circular_2d(
|
||||
}
|
||||
|
||||
/// A circular pattern on a 3D model.
|
||||
pub async fn pattern_circular_3d(args: Args) -> Result<KclValue, KclError> {
|
||||
pub async fn pattern_circular_3d(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let (data, extrude_group_set): (CircularPattern3dData, ExtrudeGroupSet) = args.get_data_and_extrude_group_set()?;
|
||||
|
||||
let extrude_groups = inner_pattern_circular_3d(data, extrude_group_set, args).await?;
|
||||
let extrude_groups = inner_pattern_circular_3d(data, extrude_group_set, exec_state, args).await?;
|
||||
Ok(extrude_groups.into())
|
||||
}
|
||||
|
||||
@ -670,12 +673,13 @@ pub async fn pattern_circular_3d(args: Args) -> Result<KclValue, KclError> {
|
||||
async fn inner_pattern_circular_3d(
|
||||
data: CircularPattern3dData,
|
||||
extrude_group_set: ExtrudeGroupSet,
|
||||
exec_state: &mut ExecState,
|
||||
args: Args,
|
||||
) -> Result<Vec<Box<ExtrudeGroup>>, KclError> {
|
||||
// Flush the batch for our fillets/chamfers if there are any.
|
||||
// If we do not flush these, then you won't be able to pattern something with fillets.
|
||||
// Flush just the fillets/chamfers that apply to these extrude groups.
|
||||
args.flush_batch_for_extrude_group_set(extrude_group_set.clone().into())
|
||||
args.flush_batch_for_extrude_group_set(exec_state, extrude_group_set.clone().into())
|
||||
.await?;
|
||||
|
||||
let starting_extrude_groups: Vec<Box<ExtrudeGroup>> = extrude_group_set.into();
|
||||
|
@ -6,7 +6,7 @@ use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
errors::KclError,
|
||||
executor::{KclValue, Metadata, Plane, UserVal},
|
||||
executor::{ExecState, KclValue, Metadata, Plane, UserVal},
|
||||
std::{sketch::PlaneData, Args},
|
||||
};
|
||||
|
||||
@ -48,7 +48,7 @@ impl From<StandardPlane> for PlaneData {
|
||||
}
|
||||
|
||||
/// Offset a plane by a distance along its normal.
|
||||
pub async fn offset_plane(args: Args) -> Result<KclValue, KclError> {
|
||||
pub async fn offset_plane(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let (std_plane, offset): (StandardPlane, f64) = args.get_data_and_float()?;
|
||||
|
||||
let plane = inner_offset_plane(std_plane, offset).await?;
|
||||
|
@ -5,7 +5,11 @@ use derive_docs::stdlib;
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{errors::KclError, executor::KclValue, std::Args};
|
||||
use crate::{
|
||||
errors::KclError,
|
||||
executor::{ExecState, KclValue},
|
||||
std::Args,
|
||||
};
|
||||
|
||||
/// Data for polar coordinates.
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
|
||||
@ -19,7 +23,7 @@ pub struct PolarCoordsData {
|
||||
}
|
||||
|
||||
/// Convert from polar/sphere coordinates to cartesian coordinates.
|
||||
pub async fn polar(args: Args) -> Result<KclValue, KclError> {
|
||||
pub async fn polar(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let data: PolarCoordsData = args.get_data()?;
|
||||
let result = inner_polar(&data)?;
|
||||
|
||||
|
@ -8,7 +8,7 @@ use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
errors::{KclError, KclErrorDetails},
|
||||
executor::{ExtrudeGroup, KclValue, SketchGroup},
|
||||
executor::{ExecState, ExtrudeGroup, KclValue, SketchGroup},
|
||||
std::{
|
||||
extrude::do_post_extrude,
|
||||
fillet::{default_tolerance, EdgeReference},
|
||||
@ -101,10 +101,10 @@ impl RevolveAxisAndOrigin {
|
||||
}
|
||||
|
||||
/// Revolve a sketch around an axis.
|
||||
pub async fn revolve(args: Args) -> Result<KclValue, KclError> {
|
||||
pub async fn revolve(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let (data, sketch_group): (RevolveData, SketchGroup) = args.get_data_and_sketch_group()?;
|
||||
|
||||
let extrude_group = inner_revolve(data, sketch_group, args).await?;
|
||||
let extrude_group = inner_revolve(data, sketch_group, exec_state, args).await?;
|
||||
Ok(KclValue::ExtrudeGroup(extrude_group))
|
||||
}
|
||||
|
||||
@ -250,6 +250,7 @@ pub async fn revolve(args: Args) -> Result<KclValue, KclError> {
|
||||
async fn inner_revolve(
|
||||
data: RevolveData,
|
||||
sketch_group: SketchGroup,
|
||||
exec_state: &mut ExecState,
|
||||
args: Args,
|
||||
) -> Result<Box<ExtrudeGroup>, KclError> {
|
||||
if let Some(angle) = data.angle {
|
||||
@ -284,7 +285,7 @@ async fn inner_revolve(
|
||||
RevolveAxis::Edge(edge) => {
|
||||
let edge_id = match edge {
|
||||
EdgeReference::Uuid(uuid) => uuid,
|
||||
EdgeReference::Tag(tag) => args.get_tag_engine_info(&tag)?.id,
|
||||
EdgeReference::Tag(tag) => args.get_tag_engine_info(exec_state, &tag)?.id,
|
||||
};
|
||||
args.batch_modeling_cmd(
|
||||
id,
|
||||
|
@ -6,14 +6,14 @@ use schemars::JsonSchema;
|
||||
|
||||
use crate::{
|
||||
errors::{KclError, KclErrorDetails},
|
||||
executor::{KclValue, SketchGroup, TagIdentifier},
|
||||
executor::{ExecState, KclValue, SketchGroup, TagIdentifier},
|
||||
std::{utils::between, Args},
|
||||
};
|
||||
|
||||
/// Returns the segment end of x.
|
||||
pub async fn segment_end_x(args: Args) -> Result<KclValue, KclError> {
|
||||
pub async fn segment_end_x(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let tag: TagIdentifier = args.get_data()?;
|
||||
let result = inner_segment_end_x(&tag, args.clone())?;
|
||||
let result = inner_segment_end_x(&tag, exec_state, args.clone())?;
|
||||
|
||||
args.make_user_val_from_f64(result)
|
||||
}
|
||||
@ -34,8 +34,8 @@ pub async fn segment_end_x(args: Args) -> Result<KclValue, KclError> {
|
||||
#[stdlib {
|
||||
name = "segEndX",
|
||||
}]
|
||||
fn inner_segment_end_x(tag: &TagIdentifier, args: Args) -> Result<f64, KclError> {
|
||||
let line = args.get_tag_engine_info(tag)?;
|
||||
fn inner_segment_end_x(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<f64, KclError> {
|
||||
let line = args.get_tag_engine_info(exec_state, tag)?;
|
||||
let path = line.path.clone().ok_or_else(|| {
|
||||
KclError::Type(KclErrorDetails {
|
||||
message: format!("Expected a line segment with a path, found `{:?}`", line),
|
||||
@ -47,9 +47,9 @@ fn inner_segment_end_x(tag: &TagIdentifier, args: Args) -> Result<f64, KclError>
|
||||
}
|
||||
|
||||
/// Returns the segment end of y.
|
||||
pub async fn segment_end_y(args: Args) -> Result<KclValue, KclError> {
|
||||
pub async fn segment_end_y(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let tag: TagIdentifier = args.get_data()?;
|
||||
let result = inner_segment_end_y(&tag, args.clone())?;
|
||||
let result = inner_segment_end_y(&tag, exec_state, args.clone())?;
|
||||
|
||||
args.make_user_val_from_f64(result)
|
||||
}
|
||||
@ -71,8 +71,8 @@ pub async fn segment_end_y(args: Args) -> Result<KclValue, KclError> {
|
||||
#[stdlib {
|
||||
name = "segEndY",
|
||||
}]
|
||||
fn inner_segment_end_y(tag: &TagIdentifier, args: Args) -> Result<f64, KclError> {
|
||||
let line = args.get_tag_engine_info(tag)?;
|
||||
fn inner_segment_end_y(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<f64, KclError> {
|
||||
let line = args.get_tag_engine_info(exec_state, tag)?;
|
||||
let path = line.path.clone().ok_or_else(|| {
|
||||
KclError::Type(KclErrorDetails {
|
||||
message: format!("Expected a line segment with a path, found `{:?}`", line),
|
||||
@ -84,7 +84,7 @@ fn inner_segment_end_y(tag: &TagIdentifier, args: Args) -> Result<f64, KclError>
|
||||
}
|
||||
|
||||
/// Returns the last segment of x.
|
||||
pub async fn last_segment_x(args: Args) -> Result<KclValue, KclError> {
|
||||
pub async fn last_segment_x(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let sketch_group = args.get_sketch_group()?;
|
||||
let result = inner_last_segment_x(sketch_group, args.clone())?;
|
||||
|
||||
@ -127,7 +127,7 @@ fn inner_last_segment_x(sketch_group: SketchGroup, args: Args) -> Result<f64, Kc
|
||||
}
|
||||
|
||||
/// Returns the last segment of y.
|
||||
pub async fn last_segment_y(args: Args) -> Result<KclValue, KclError> {
|
||||
pub async fn last_segment_y(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let sketch_group = args.get_sketch_group()?;
|
||||
let result = inner_last_segment_y(sketch_group, args.clone())?;
|
||||
|
||||
@ -170,9 +170,9 @@ fn inner_last_segment_y(sketch_group: SketchGroup, args: Args) -> Result<f64, Kc
|
||||
}
|
||||
|
||||
/// Returns the length of the segment.
|
||||
pub async fn segment_length(args: Args) -> Result<KclValue, KclError> {
|
||||
pub async fn segment_length(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let tag: TagIdentifier = args.get_data()?;
|
||||
let result = inner_segment_length(&tag, args.clone())?;
|
||||
let result = inner_segment_length(&tag, exec_state, args.clone())?;
|
||||
args.make_user_val_from_f64(result)
|
||||
}
|
||||
|
||||
@ -200,8 +200,8 @@ pub async fn segment_length(args: Args) -> Result<KclValue, KclError> {
|
||||
#[stdlib {
|
||||
name = "segLen",
|
||||
}]
|
||||
fn inner_segment_length(tag: &TagIdentifier, args: Args) -> Result<f64, KclError> {
|
||||
let line = args.get_tag_engine_info(tag)?;
|
||||
fn inner_segment_length(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<f64, KclError> {
|
||||
let line = args.get_tag_engine_info(exec_state, tag)?;
|
||||
let path = line.path.clone().ok_or_else(|| {
|
||||
KclError::Type(KclErrorDetails {
|
||||
message: format!("Expected a line segment with a path, found `{:?}`", line),
|
||||
@ -215,10 +215,10 @@ fn inner_segment_length(tag: &TagIdentifier, args: Args) -> Result<f64, KclError
|
||||
}
|
||||
|
||||
/// Returns the angle of the segment.
|
||||
pub async fn segment_angle(args: Args) -> Result<KclValue, KclError> {
|
||||
pub async fn segment_angle(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let tag: TagIdentifier = args.get_data()?;
|
||||
|
||||
let result = inner_segment_angle(&tag, args.clone())?;
|
||||
let result = inner_segment_angle(&tag, exec_state, args.clone())?;
|
||||
args.make_user_val_from_f64(result)
|
||||
}
|
||||
|
||||
@ -240,8 +240,8 @@ pub async fn segment_angle(args: Args) -> Result<KclValue, KclError> {
|
||||
#[stdlib {
|
||||
name = "segAng",
|
||||
}]
|
||||
fn inner_segment_angle(tag: &TagIdentifier, args: Args) -> Result<f64, KclError> {
|
||||
let line = args.get_tag_engine_info(tag)?;
|
||||
fn inner_segment_angle(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<f64, KclError> {
|
||||
let line = args.get_tag_engine_info(exec_state, tag)?;
|
||||
let path = line.path.clone().ok_or_else(|| {
|
||||
KclError::Type(KclErrorDetails {
|
||||
message: format!("Expected a line segment with a path, found `{:?}`", line),
|
||||
@ -255,9 +255,9 @@ fn inner_segment_angle(tag: &TagIdentifier, args: Args) -> Result<f64, KclError>
|
||||
}
|
||||
|
||||
/// Returns the angle to match the given length for x.
|
||||
pub async fn angle_to_match_length_x(args: Args) -> Result<KclValue, KclError> {
|
||||
pub async fn angle_to_match_length_x(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let (tag, to, sketch_group) = args.get_tag_to_number_sketch_group()?;
|
||||
let result = inner_angle_to_match_length_x(&tag, to, sketch_group, args.clone())?;
|
||||
let result = inner_angle_to_match_length_x(&tag, to, sketch_group, exec_state, args.clone())?;
|
||||
args.make_user_val_from_f64(result)
|
||||
}
|
||||
|
||||
@ -282,9 +282,10 @@ fn inner_angle_to_match_length_x(
|
||||
tag: &TagIdentifier,
|
||||
to: f64,
|
||||
sketch_group: SketchGroup,
|
||||
exec_state: &mut ExecState,
|
||||
args: Args,
|
||||
) -> Result<f64, KclError> {
|
||||
let line = args.get_tag_engine_info(tag)?;
|
||||
let line = args.get_tag_engine_info(exec_state, tag)?;
|
||||
let path = line.path.clone().ok_or_else(|| {
|
||||
KclError::Type(KclErrorDetails {
|
||||
message: format!("Expected a line segment with a path, found `{:?}`", line),
|
||||
@ -320,9 +321,9 @@ fn inner_angle_to_match_length_x(
|
||||
}
|
||||
|
||||
/// Returns the angle to match the given length for y.
|
||||
pub async fn angle_to_match_length_y(args: Args) -> Result<KclValue, KclError> {
|
||||
pub async fn angle_to_match_length_y(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let (tag, to, sketch_group) = args.get_tag_to_number_sketch_group()?;
|
||||
let result = inner_angle_to_match_length_y(&tag, to, sketch_group, args.clone())?;
|
||||
let result = inner_angle_to_match_length_y(&tag, to, sketch_group, exec_state, args.clone())?;
|
||||
args.make_user_val_from_f64(result)
|
||||
}
|
||||
|
||||
@ -348,9 +349,10 @@ fn inner_angle_to_match_length_y(
|
||||
tag: &TagIdentifier,
|
||||
to: f64,
|
||||
sketch_group: SketchGroup,
|
||||
exec_state: &mut ExecState,
|
||||
args: Args,
|
||||
) -> Result<f64, KclError> {
|
||||
let line = args.get_tag_engine_info(tag)?;
|
||||
let line = args.get_tag_engine_info(exec_state, tag)?;
|
||||
let path = line.path.clone().ok_or_else(|| {
|
||||
KclError::Type(KclErrorDetails {
|
||||
message: format!("Expected a line segment with a path, found `{:?}`", line),
|
||||
|
@ -8,7 +8,7 @@ use serde::{Deserialize, Serialize};
|
||||
use crate::{
|
||||
ast::types::TagDeclarator,
|
||||
errors::KclError,
|
||||
executor::KclValue,
|
||||
executor::{ExecState, KclValue},
|
||||
std::{Args, SketchGroup, SketchSurface},
|
||||
};
|
||||
|
||||
@ -22,11 +22,11 @@ pub enum SketchSurfaceOrGroup {
|
||||
}
|
||||
|
||||
/// Sketch a circle.
|
||||
pub async fn circle(args: Args) -> Result<KclValue, KclError> {
|
||||
pub async fn circle(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let (center, radius, sketch_surface_or_group, tag): ([f64; 2], f64, SketchSurfaceOrGroup, Option<TagDeclarator>) =
|
||||
args.get_circle_args()?;
|
||||
|
||||
let sketch_group = inner_circle(center, radius, sketch_surface_or_group, tag, args).await?;
|
||||
let sketch_group = inner_circle(center, radius, sketch_surface_or_group, tag, exec_state, args).await?;
|
||||
Ok(KclValue::new_user_val(sketch_group.meta.clone(), sketch_group))
|
||||
}
|
||||
|
||||
@ -59,14 +59,20 @@ async fn inner_circle(
|
||||
radius: f64,
|
||||
sketch_surface_or_group: SketchSurfaceOrGroup,
|
||||
tag: Option<TagDeclarator>,
|
||||
exec_state: &mut ExecState,
|
||||
args: Args,
|
||||
) -> Result<SketchGroup, KclError> {
|
||||
let sketch_surface = match sketch_surface_or_group {
|
||||
SketchSurfaceOrGroup::SketchSurface(surface) => surface,
|
||||
SketchSurfaceOrGroup::SketchGroup(group) => group.on,
|
||||
};
|
||||
let mut sketch_group =
|
||||
crate::std::sketch::inner_start_profile_at([center[0] + radius, center[1]], sketch_surface, None, args.clone())
|
||||
let mut sketch_group = crate::std::sketch::inner_start_profile_at(
|
||||
[center[0] + radius, center[1]],
|
||||
sketch_surface,
|
||||
None,
|
||||
exec_state,
|
||||
args.clone(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
// Call arc.
|
||||
|
@ -8,7 +8,7 @@ use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
errors::{KclError, KclErrorDetails},
|
||||
executor::{ExtrudeGroup, KclValue},
|
||||
executor::{ExecState, ExtrudeGroup, KclValue},
|
||||
std::{sketch::FaceTag, Args},
|
||||
};
|
||||
|
||||
@ -24,10 +24,10 @@ pub struct ShellData {
|
||||
}
|
||||
|
||||
/// Create a shell.
|
||||
pub async fn shell(args: Args) -> Result<KclValue, KclError> {
|
||||
pub async fn shell(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let (data, extrude_group): (ShellData, Box<ExtrudeGroup>) = args.get_data_and_extrude_group()?;
|
||||
|
||||
let extrude_group = inner_shell(data, extrude_group, args).await?;
|
||||
let extrude_group = inner_shell(data, extrude_group, exec_state, args).await?;
|
||||
Ok(KclValue::ExtrudeGroup(extrude_group))
|
||||
}
|
||||
|
||||
@ -154,6 +154,7 @@ pub async fn shell(args: Args) -> Result<KclValue, KclError> {
|
||||
async fn inner_shell(
|
||||
data: ShellData,
|
||||
extrude_group: Box<ExtrudeGroup>,
|
||||
exec_state: &mut ExecState,
|
||||
args: Args,
|
||||
) -> Result<Box<ExtrudeGroup>, KclError> {
|
||||
if data.faces.is_empty() {
|
||||
@ -165,7 +166,7 @@ async fn inner_shell(
|
||||
|
||||
let mut face_ids = Vec::new();
|
||||
for tag in data.faces {
|
||||
let extrude_plane_id = tag.get_face_id(&extrude_group, &args, false).await?;
|
||||
let extrude_plane_id = tag.get_face_id(&extrude_group, exec_state, &args, false).await?;
|
||||
|
||||
face_ids.push(extrude_plane_id);
|
||||
}
|
||||
@ -179,7 +180,7 @@ async fn inner_shell(
|
||||
|
||||
// Flush the batch for our fillets/chamfers if there are any.
|
||||
// If we do not do these for sketch on face, things will fail with face does not exist.
|
||||
args.flush_batch_for_extrude_group_set(extrude_group.clone().into())
|
||||
args.flush_batch_for_extrude_group_set(exec_state, extrude_group.clone().into())
|
||||
.await?;
|
||||
|
||||
args.batch_modeling_cmd(
|
||||
@ -197,10 +198,10 @@ async fn inner_shell(
|
||||
}
|
||||
|
||||
/// Make the inside of a 3D object hollow.
|
||||
pub async fn hollow(args: Args) -> Result<KclValue, KclError> {
|
||||
pub async fn hollow(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let (thickness, extrude_group): (f64, Box<ExtrudeGroup>) = args.get_data_and_extrude_group()?;
|
||||
|
||||
let extrude_group = inner_hollow(thickness, extrude_group, args).await?;
|
||||
let extrude_group = inner_hollow(thickness, extrude_group, exec_state, args).await?;
|
||||
Ok(KclValue::ExtrudeGroup(extrude_group))
|
||||
}
|
||||
|
||||
@ -236,11 +237,12 @@ pub async fn hollow(args: Args) -> Result<KclValue, KclError> {
|
||||
async fn inner_hollow(
|
||||
thickness: f64,
|
||||
extrude_group: Box<ExtrudeGroup>,
|
||||
exec_state: &mut ExecState,
|
||||
args: Args,
|
||||
) -> Result<Box<ExtrudeGroup>, KclError> {
|
||||
// Flush the batch for our fillets/chamfers if there are any.
|
||||
// If we do not do these for sketch on face, things will fail with face does not exist.
|
||||
args.flush_batch_for_extrude_group_set(extrude_group.clone().into())
|
||||
args.flush_batch_for_extrude_group_set(exec_state, extrude_group.clone().into())
|
||||
.await?;
|
||||
|
||||
args.batch_modeling_cmd(
|
||||
|
@ -13,8 +13,8 @@ use crate::{
|
||||
ast::types::TagDeclarator,
|
||||
errors::{KclError, KclErrorDetails},
|
||||
executor::{
|
||||
BasePath, ExtrudeGroup, Face, GeoMeta, KclValue, Path, Plane, PlaneType, Point2d, Point3d, SketchGroup,
|
||||
SketchGroupSet, SketchSurface, TagEngineInfo, TagIdentifier, UserVal,
|
||||
BasePath, ExecState, ExtrudeGroup, Face, GeoMeta, KclValue, Path, Plane, PlaneType, Point2d, Point3d,
|
||||
SketchGroup, SketchGroupSet, SketchSurface, TagEngineInfo, TagIdentifier, UserVal,
|
||||
},
|
||||
std::{
|
||||
utils::{
|
||||
@ -50,11 +50,12 @@ impl FaceTag {
|
||||
pub async fn get_face_id(
|
||||
&self,
|
||||
extrude_group: &ExtrudeGroup,
|
||||
exec_state: &mut ExecState,
|
||||
args: &Args,
|
||||
must_be_planar: bool,
|
||||
) -> Result<uuid::Uuid, KclError> {
|
||||
match self {
|
||||
FaceTag::Tag(ref t) => args.get_adjacent_face_to_tag(t, must_be_planar).await,
|
||||
FaceTag::Tag(ref t) => args.get_adjacent_face_to_tag(exec_state, t, must_be_planar).await,
|
||||
FaceTag::StartOrEnd(StartOrEnd::Start) => extrude_group.start_cap_id.ok_or_else(|| {
|
||||
KclError::Type(KclErrorDetails {
|
||||
message: "Expected a start face".to_string(),
|
||||
@ -89,7 +90,7 @@ pub enum StartOrEnd {
|
||||
}
|
||||
|
||||
/// Draw a line to a point.
|
||||
pub async fn line_to(args: Args) -> Result<KclValue, KclError> {
|
||||
pub async fn line_to(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let (to, sketch_group, tag): ([f64; 2], SketchGroup, Option<TagDeclarator>) =
|
||||
args.get_data_and_sketch_group_and_tag()?;
|
||||
|
||||
@ -160,7 +161,7 @@ async fn inner_line_to(
|
||||
}
|
||||
|
||||
/// Draw a line to a point on the x-axis.
|
||||
pub async fn x_line_to(args: Args) -> Result<KclValue, KclError> {
|
||||
pub async fn x_line_to(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let (to, sketch_group, tag): (f64, SketchGroup, Option<TagDeclarator>) =
|
||||
args.get_data_and_sketch_group_and_tag()?;
|
||||
|
||||
@ -208,7 +209,7 @@ async fn inner_x_line_to(
|
||||
}
|
||||
|
||||
/// Draw a line to a point on the y-axis.
|
||||
pub async fn y_line_to(args: Args) -> Result<KclValue, KclError> {
|
||||
pub async fn y_line_to(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let (to, sketch_group, tag): (f64, SketchGroup, Option<TagDeclarator>) =
|
||||
args.get_data_and_sketch_group_and_tag()?;
|
||||
|
||||
@ -248,7 +249,7 @@ async fn inner_y_line_to(
|
||||
}
|
||||
|
||||
/// Draw a line.
|
||||
pub async fn line(args: Args) -> Result<KclValue, KclError> {
|
||||
pub async fn line(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let (delta, sketch_group, tag): ([f64; 2], SketchGroup, Option<TagDeclarator>) =
|
||||
args.get_data_and_sketch_group_and_tag()?;
|
||||
|
||||
@ -333,7 +334,7 @@ async fn inner_line(
|
||||
}
|
||||
|
||||
/// Draw a line on the x-axis.
|
||||
pub async fn x_line(args: Args) -> Result<KclValue, KclError> {
|
||||
pub async fn x_line(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let (length, sketch_group, tag): (f64, SketchGroup, Option<TagDeclarator>) =
|
||||
args.get_data_and_sketch_group_and_tag()?;
|
||||
|
||||
@ -376,7 +377,7 @@ async fn inner_x_line(
|
||||
}
|
||||
|
||||
/// Draw a line on the y-axis.
|
||||
pub async fn y_line(args: Args) -> Result<KclValue, KclError> {
|
||||
pub async fn y_line(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let (length, sketch_group, tag): (f64, SketchGroup, Option<TagDeclarator>) =
|
||||
args.get_data_and_sketch_group_and_tag()?;
|
||||
|
||||
@ -430,7 +431,7 @@ pub enum AngledLineData {
|
||||
}
|
||||
|
||||
/// Draw an angled line.
|
||||
pub async fn angled_line(args: Args) -> Result<KclValue, KclError> {
|
||||
pub async fn angled_line(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let (data, sketch_group, tag): (AngledLineData, SketchGroup, Option<TagDeclarator>) =
|
||||
args.get_data_and_sketch_group_and_tag()?;
|
||||
|
||||
@ -519,7 +520,7 @@ async fn inner_angled_line(
|
||||
}
|
||||
|
||||
/// Draw an angled line of a given x length.
|
||||
pub async fn angled_line_of_x_length(args: Args) -> Result<KclValue, KclError> {
|
||||
pub async fn angled_line_of_x_length(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let (data, sketch_group, tag): (AngledLineData, SketchGroup, Option<TagDeclarator>) =
|
||||
args.get_data_and_sketch_group_and_tag()?;
|
||||
|
||||
@ -587,7 +588,7 @@ pub struct AngledLineToData {
|
||||
}
|
||||
|
||||
/// Draw an angled line to a given x coordinate.
|
||||
pub async fn angled_line_to_x(args: Args) -> Result<KclValue, KclError> {
|
||||
pub async fn angled_line_to_x(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let (data, sketch_group, tag): (AngledLineToData, SketchGroup, Option<TagDeclarator>) =
|
||||
args.get_data_and_sketch_group_and_tag()?;
|
||||
|
||||
@ -644,7 +645,7 @@ async fn inner_angled_line_to_x(
|
||||
}
|
||||
|
||||
/// Draw an angled line of a given y length.
|
||||
pub async fn angled_line_of_y_length(args: Args) -> Result<KclValue, KclError> {
|
||||
pub async fn angled_line_of_y_length(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let (data, sketch_group, tag): (AngledLineData, SketchGroup, Option<TagDeclarator>) =
|
||||
args.get_data_and_sketch_group_and_tag()?;
|
||||
|
||||
@ -704,7 +705,7 @@ async fn inner_angled_line_of_y_length(
|
||||
}
|
||||
|
||||
/// Draw an angled line to a given y coordinate.
|
||||
pub async fn angled_line_to_y(args: Args) -> Result<KclValue, KclError> {
|
||||
pub async fn angled_line_to_y(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let (data, sketch_group, tag): (AngledLineToData, SketchGroup, Option<TagDeclarator>) =
|
||||
args.get_data_and_sketch_group_and_tag()?;
|
||||
|
||||
@ -775,10 +776,10 @@ pub struct AngledLineThatIntersectsData {
|
||||
}
|
||||
|
||||
/// Draw an angled line that intersects with a given line.
|
||||
pub async fn angled_line_that_intersects(args: Args) -> Result<KclValue, KclError> {
|
||||
pub async fn angled_line_that_intersects(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let (data, sketch_group, tag): (AngledLineThatIntersectsData, SketchGroup, Option<TagDeclarator>) =
|
||||
args.get_data_and_sketch_group_and_tag()?;
|
||||
let new_sketch_group = inner_angled_line_that_intersects(data, sketch_group, tag, args).await?;
|
||||
let new_sketch_group = inner_angled_line_that_intersects(data, sketch_group, tag, exec_state, args).await?;
|
||||
Ok(KclValue::new_user_val(new_sketch_group.meta.clone(), new_sketch_group))
|
||||
}
|
||||
|
||||
@ -808,9 +809,10 @@ async fn inner_angled_line_that_intersects(
|
||||
data: AngledLineThatIntersectsData,
|
||||
sketch_group: SketchGroup,
|
||||
tag: Option<TagDeclarator>,
|
||||
exec_state: &mut ExecState,
|
||||
args: Args,
|
||||
) -> Result<SketchGroup, KclError> {
|
||||
let intersect_path = args.get_tag_engine_info(&data.intersect_tag)?;
|
||||
let intersect_path = args.get_tag_engine_info(exec_state, &data.intersect_tag)?;
|
||||
let path = intersect_path.path.clone().ok_or_else(|| {
|
||||
KclError::Type(KclErrorDetails {
|
||||
message: format!("Expected an intersect path with a path, found `{:?}`", intersect_path),
|
||||
@ -831,10 +833,10 @@ async fn inner_angled_line_that_intersects(
|
||||
}
|
||||
|
||||
/// Start a sketch at a given point.
|
||||
pub async fn start_sketch_at(args: Args) -> Result<KclValue, KclError> {
|
||||
pub async fn start_sketch_at(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let data: [f64; 2] = args.get_data()?;
|
||||
|
||||
let sketch_group = inner_start_sketch_at(data, args).await?;
|
||||
let sketch_group = inner_start_sketch_at(data, exec_state, args).await?;
|
||||
Ok(KclValue::new_user_val(sketch_group.meta.clone(), sketch_group))
|
||||
}
|
||||
|
||||
@ -872,11 +874,15 @@ pub async fn start_sketch_at(args: Args) -> Result<KclValue, KclError> {
|
||||
#[stdlib {
|
||||
name = "startSketchAt",
|
||||
}]
|
||||
async fn inner_start_sketch_at(data: [f64; 2], args: Args) -> Result<SketchGroup, KclError> {
|
||||
async fn inner_start_sketch_at(
|
||||
data: [f64; 2],
|
||||
exec_state: &mut ExecState,
|
||||
args: Args,
|
||||
) -> Result<SketchGroup, KclError> {
|
||||
// Let's assume it's the XY plane for now, this is just for backwards compatibility.
|
||||
let xy_plane = PlaneData::XY;
|
||||
let sketch_surface = inner_start_sketch_on(SketchData::Plane(xy_plane), None, args.clone()).await?;
|
||||
let sketch_group = inner_start_profile_at(data, sketch_surface, None, args).await?;
|
||||
let sketch_surface = inner_start_sketch_on(SketchData::Plane(xy_plane), None, exec_state, &args).await?;
|
||||
let sketch_group = inner_start_profile_at(data, sketch_surface, None, exec_state, args).await?;
|
||||
Ok(sketch_group)
|
||||
}
|
||||
|
||||
@ -1006,10 +1012,10 @@ impl From<PlaneData> for Plane {
|
||||
}
|
||||
|
||||
/// Start a sketch on a specific plane or face.
|
||||
pub async fn start_sketch_on(args: Args) -> Result<KclValue, KclError> {
|
||||
pub async fn start_sketch_on(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let (data, tag): (SketchData, Option<FaceTag>) = args.get_data_and_optional_tag()?;
|
||||
|
||||
match inner_start_sketch_on(data, tag, args).await? {
|
||||
match inner_start_sketch_on(data, tag, exec_state, &args).await? {
|
||||
SketchSurface::Plane(plane) => Ok(KclValue::Plane(plane)),
|
||||
SketchSurface::Face(face) => Ok(KclValue::Face(face)),
|
||||
}
|
||||
@ -1119,7 +1125,12 @@ pub async fn start_sketch_on(args: Args) -> Result<KclValue, KclError> {
|
||||
#[stdlib {
|
||||
name = "startSketchOn",
|
||||
}]
|
||||
async fn inner_start_sketch_on(data: SketchData, tag: Option<FaceTag>, args: Args) -> Result<SketchSurface, KclError> {
|
||||
async fn inner_start_sketch_on(
|
||||
data: SketchData,
|
||||
tag: Option<FaceTag>,
|
||||
exec_state: &mut ExecState,
|
||||
args: &Args,
|
||||
) -> Result<SketchSurface, KclError> {
|
||||
match data {
|
||||
SketchData::Plane(plane_data) => {
|
||||
let plane = start_sketch_on_plane(plane_data, args).await?;
|
||||
@ -1132,7 +1143,7 @@ async fn inner_start_sketch_on(data: SketchData, tag: Option<FaceTag>, args: Arg
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
};
|
||||
let face = start_sketch_on_face(extrude_group, tag, args).await?;
|
||||
let face = start_sketch_on_face(extrude_group, tag, exec_state, args).await?;
|
||||
Ok(SketchSurface::Face(face))
|
||||
}
|
||||
}
|
||||
@ -1141,9 +1152,10 @@ async fn inner_start_sketch_on(data: SketchData, tag: Option<FaceTag>, args: Arg
|
||||
async fn start_sketch_on_face(
|
||||
extrude_group: Box<ExtrudeGroup>,
|
||||
tag: FaceTag,
|
||||
args: Args,
|
||||
exec_state: &mut ExecState,
|
||||
args: &Args,
|
||||
) -> Result<Box<Face>, KclError> {
|
||||
let extrude_plane_id = tag.get_face_id(&extrude_group, &args, true).await?;
|
||||
let extrude_plane_id = tag.get_face_id(&extrude_group, exec_state, args, true).await?;
|
||||
|
||||
Ok(Box::new(Face {
|
||||
id: extrude_plane_id,
|
||||
@ -1157,7 +1169,7 @@ async fn start_sketch_on_face(
|
||||
}))
|
||||
}
|
||||
|
||||
async fn start_sketch_on_plane(data: PlaneData, args: Args) -> Result<Box<Plane>, KclError> {
|
||||
async fn start_sketch_on_plane(data: PlaneData, args: &Args) -> Result<Box<Plane>, KclError> {
|
||||
let mut plane: Plane = data.clone().into();
|
||||
|
||||
// Get the default planes.
|
||||
@ -1199,11 +1211,11 @@ async fn start_sketch_on_plane(data: PlaneData, args: Args) -> Result<Box<Plane>
|
||||
}
|
||||
|
||||
/// Start a new profile at a given point.
|
||||
pub async fn start_profile_at(args: Args) -> Result<KclValue, KclError> {
|
||||
pub async fn start_profile_at(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let (start, sketch_surface, tag): ([f64; 2], SketchSurface, Option<TagDeclarator>) =
|
||||
args.get_data_and_sketch_surface()?;
|
||||
|
||||
let sketch_group = inner_start_profile_at(start, sketch_surface, tag, args).await?;
|
||||
let sketch_group = inner_start_profile_at(start, sketch_surface, tag, exec_state, args).await?;
|
||||
Ok(KclValue::new_user_val(sketch_group.meta.clone(), sketch_group))
|
||||
}
|
||||
|
||||
@ -1248,12 +1260,13 @@ pub(crate) async fn inner_start_profile_at(
|
||||
to: [f64; 2],
|
||||
sketch_surface: SketchSurface,
|
||||
tag: Option<TagDeclarator>,
|
||||
exec_state: &mut ExecState,
|
||||
args: Args,
|
||||
) -> Result<SketchGroup, KclError> {
|
||||
if let SketchSurface::Face(face) = &sketch_surface {
|
||||
// Flush the batch for our fillets/chamfers if there are any.
|
||||
// If we do not do these for sketch on face, things will fail with face does not exist.
|
||||
args.flush_batch_for_extrude_group_set(face.extrude_group.clone().into())
|
||||
args.flush_batch_for_extrude_group_set(exec_state, face.extrude_group.clone().into())
|
||||
.await?;
|
||||
}
|
||||
|
||||
@ -1328,7 +1341,7 @@ pub(crate) async fn inner_start_profile_at(
|
||||
}
|
||||
|
||||
/// Returns the X component of the sketch profile start point.
|
||||
pub async fn profile_start_x(args: Args) -> Result<KclValue, KclError> {
|
||||
pub async fn profile_start_x(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let sketch_group: SketchGroup = args.get_sketch_group()?;
|
||||
let x = inner_profile_start_x(sketch_group)?;
|
||||
args.make_user_val_from_f64(x)
|
||||
@ -1352,7 +1365,7 @@ pub(crate) fn inner_profile_start_x(sketch_group: SketchGroup) -> Result<f64, Kc
|
||||
}
|
||||
|
||||
/// Returns the Y component of the sketch profile start point.
|
||||
pub async fn profile_start_y(args: Args) -> Result<KclValue, KclError> {
|
||||
pub async fn profile_start_y(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let sketch_group: SketchGroup = args.get_sketch_group()?;
|
||||
let x = inner_profile_start_y(sketch_group)?;
|
||||
args.make_user_val_from_f64(x)
|
||||
@ -1375,7 +1388,7 @@ pub(crate) fn inner_profile_start_y(sketch_group: SketchGroup) -> Result<f64, Kc
|
||||
}
|
||||
|
||||
/// Returns the sketch profile start point.
|
||||
pub async fn profile_start(args: Args) -> Result<KclValue, KclError> {
|
||||
pub async fn profile_start(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let sketch_group: SketchGroup = args.get_sketch_group()?;
|
||||
let point = inner_profile_start(sketch_group)?;
|
||||
Ok(KclValue::UserVal(UserVal {
|
||||
@ -1409,7 +1422,7 @@ pub(crate) fn inner_profile_start(sketch_group: SketchGroup) -> Result<[f64; 2],
|
||||
}
|
||||
|
||||
/// Close the current sketch.
|
||||
pub async fn close(args: Args) -> Result<KclValue, KclError> {
|
||||
pub async fn close(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let (sketch_group, tag): (SketchGroup, Option<TagDeclarator>) = args.get_sketch_group_and_optional_tag()?;
|
||||
|
||||
let new_sketch_group = inner_close(sketch_group, tag, args).await?;
|
||||
@ -1516,7 +1529,7 @@ pub enum ArcData {
|
||||
}
|
||||
|
||||
/// Draw an arc.
|
||||
pub async fn arc(args: Args) -> Result<KclValue, KclError> {
|
||||
pub async fn arc(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let (data, sketch_group, tag): (ArcData, SketchGroup, Option<TagDeclarator>) =
|
||||
args.get_data_and_sketch_group_and_tag()?;
|
||||
|
||||
@ -1637,7 +1650,7 @@ pub enum TangentialArcData {
|
||||
}
|
||||
|
||||
/// Draw a tangential arc.
|
||||
pub async fn tangential_arc(args: Args) -> Result<KclValue, KclError> {
|
||||
pub async fn tangential_arc(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let (data, sketch_group, tag): (TangentialArcData, SketchGroup, Option<TagDeclarator>) =
|
||||
args.get_data_and_sketch_group_and_tag()?;
|
||||
|
||||
@ -1767,7 +1780,7 @@ fn tan_arc_to(sketch_group: &SketchGroup, to: &[f64; 2]) -> ModelingCmd {
|
||||
}
|
||||
|
||||
/// Draw a tangential arc to a specific point.
|
||||
pub async fn tangential_arc_to(args: Args) -> Result<KclValue, KclError> {
|
||||
pub async fn tangential_arc_to(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let (to, sketch_group, tag): ([f64; 2], SketchGroup, Option<TagDeclarator>) =
|
||||
super::args::FromArgs::from_args(&args, 0)?;
|
||||
|
||||
@ -1776,7 +1789,7 @@ pub async fn tangential_arc_to(args: Args) -> Result<KclValue, KclError> {
|
||||
}
|
||||
|
||||
/// Draw a tangential arc to point some distance away..
|
||||
pub async fn tangential_arc_to_relative(args: Args) -> Result<KclValue, KclError> {
|
||||
pub async fn tangential_arc_to_relative(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let (delta, sketch_group, tag): ([f64; 2], SketchGroup, Option<TagDeclarator>) =
|
||||
super::args::FromArgs::from_args(&args, 0)?;
|
||||
|
||||
@ -1951,7 +1964,7 @@ pub struct BezierData {
|
||||
}
|
||||
|
||||
/// Draw a bezier curve.
|
||||
pub async fn bezier_curve(args: Args) -> Result<KclValue, KclError> {
|
||||
pub async fn bezier_curve(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let (data, sketch_group, tag): (BezierData, SketchGroup, Option<TagDeclarator>) =
|
||||
args.get_data_and_sketch_group_and_tag()?;
|
||||
|
||||
@ -2043,7 +2056,7 @@ async fn inner_bezier_curve(
|
||||
}
|
||||
|
||||
/// Use a sketch to cut a hole in another sketch.
|
||||
pub async fn hole(args: Args) -> Result<KclValue, KclError> {
|
||||
pub async fn hole(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let (hole_sketch_group, sketch_group): (SketchGroupSet, SketchGroup) = args.get_sketch_groups()?;
|
||||
|
||||
let new_sketch_group = inner_hole(hole_sketch_group, sketch_group, args).await?;
|
||||
|
@ -4,10 +4,15 @@ use anyhow::Result;
|
||||
use derive_docs::stdlib;
|
||||
use schemars::JsonSchema;
|
||||
|
||||
use crate::{errors::KclError, executor::KclValue, settings::types::UnitLength, std::Args};
|
||||
use crate::{
|
||||
errors::KclError,
|
||||
executor::{ExecState, KclValue},
|
||||
settings::types::UnitLength,
|
||||
std::Args,
|
||||
};
|
||||
|
||||
/// Millimeters conversion factor for current projects units.
|
||||
pub async fn mm(args: Args) -> Result<KclValue, KclError> {
|
||||
pub async fn mm(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let result = inner_mm(&args)?;
|
||||
|
||||
args.make_user_val_from_f64(result)
|
||||
@ -48,7 +53,7 @@ fn inner_mm(args: &Args) -> Result<f64, KclError> {
|
||||
}
|
||||
|
||||
/// Inches conversion factor for current projects units.
|
||||
pub async fn inch(args: Args) -> Result<KclValue, KclError> {
|
||||
pub async fn inch(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let result = inner_inch(&args)?;
|
||||
|
||||
args.make_user_val_from_f64(result)
|
||||
@ -89,7 +94,7 @@ fn inner_inch(args: &Args) -> Result<f64, KclError> {
|
||||
}
|
||||
|
||||
/// Feet conversion factor for current projects units.
|
||||
pub async fn ft(args: Args) -> Result<KclValue, KclError> {
|
||||
pub async fn ft(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let result = inner_ft(&args)?;
|
||||
|
||||
args.make_user_val_from_f64(result)
|
||||
@ -131,7 +136,7 @@ fn inner_ft(args: &Args) -> Result<f64, KclError> {
|
||||
}
|
||||
|
||||
/// Meters conversion factor for current projects units.
|
||||
pub async fn m(args: Args) -> Result<KclValue, KclError> {
|
||||
pub async fn m(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let result = inner_m(&args)?;
|
||||
|
||||
args.make_user_val_from_f64(result)
|
||||
@ -173,7 +178,7 @@ fn inner_m(args: &Args) -> Result<f64, KclError> {
|
||||
}
|
||||
|
||||
/// Centimeters conversion factor for current projects units.
|
||||
pub async fn cm(args: Args) -> Result<KclValue, KclError> {
|
||||
pub async fn cm(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let result = inner_cm(&args)?;
|
||||
|
||||
args.make_user_val_from_f64(result)
|
||||
@ -215,7 +220,7 @@ fn inner_cm(args: &Args) -> Result<f64, KclError> {
|
||||
}
|
||||
|
||||
/// Yards conversion factor for current projects units.
|
||||
pub async fn yd(args: Args) -> Result<KclValue, KclError> {
|
||||
pub async fn yd(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let result = inner_yd(&args)?;
|
||||
|
||||
args.make_user_val_from_f64(result)
|
||||
|
@ -53,13 +53,13 @@ pub async fn execute_wasm(
|
||||
is_mock,
|
||||
};
|
||||
|
||||
let memory = ctx.run(&program, Some(memory)).await.map_err(String::from)?;
|
||||
let exec_state = ctx.run(&program, Some(memory)).await.map_err(String::from)?;
|
||||
|
||||
// The serde-wasm-bindgen does not work here because of weird HashMap issues so we use the
|
||||
// gloo-serialize crate instead.
|
||||
// DO NOT USE serde_wasm_bindgen::to_value(&memory).map_err(|e| e.to_string())
|
||||
// it will break the frontend.
|
||||
JsValue::from_serde(&memory).map_err(|e| e.to_string())
|
||||
JsValue::from_serde(&exec_state.memory).map_err(|e| e.to_string())
|
||||
}
|
||||
|
||||
// wasm_bindgen wrapper for execute
|
||||
|
@ -0,0 +1,7 @@
|
||||
// Make sure pipe value doesn't leak into the function call.
|
||||
fn f = (ignored) => {
|
||||
return %
|
||||
}
|
||||
|
||||
const answer = %
|
||||
|> f(%)
|
@ -85,5 +85,9 @@ gen_test_fail!(
|
||||
object_prop_not_found,
|
||||
"undefined value: Property 'age' not found in object"
|
||||
);
|
||||
gen_test_fail!(
|
||||
pipe_substitution_inside_function_called_from_pipeline,
|
||||
"semantic: cannot use % outside a pipe expression"
|
||||
);
|
||||
gen_test!(sketch_group_in_object);
|
||||
gen_test!(add_lots);
|
||||
|
@ -35,12 +35,12 @@ async fn setup(code: &str, name: &str) -> Result<(ExecutorContext, Program, uuid
|
||||
let parser = kcl_lib::parser::Parser::new(tokens);
|
||||
let program = parser.ast()?;
|
||||
let ctx = kcl_lib::executor::ExecutorContext::new(&client, Default::default()).await?;
|
||||
let memory = ctx.run(&program, None).await?;
|
||||
let exec_state = ctx.run(&program, None).await?;
|
||||
|
||||
// We need to get the sketch ID.
|
||||
// Get the sketch group ID from memory.
|
||||
let KclValue::UserVal(user_val) = memory.get(name, SourceRange::default()).unwrap() else {
|
||||
anyhow::bail!("part001 not found in memory: {:?}", memory);
|
||||
let KclValue::UserVal(user_val) = exec_state.memory.get(name, SourceRange::default()).unwrap() else {
|
||||
anyhow::bail!("part001 not found in memory: {:?}", exec_state.memory);
|
||||
};
|
||||
let Some((sketch_group, _meta)) = user_val.get::<SketchGroup>() else {
|
||||
anyhow::bail!("part001 was not a SketchGroup");
|
||||
|
Reference in New Issue
Block a user