Grackle: lineTo stdlib function
This commit is contained in:
		
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@ -33,6 +33,7 @@ src/wasm-lib/bindings
 | 
			
		||||
src/wasm-lib/kcl/bindings
 | 
			
		||||
public/wasm_lib_bg.wasm
 | 
			
		||||
src/wasm-lib/lcov.info
 | 
			
		||||
src/wasm-lib/grackle/*.test.json
 | 
			
		||||
 | 
			
		||||
e2e/playwright/playwright-secrets.env
 | 
			
		||||
e2e/playwright/temp1.png
 | 
			
		||||
 | 
			
		||||
@ -105,6 +105,10 @@ impl BindingScope {
 | 
			
		||||
                    "startSketchAt".into(),
 | 
			
		||||
                    EpBinding::from(KclFunction::StartSketchAt(native_functions::sketch::StartSketchAt)),
 | 
			
		||||
                ),
 | 
			
		||||
                (
 | 
			
		||||
                    "lineTo".into(),
 | 
			
		||||
                    EpBinding::from(KclFunction::LineTo(native_functions::sketch::LineTo)),
 | 
			
		||||
                ),
 | 
			
		||||
            ]),
 | 
			
		||||
            parent: None,
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -252,6 +252,7 @@ impl Planner {
 | 
			
		||||
                } = match callee {
 | 
			
		||||
                    KclFunction::Id(f) => f.call(&mut self.next_addr, args)?,
 | 
			
		||||
                    KclFunction::StartSketchAt(f) => f.call(&mut self.next_addr, args)?,
 | 
			
		||||
                    KclFunction::LineTo(f) => f.call(&mut self.next_addr, args)?,
 | 
			
		||||
                    KclFunction::Add(f) => f.call(&mut self.next_addr, args)?,
 | 
			
		||||
                    KclFunction::UserDefined(f) => {
 | 
			
		||||
                        let UserDefinedFunction {
 | 
			
		||||
@ -619,6 +620,7 @@ impl Eq for UserDefinedFunction {}
 | 
			
		||||
enum KclFunction {
 | 
			
		||||
    Id(native_functions::Id),
 | 
			
		||||
    StartSketchAt(native_functions::sketch::StartSketchAt),
 | 
			
		||||
    LineTo(native_functions::sketch::LineTo),
 | 
			
		||||
    Add(native_functions::Add),
 | 
			
		||||
    UserDefined(UserDefinedFunction),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -4,4 +4,4 @@ pub mod helpers;
 | 
			
		||||
pub mod stdlib_functions;
 | 
			
		||||
pub mod types;
 | 
			
		||||
 | 
			
		||||
pub use stdlib_functions::StartSketchAt;
 | 
			
		||||
pub use stdlib_functions::{LineTo, StartSketchAt};
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
use kittycad_execution_plan::{api_request::ApiRequest, Instruction};
 | 
			
		||||
use kittycad_execution_plan::{api_request::ApiRequest, Destination, Instruction};
 | 
			
		||||
use kittycad_execution_plan_traits::{Address, InMemory, Value};
 | 
			
		||||
use kittycad_modeling_cmds::{
 | 
			
		||||
    shared::{Point3d, Point4d},
 | 
			
		||||
@ -12,6 +12,82 @@ use super::{
 | 
			
		||||
};
 | 
			
		||||
use crate::{binding_scope::EpBinding, error::CompileError, native_functions::Callable, EvalPlan};
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Clone)]
 | 
			
		||||
#[cfg_attr(test, derive(Eq, PartialEq))]
 | 
			
		||||
pub struct LineTo;
 | 
			
		||||
 | 
			
		||||
impl Callable for LineTo {
 | 
			
		||||
    fn call(&self, next_addr: &mut Address, args: Vec<EpBinding>) -> Result<EvalPlan, CompileError> {
 | 
			
		||||
        let mut instructions = Vec::new();
 | 
			
		||||
        let fn_name = "lineTo";
 | 
			
		||||
        // Get both required params.
 | 
			
		||||
        let mut args_iter = args.into_iter();
 | 
			
		||||
        let Some(to) = args_iter.next() else {
 | 
			
		||||
            return Err(CompileError::NotEnoughArgs {
 | 
			
		||||
                fn_name: fn_name.into(),
 | 
			
		||||
                required: 2,
 | 
			
		||||
                actual: 0,
 | 
			
		||||
            });
 | 
			
		||||
        };
 | 
			
		||||
        let Some(sketch_group) = args_iter.next() else {
 | 
			
		||||
            return Err(CompileError::NotEnoughArgs {
 | 
			
		||||
                fn_name: fn_name.into(),
 | 
			
		||||
                required: 2,
 | 
			
		||||
                actual: 1,
 | 
			
		||||
            });
 | 
			
		||||
        };
 | 
			
		||||
        // Check the type of both required params.
 | 
			
		||||
        let to = arg_point2d(to, fn_name, &mut instructions, next_addr, 0)?;
 | 
			
		||||
        let sg = single_binding(sketch_group, fn_name, "sketch group", 1)?;
 | 
			
		||||
        let id = Uuid::new_v4();
 | 
			
		||||
        let start_of_line = next_addr.offset(1);
 | 
			
		||||
        let length_of_3d_point = Point3d::<f64>::default().into_parts().len();
 | 
			
		||||
        instructions.extend([
 | 
			
		||||
            // Push the `to` 2D point onto the stack.
 | 
			
		||||
            Instruction::Copy {
 | 
			
		||||
                source: to,
 | 
			
		||||
                length: 2,
 | 
			
		||||
                destination: Destination::StackPush,
 | 
			
		||||
            },
 | 
			
		||||
            // Make it a 3D point.
 | 
			
		||||
            Instruction::StackExtend { data: vec![0.0.into()] },
 | 
			
		||||
            // Append the new path segment to memory.
 | 
			
		||||
            // First comes its tag.
 | 
			
		||||
            Instruction::SetPrimitive {
 | 
			
		||||
                address: start_of_line,
 | 
			
		||||
                value: "Line".to_owned().into(),
 | 
			
		||||
            },
 | 
			
		||||
            // Then its end
 | 
			
		||||
            Instruction::StackPop {
 | 
			
		||||
                destination: Some(start_of_line + 1),
 | 
			
		||||
            },
 | 
			
		||||
            // Then its `relative` field.
 | 
			
		||||
            Instruction::SetPrimitive {
 | 
			
		||||
                address: start_of_line + 1 + length_of_3d_point,
 | 
			
		||||
                value: false.into(),
 | 
			
		||||
            },
 | 
			
		||||
            // Send the ExtendPath request
 | 
			
		||||
            Instruction::ApiRequest(ApiRequest {
 | 
			
		||||
                endpoint: ModelingCmdEndpoint::ExtendPath,
 | 
			
		||||
                store_response: None,
 | 
			
		||||
                arguments: vec![
 | 
			
		||||
                    // Path ID
 | 
			
		||||
                    InMemory::Address(sg + SketchGroup::path_id_offset()),
 | 
			
		||||
                    // Segment
 | 
			
		||||
                    InMemory::Address(start_of_line),
 | 
			
		||||
                ],
 | 
			
		||||
                cmd_id: id.into(),
 | 
			
		||||
            }),
 | 
			
		||||
        ]);
 | 
			
		||||
 | 
			
		||||
        // TODO: Create a new SketchGroup from the old one + add the new path, then store it.
 | 
			
		||||
        Ok(EvalPlan {
 | 
			
		||||
            instructions,
 | 
			
		||||
            binding: EpBinding::Single(Address::ZERO + 9999),
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Clone)]
 | 
			
		||||
#[cfg_attr(test, derive(Eq, PartialEq))]
 | 
			
		||||
pub struct StartSketchAt;
 | 
			
		||||
 | 
			
		||||
@ -7,6 +7,8 @@ use uuid::Uuid;
 | 
			
		||||
/// A sketch group is a collection of paths.
 | 
			
		||||
#[derive(Clone, ExecutionPlanValue)]
 | 
			
		||||
pub struct SketchGroup {
 | 
			
		||||
    // NOTE to developers
 | 
			
		||||
    // Do NOT reorder these fields without updating the  _offset() methods below.
 | 
			
		||||
    /// The id of the sketch group.
 | 
			
		||||
    pub id: Uuid,
 | 
			
		||||
    /// What the sketch is on (can be a plane or a face).
 | 
			
		||||
@ -26,6 +28,10 @@ pub struct SketchGroup {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl SketchGroup {
 | 
			
		||||
    /// Get the offset for the `id` field.
 | 
			
		||||
    pub fn path_id_offset() -> usize {
 | 
			
		||||
        0
 | 
			
		||||
    }
 | 
			
		||||
    pub fn set_base_path(&self, sketch_group: Address, start_point: Address, tag: Option<Address>) -> Vec<Instruction> {
 | 
			
		||||
        let base_path_addr = sketch_group
 | 
			
		||||
            + self.id.into_parts().len()
 | 
			
		||||
 | 
			
		||||
@ -1048,15 +1048,35 @@ fn store_object_with_array_property() {
 | 
			
		||||
#[tokio::test]
 | 
			
		||||
async fn stdlib_cube_partial() {
 | 
			
		||||
    let program = r#"
 | 
			
		||||
    let cube = startSketchAt([22.0, 33.0])
 | 
			
		||||
    let cube = startSketchAt([0.0, 0.0])
 | 
			
		||||
        |> lineTo([4.0, 0.0], %)
 | 
			
		||||
    "#;
 | 
			
		||||
    let (plan, _scope) = must_plan(program);
 | 
			
		||||
    std::fs::write("stdlib_cube_partial.json", serde_json::to_string_pretty(&plan).unwrap()).unwrap();
 | 
			
		||||
    std::fs::write(
 | 
			
		||||
        "stdlib_cube_partial.test.json",
 | 
			
		||||
        serde_json::to_string_pretty(&plan).unwrap(),
 | 
			
		||||
    )
 | 
			
		||||
    .unwrap();
 | 
			
		||||
    let ast = kcl_lib::parser::Parser::new(kcl_lib::token::lexer(program))
 | 
			
		||||
        .ast()
 | 
			
		||||
        .unwrap();
 | 
			
		||||
    let mem = crate::execute(ast, Some(test_client().await)).await.unwrap();
 | 
			
		||||
    dbg!(mem);
 | 
			
		||||
    let client = test_client().await;
 | 
			
		||||
    let _mem = crate::execute(ast, Some(client)).await.unwrap();
 | 
			
		||||
    // use kittycad_modeling_cmds::{each_cmd, ok_response::OkModelingCmdResponse, ImageFormat, ModelingCmd};
 | 
			
		||||
    // let out = client
 | 
			
		||||
    //     .run_command(
 | 
			
		||||
    //         uuid::Uuid::new_v4().into(),
 | 
			
		||||
    //         each_cmd::TakeSnapshot {
 | 
			
		||||
    //             format: ImageFormat::Png,
 | 
			
		||||
    //         },
 | 
			
		||||
    //     )
 | 
			
		||||
    //     .await
 | 
			
		||||
    //     .unwrap();
 | 
			
		||||
    // let out = match out {
 | 
			
		||||
    //     OkModelingCmdResponse::TakeSnapshot(b) => b,
 | 
			
		||||
    //     other => panic!("wrong output: {other:?}"),
 | 
			
		||||
    // };
 | 
			
		||||
    // let out: Vec<u8> = out.contents.into();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async fn test_client() -> Session {
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user