Compare commits
4 Commits
pierremtb/
...
lee/native
Author | SHA1 | Date | |
---|---|---|---|
17ddf52264 | |||
d318f4ddb2 | |||
7823bff8d7 | |||
9ef114d1bd |
44
src/wasm-lib/Cargo.lock
generated
44
src/wasm-lib/Cargo.lock
generated
@ -1460,13 +1460,16 @@ name = "grackle"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"kcl-lib",
|
||||
"kittycad",
|
||||
"kittycad-execution-plan",
|
||||
"kittycad-execution-plan-traits",
|
||||
"kittycad-modeling-cmds",
|
||||
"kittycad-modeling-session",
|
||||
"pretty_assertions",
|
||||
"serde_json",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1912,7 +1915,7 @@ dependencies = [
|
||||
"itertools 0.12.1",
|
||||
"js-sys",
|
||||
"kittycad",
|
||||
"kittycad-execution-plan-macros 0.1.4 (git+https://github.com/KittyCAD/modeling-api?branch=main)",
|
||||
"kittycad-execution-plan-macros",
|
||||
"kittycad-execution-plan-traits",
|
||||
"lazy_static",
|
||||
"parse-display 0.9.0",
|
||||
@ -1986,7 +1989,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "kittycad-execution-plan"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/KittyCAD/modeling-api?branch=main#08f05d91062380fe3a69f4baa1f1301532d31977"
|
||||
source = "git+https://github.com/KittyCAD/modeling-api?branch=main#be68126f2dbf6c15f44fb72db5b5cb44122aed36"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"insta",
|
||||
@ -2004,19 +2007,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kittycad-execution-plan-macros"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "71d31b689c944d00aadda2ef83d8422a6efff97e1be5654a61f9d95496f0c19e"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.49",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "kittycad-execution-plan-macros"
|
||||
version = "0.1.4"
|
||||
source = "git+https://github.com/KittyCAD/modeling-api?branch=main#632b75a0242400fa34373d7973b9149b0e08aa3f"
|
||||
version = "0.1.5"
|
||||
source = "git+https://github.com/KittyCAD/modeling-api?branch=main#be68126f2dbf6c15f44fb72db5b5cb44122aed36"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -2026,8 +2018,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "kittycad-execution-plan-traits"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a3ec8efd57b59697eb140b63c0ffe7db44fdfe5a55f14e45513411eba2280ba5"
|
||||
source = "git+https://github.com/KittyCAD/modeling-api?branch=main#be68126f2dbf6c15f44fb72db5b5cb44122aed36"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"thiserror",
|
||||
@ -2036,8 +2027,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kittycad-modeling-cmds"
|
||||
version = "0.1.18"
|
||||
source = "git+https://github.com/KittyCAD/modeling-api?branch=main#08f05d91062380fe3a69f4baa1f1301532d31977"
|
||||
version = "0.1.24"
|
||||
source = "git+https://github.com/KittyCAD/modeling-api?branch=main#be68126f2dbf6c15f44fb72db5b5cb44122aed36"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"chrono",
|
||||
@ -2047,8 +2038,9 @@ dependencies = [
|
||||
"enum-iterator-derive",
|
||||
"euler",
|
||||
"http 0.2.9",
|
||||
"kittycad-execution-plan-macros 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"kittycad-execution-plan-macros",
|
||||
"kittycad-execution-plan-traits",
|
||||
"kittycad-modeling-cmds-macros",
|
||||
"kittycad-unit-conversion-derive",
|
||||
"measurements",
|
||||
"parse-display 0.8.2",
|
||||
@ -2061,10 +2053,20 @@ dependencies = [
|
||||
"webrtc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "kittycad-modeling-cmds-macros"
|
||||
version = "0.1.1"
|
||||
source = "git+https://github.com/KittyCAD/modeling-api?branch=main#be68126f2dbf6c15f44fb72db5b5cb44122aed36"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.49",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "kittycad-modeling-session"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/KittyCAD/modeling-api?branch=main#08f05d91062380fe3a69f4baa1f1301532d31977"
|
||||
source = "git+https://github.com/KittyCAD/modeling-api?branch=main#be68126f2dbf6c15f44fb72db5b5cb44122aed36"
|
||||
dependencies = [
|
||||
"futures",
|
||||
"kittycad",
|
||||
|
@ -60,9 +60,10 @@ members = [
|
||||
[workspace.dependencies]
|
||||
kittycad = { version = "0.2.54", default-features = false, features = ["js", "requests"] }
|
||||
kittycad-execution-plan = { git = "https://github.com/KittyCAD/modeling-api", branch = "main" }
|
||||
kittycad-execution-plan-traits = "0.1.10"
|
||||
kittycad-modeling-session = { git = "https://github.com/KittyCAD/modeling-api", branch = "main" }
|
||||
kittycad-execution-plan-macros = { git = "https://github.com/KittyCAD/modeling-api", branch = "main" }
|
||||
kittycad-execution-plan-traits = { git = "https://github.com/KittyCAD/modeling-api", branch = "main" }
|
||||
kittycad-modeling-cmds = { git = "https://github.com/KittyCAD/modeling-api", branch = "main" }
|
||||
kittycad-modeling-session = { git = "https://github.com/KittyCAD/modeling-api", branch = "main" }
|
||||
|
||||
[[test]]
|
||||
name = "executor"
|
||||
@ -73,6 +74,9 @@ name = "modify"
|
||||
path = "tests/modify/main.rs"
|
||||
|
||||
# Example: how to point modeling-api at a different repo (e.g. a branch or a local clone)
|
||||
# [patch."https://github.com/KittyCAD/modeling-api"]
|
||||
# kittycad-execution-plan = { path = "../../../modeling-api/execution-plan" }
|
||||
# kittycad-modeling-session = { path = "../../../modeling-api/modeling-session" }
|
||||
#[patch."https://github.com/KittyCAD/modeling-api"]
|
||||
#kittycad-execution-plan = { path = "../../../modeling-api/execution-plan" }
|
||||
#kittycad-execution-plan-macros = { path = "../../../modeling-api/execution-plan-macros" }
|
||||
#kittycad-execution-plan-traits = { path = "../../../modeling-api/execution-plan-traits" }
|
||||
#kittycad-modeling-cmds = { path = "../../../modeling-api/modeling-cmds" }
|
||||
#kittycad-modeling-session = { path = "../../../modeling-api/modeling-session" }
|
||||
|
@ -7,11 +7,14 @@ description = "A new executor for KCL which compiles to Execution Plans"
|
||||
|
||||
[dependencies]
|
||||
kcl-lib = { path = "../kcl" }
|
||||
kittycad = { workspace = true }
|
||||
kittycad-execution-plan = { workspace = true }
|
||||
kittycad-execution-plan-traits = { workspace = true }
|
||||
kittycad-modeling-cmds = { workspace = true }
|
||||
kittycad-modeling-session = { workspace = true }
|
||||
thiserror = "1.0.57"
|
||||
tokio = { version = "1.36.0", features = ["macros", "rt"] }
|
||||
uuid = "1.7"
|
||||
|
||||
[dev-dependencies]
|
||||
pretty_assertions = "1"
|
||||
|
@ -2,8 +2,12 @@ use std::collections::HashMap;
|
||||
|
||||
use kcl_lib::ast::types::{LiteralIdentifier, LiteralValue};
|
||||
|
||||
|
||||
use super::{native_functions, Address};
|
||||
use crate::{CompileError, KclFunction};
|
||||
use crate::{
|
||||
CompileError,
|
||||
KclFunction
|
||||
};
|
||||
|
||||
/// KCL values which can be written to KCEP memory.
|
||||
/// This is recursive. For example, the bound value might be an array, which itself contains bound values.
|
||||
@ -99,11 +103,11 @@ impl BindingScope {
|
||||
// TODO: Actually put the stdlib prelude in here,
|
||||
// things like `startSketchAt` and `line`.
|
||||
ep_bindings: HashMap::from([
|
||||
("id".into(), EpBinding::from(KclFunction::Id(native_functions::Id))),
|
||||
("id".into(), EpBinding::from(KclFunction::Id(native_functions::id::Id))),
|
||||
("add".into(), EpBinding::from(KclFunction::Add(native_functions::Add))),
|
||||
(
|
||||
"startSketchAt".into(),
|
||||
EpBinding::from(KclFunction::StartSketchAt(native_functions::StartSketchAt)),
|
||||
EpBinding::from(KclFunction::StartSketchAt(native_functions::sketch::StartSketchAt)),
|
||||
),
|
||||
]),
|
||||
parent: None,
|
||||
|
@ -45,6 +45,12 @@ pub enum CompileError {
|
||||
NoReturnStmt,
|
||||
#[error("You used the %, which means \"substitute this argument for the value to the left in this |> pipeline\". But there is no such value, because you're not calling a pipeline.")]
|
||||
NotInPipeline,
|
||||
#[error("The function '{fn_name}' expects a parameter of type {expected} but you supplied {actual}")]
|
||||
ArgWrongType {
|
||||
fn_name: &'static str,
|
||||
expected: &'static str,
|
||||
actual: String,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
|
@ -589,6 +589,8 @@ fn kcl_literal_to_kcep_literal(expr: LiteralValue) -> ept::Primitive {
|
||||
}
|
||||
|
||||
/// Instructions that can compute some value.
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(test, derive(PartialEq))]
|
||||
struct EvalPlan {
|
||||
/// The instructions which will compute the value.
|
||||
instructions: Vec<Instruction>,
|
||||
@ -617,8 +619,8 @@ impl Eq for UserDefinedFunction {}
|
||||
#[derive(Debug, Clone)]
|
||||
#[cfg_attr(test, derive(Eq, PartialEq))]
|
||||
enum KclFunction {
|
||||
Id(native_functions::Id),
|
||||
StartSketchAt(native_functions::StartSketchAt),
|
||||
Id(native_functions::id::Id),
|
||||
StartSketchAt(native_functions::sketch::StartSketchAt),
|
||||
Add(native_functions::Add),
|
||||
UserDefined(UserDefinedFunction),
|
||||
}
|
||||
|
@ -2,73 +2,18 @@
|
||||
//! This includes some of the stdlib, e.g. `startSketchAt`.
|
||||
//! But some other stdlib functions will be written in KCL.
|
||||
|
||||
use kcl_lib::std::sketch::PlaneData;
|
||||
use kittycad_execution_plan::{BinaryArithmetic, Destination, Instruction};
|
||||
use kittycad_execution_plan_traits::{Address, Value};
|
||||
use kittycad_execution_plan_traits::Address;
|
||||
|
||||
use crate::{CompileError, EpBinding, EvalPlan};
|
||||
|
||||
/// The identity function. Always returns its first input.
|
||||
#[derive(Debug, Clone)]
|
||||
#[cfg_attr(test, derive(Eq, PartialEq))]
|
||||
pub struct Id;
|
||||
pub mod sketch;
|
||||
pub mod id;
|
||||
|
||||
pub trait Callable {
|
||||
fn call(&self, next_addr: &mut Address, args: Vec<EpBinding>) -> Result<EvalPlan, CompileError>;
|
||||
}
|
||||
|
||||
impl Callable for Id {
|
||||
fn call(&self, _: &mut Address, args: Vec<EpBinding>) -> Result<EvalPlan, CompileError> {
|
||||
if args.len() > 1 {
|
||||
return Err(CompileError::TooManyArgs {
|
||||
fn_name: "id".into(),
|
||||
maximum: 1,
|
||||
actual: args.len(),
|
||||
});
|
||||
}
|
||||
let arg = args
|
||||
.first()
|
||||
.ok_or(CompileError::NotEnoughArgs {
|
||||
fn_name: "id".into(),
|
||||
required: 1,
|
||||
actual: 0,
|
||||
})?
|
||||
.clone();
|
||||
Ok(EvalPlan {
|
||||
instructions: Vec::new(),
|
||||
binding: arg,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[cfg_attr(test, derive(Eq, PartialEq))]
|
||||
pub struct StartSketchAt;
|
||||
|
||||
impl Callable for StartSketchAt {
|
||||
fn call(&self, next_addr: &mut Address, _args: Vec<EpBinding>) -> Result<EvalPlan, CompileError> {
|
||||
let mut instructions = Vec::new();
|
||||
// Store the plane.
|
||||
let plane = PlaneData::XY.into_parts();
|
||||
instructions.push(Instruction::SetValue {
|
||||
address: next_addr.offset_by(plane.len()),
|
||||
value_parts: plane,
|
||||
});
|
||||
// TODO: Get the plane ID from global context.
|
||||
// TODO: Send this command:
|
||||
// ModelingCmd::SketchModeEnable {
|
||||
// animated: false,
|
||||
// ortho: false,
|
||||
// plane_id: plane.id,
|
||||
// // We pass in the normal for the plane here.
|
||||
// disable_camera_with_plane: Some(plane.z_axis.clone().into()),
|
||||
// },
|
||||
// TODO: Send ModelingCmd::StartPath at the given point.
|
||||
// TODO (maybe): Store the SketchGroup in KCEP memory.
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
/// A test function that adds two numbers.
|
||||
#[derive(Debug, Clone)]
|
||||
#[cfg_attr(test, derive(Eq, PartialEq))]
|
||||
|
91
src/wasm-lib/grackle/src/native_functions/id.rs
Normal file
91
src/wasm-lib/grackle/src/native_functions/id.rs
Normal file
@ -0,0 +1,91 @@
|
||||
use kittycad_execution_plan_traits::Address;
|
||||
|
||||
use crate::{CompileError, EpBinding, EvalPlan};
|
||||
|
||||
use super::Callable;
|
||||
|
||||
/// The identity function. Always returns its first input.
|
||||
#[derive(Debug, Clone)]
|
||||
#[cfg_attr(test, derive(Eq, PartialEq))]
|
||||
pub struct Id;
|
||||
|
||||
impl Callable for Id {
|
||||
fn call(&self, _next_addr: &mut Address, args: Vec<EpBinding>) -> Result<EvalPlan, CompileError> {
|
||||
if args.len() > 1 {
|
||||
return Err(CompileError::TooManyArgs {
|
||||
fn_name: "id".into(),
|
||||
maximum: 1,
|
||||
actual: args.len(),
|
||||
});
|
||||
} else if args.len() < 1 {
|
||||
return Err(CompileError::NotEnoughArgs {
|
||||
fn_name: "id".into(),
|
||||
required: 1,
|
||||
actual: args.len(),
|
||||
});
|
||||
}
|
||||
|
||||
let arg = args.get(0).unwrap().clone();
|
||||
|
||||
Ok(EvalPlan {
|
||||
instructions: vec![],
|
||||
binding: arg,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn call_id() {
|
||||
let fn_id = Id {};
|
||||
let mut addr = Address::ZERO;
|
||||
addr = addr.offset_by(1);
|
||||
let args = vec![EpBinding::Single(addr)];
|
||||
let ep = fn_id.call(&mut addr, args.clone());
|
||||
|
||||
assert_eq!(
|
||||
ep,
|
||||
Ok(EvalPlan{
|
||||
instructions: vec![],
|
||||
binding: args.get(0).unwrap().clone()
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn call_id_too_many_args() {
|
||||
let fn_id = Id {};
|
||||
let mut addr = Address::ZERO;
|
||||
let b1 = EpBinding::Single(addr);
|
||||
addr = addr.offset_by(1);
|
||||
let b2 = EpBinding::Single(addr);
|
||||
addr = addr.offset_by(1);
|
||||
|
||||
let args = vec![b1, b2];
|
||||
let ep = fn_id.call(&mut addr, args.clone());
|
||||
|
||||
assert_eq!(
|
||||
ep,
|
||||
Err(CompileError::TooManyArgs {
|
||||
fn_name: "id".into(),
|
||||
maximum: 1,
|
||||
actual: args.len(),
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn call_id_not_enough_args() {
|
||||
let fn_id = Id {};
|
||||
let mut addr = Address::ZERO;
|
||||
let args = vec![];
|
||||
let ep = fn_id.call(&mut addr, args.clone());
|
||||
|
||||
assert_eq!(
|
||||
ep,
|
||||
Err(CompileError::NotEnoughArgs {
|
||||
fn_name: "id".into(),
|
||||
required: 1,
|
||||
actual: args.len(),
|
||||
})
|
||||
);
|
||||
}
|
202
src/wasm-lib/grackle/src/native_functions/sketch.rs
Normal file
202
src/wasm-lib/grackle/src/native_functions/sketch.rs
Normal file
@ -0,0 +1,202 @@
|
||||
//! Native functions for sketching on the plane.
|
||||
|
||||
use kittycad_execution_plan::{api_request::ApiRequest, Instruction};
|
||||
use kittycad_execution_plan_traits::{Address, InMemory, Value};
|
||||
use kittycad_modeling_cmds::{id::ModelingCmdId, shared::Point3d, ModelingCmdEndpoint};
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::{binding_scope::EpBinding, error::CompileError, EvalPlan};
|
||||
|
||||
use super::Callable;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[cfg_attr(test, derive(Eq, PartialEq))]
|
||||
pub struct StartSketchAt;
|
||||
|
||||
impl Callable for StartSketchAt {
|
||||
fn call(&self, next_addr: &mut Address, args: Vec<EpBinding>) -> Result<EvalPlan, CompileError> {
|
||||
let mut instructions = Vec::new();
|
||||
// First, before we send any API calls, let's validate the arguments to this function.
|
||||
let mut args_iter = args.into_iter();
|
||||
let Some(start) = args_iter.next() else {
|
||||
return Err(CompileError::NotEnoughArgs {
|
||||
fn_name: "startSketchAt".into(),
|
||||
required: 1,
|
||||
actual: 0,
|
||||
});
|
||||
};
|
||||
let start_point = {
|
||||
let expected = "2D point (array with length 2)";
|
||||
let fn_name = "startSketchAt";
|
||||
match start {
|
||||
EpBinding::Single(_) => {
|
||||
return Err(CompileError::ArgWrongType {
|
||||
fn_name,
|
||||
expected,
|
||||
actual: "a single value".to_owned(),
|
||||
})
|
||||
}
|
||||
EpBinding::Sequence { elements, .. } if elements.len() == 2 => {
|
||||
// KCL stores points as an array.
|
||||
// KC API stores them as Rust objects laid flat out in memory.
|
||||
let start = next_addr.offset_by(2);
|
||||
let start_x = start;
|
||||
let start_y = start + 1;
|
||||
let start_z = start + 2;
|
||||
instructions.extend([
|
||||
Instruction::Copy {
|
||||
source: single_binding(
|
||||
elements[0].clone(),
|
||||
"startSketchAt (first parameter, elem 0)",
|
||||
"number",
|
||||
)?,
|
||||
destination: start_x,
|
||||
},
|
||||
Instruction::Copy {
|
||||
source: single_binding(
|
||||
elements[1].clone(),
|
||||
"startSketchAt (first parameter, elem 1)",
|
||||
"number",
|
||||
)?,
|
||||
destination: start_y,
|
||||
},
|
||||
Instruction::SetPrimitive {
|
||||
address: start_z,
|
||||
value: 0.0.into(),
|
||||
},
|
||||
]);
|
||||
start
|
||||
}
|
||||
EpBinding::Sequence { elements, .. } => {
|
||||
return Err(CompileError::ArgWrongType {
|
||||
fn_name,
|
||||
expected,
|
||||
actual: format!("array of length {}", elements.len()),
|
||||
})
|
||||
}
|
||||
EpBinding::Map { .. } => {
|
||||
return Err(CompileError::ArgWrongType {
|
||||
fn_name,
|
||||
expected,
|
||||
actual: "object".to_owned(),
|
||||
})
|
||||
}
|
||||
EpBinding::Function(_) => {
|
||||
return Err(CompileError::ArgWrongType {
|
||||
fn_name,
|
||||
expected,
|
||||
actual: "function".to_owned(),
|
||||
})
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Now the function can start.
|
||||
|
||||
// First API call: make the plane.
|
||||
let plane_id = Uuid::new_v4();
|
||||
stack_api_call(
|
||||
&mut instructions,
|
||||
ModelingCmdEndpoint::MakePlane,
|
||||
None,
|
||||
plane_id.into(),
|
||||
[
|
||||
Some(true).into_parts(), // hide
|
||||
vec![false.into()], // clobber
|
||||
vec![60.0.into()], // size
|
||||
Point3d { x: 0.0, y: 1.0, z: 0.0 }.into_parts(), // Y axis
|
||||
Point3d { x: 1.0, y: 0.0, z: 0.0 }.into_parts(), // X axis
|
||||
Point3d { x: 0.0, y: 0.0, z: 0.0 }.into_parts(), // origin of plane
|
||||
],
|
||||
);
|
||||
|
||||
// Next, enter sketch mode.
|
||||
stack_api_call(
|
||||
&mut instructions,
|
||||
ModelingCmdEndpoint::SketchModeEnable,
|
||||
None,
|
||||
Uuid::new_v4().into(),
|
||||
[
|
||||
Some(Point3d { x: 0.0, y: 0.0, z: 1.0 }).into_parts(), // Z axis
|
||||
vec![false.into()], // animated
|
||||
vec![false.into()], // ortho mode
|
||||
vec![plane_id.into()], // plane ID
|
||||
],
|
||||
);
|
||||
|
||||
// Then start a path
|
||||
let path_id = Uuid::new_v4();
|
||||
no_arg_api_call(&mut instructions, ModelingCmdEndpoint::StartPath, path_id.into());
|
||||
|
||||
// Move the path pen to the given point.
|
||||
instructions.push(Instruction::StackPush {
|
||||
data: vec![path_id.into()],
|
||||
});
|
||||
instructions.push(Instruction::ApiRequest(ApiRequest {
|
||||
endpoint: ModelingCmdEndpoint::MovePathPen,
|
||||
store_response: None,
|
||||
arguments: vec![InMemory::StackPop, InMemory::Address(start_point)],
|
||||
cmd_id: Uuid::new_v4().into(),
|
||||
}));
|
||||
|
||||
// TODO: Store the SketchGroup in KCEP memory.
|
||||
let sketch_group = EpBinding::Single(Address::ZERO + 999);
|
||||
|
||||
Ok(EvalPlan {
|
||||
instructions,
|
||||
binding: sketch_group,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Emit instructions for an API call with no parameters.
|
||||
fn no_arg_api_call(instrs: &mut Vec<Instruction>, endpoint: ModelingCmdEndpoint, cmd_id: ModelingCmdId) {
|
||||
instrs.push(Instruction::ApiRequest(ApiRequest {
|
||||
endpoint,
|
||||
store_response: None,
|
||||
arguments: vec![],
|
||||
cmd_id,
|
||||
}))
|
||||
}
|
||||
|
||||
/// Emit instructions for an API call with the given parameters.
|
||||
/// The API parameters are stored in the EP memory stack.
|
||||
/// So, they have to be pushed onto the stack in the right order,
|
||||
/// i.e. the reverse order in which the API call's Rust struct defines the fields.
|
||||
fn stack_api_call<const N: usize>(
|
||||
instrs: &mut Vec<Instruction>,
|
||||
endpoint: ModelingCmdEndpoint,
|
||||
store_response: Option<Address>,
|
||||
cmd_id: ModelingCmdId,
|
||||
data: [Vec<kittycad_execution_plan_traits::Primitive>; N],
|
||||
) {
|
||||
let arguments = vec![InMemory::StackPop; data.len()];
|
||||
instrs.extend(data.map(|data| Instruction::StackPush { data }));
|
||||
instrs.push(Instruction::ApiRequest(ApiRequest {
|
||||
endpoint,
|
||||
store_response,
|
||||
arguments,
|
||||
cmd_id,
|
||||
}))
|
||||
}
|
||||
|
||||
fn single_binding(b: EpBinding, fn_name: &'static str, expected: &'static str) -> Result<Address, CompileError> {
|
||||
match b {
|
||||
EpBinding::Single(a) => Ok(a),
|
||||
EpBinding::Sequence { .. } => Err(CompileError::ArgWrongType {
|
||||
fn_name,
|
||||
expected,
|
||||
actual: "array".to_owned(),
|
||||
}),
|
||||
EpBinding::Map { .. } => Err(CompileError::ArgWrongType {
|
||||
fn_name,
|
||||
expected,
|
||||
actual: "array".to_owned(),
|
||||
}),
|
||||
EpBinding::Function(_) => Err(CompileError::ArgWrongType {
|
||||
fn_name,
|
||||
expected,
|
||||
actual: "function".to_owned(),
|
||||
}),
|
||||
}
|
||||
}
|
@ -1,7 +1,9 @@
|
||||
use std::collections::HashMap;
|
||||
use std::env;
|
||||
|
||||
use ep::{Destination, UnaryArithmetic};
|
||||
use ept::{ListHeader, ObjectHeader};
|
||||
use kittycad_modeling_session::SessionBuilder;
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
use super::*;
|
||||
@ -1044,6 +1046,71 @@ fn store_object_with_array_property() {
|
||||
)
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn stdlib_cube_partial() {
|
||||
let program = r#"
|
||||
let cube = startSketchAt([22.0, 33.0])
|
||||
"#;
|
||||
let (plan, _scope) = must_plan(program);
|
||||
std::fs::write("stdlib_cube_partial.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);
|
||||
}
|
||||
|
||||
async fn test_client() -> Session {
|
||||
let kittycad_api_token = env::var("KITTYCAD_API_TOKEN").expect("You must set $KITTYCAD_API_TOKEN");
|
||||
let kittycad_api_client = kittycad::Client::new(kittycad_api_token);
|
||||
let session_builder = SessionBuilder {
|
||||
client: kittycad_api_client,
|
||||
fps: Some(10),
|
||||
unlocked_framerate: Some(false),
|
||||
video_res_height: Some(720),
|
||||
video_res_width: Some(1280),
|
||||
buffer_reqs: None,
|
||||
await_response_timeout: None,
|
||||
};
|
||||
match Session::start(session_builder).await {
|
||||
Err(e) => match e {
|
||||
kittycad::types::error::Error::InvalidRequest(s) => panic!("Request did not meet requirements {s}"),
|
||||
kittycad::types::error::Error::CommunicationError(e) => {
|
||||
panic!(" A server error either due to the data, or with the connection: {e}")
|
||||
}
|
||||
kittycad::types::error::Error::RequestError(e) => panic!("Could not build request: {e}"),
|
||||
kittycad::types::error::Error::SerdeError { error, status } => {
|
||||
panic!("Serde error (HTTP {status}): {error}")
|
||||
}
|
||||
kittycad::types::error::Error::InvalidResponsePayload { error, response } => {
|
||||
panic!("Invalid response payload. Error {error}, response {response:?}")
|
||||
}
|
||||
kittycad::types::error::Error::Server { body, status } => panic!("Server error (HTTP {status}): {body}"),
|
||||
kittycad::types::error::Error::UnexpectedResponse(resp) => {
|
||||
let status = resp.status();
|
||||
let url = resp.url().to_owned();
|
||||
match resp.text().await {
|
||||
Ok(body) => panic!(
|
||||
"Unexpected response from KittyCAD API.
|
||||
URL:{url}
|
||||
HTTP {status}
|
||||
---Body----
|
||||
{body}"
|
||||
),
|
||||
Err(e) => panic!(
|
||||
"Unexpected response from KittyCAD API.
|
||||
URL:{url}
|
||||
HTTP {status}
|
||||
---Body could not be read, the error is----
|
||||
{e}"
|
||||
),
|
||||
}
|
||||
}
|
||||
},
|
||||
Ok(x) => x,
|
||||
}
|
||||
}
|
||||
|
||||
#[ignore = "haven't done API calls or stdlib yet"]
|
||||
#[test]
|
||||
fn stdlib_api_calls() {
|
||||
|
Reference in New Issue
Block a user