KCL stdlib and circle function (#1029)

Allows stdlib functions to be written as KCL, not as Rust. 

Rust stdlib functions will hereafter be referred to as "core" not "std".

Right now the only stdlib function I implemented is a circle function (it's a wrapper around the core arc function which sets the arc's start/end to 0 and 360 respectively). I know I want to change this function as soon as KCL has enums, which is my next task. So, I don't want users to start using this right away. To that end, I've named this function "unstable_stdlib_circle" not "circle". Once the function is ready to be stabilized, I can rename it to just "circle".

Note that this PR modifies the existing "sketch and extrude a cylinder" KCL test so that instead of using a user-defined circle function, it uses the unstable_stdlib_circle function now. And the twenty-twenty tests pass, so we know my stdlib is working.

https://github.com/KittyCAD/modeling-app/issues/922
This commit is contained in:
Adam Chalmers
2023-11-09 09:58:20 -06:00
committed by GitHub
parent 0db5db2181
commit b925ed9b65
9 changed files with 356 additions and 413 deletions

View File

@ -1,8 +1,10 @@
//! Functions implemented for language execution.
pub mod extrude;
pub mod kcl_stdlib;
pub mod math;
pub mod segment;
pub mod shapes;
pub mod sketch;
pub mod utils;
@ -16,6 +18,7 @@ use parse_display::{Display, FromStr};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use self::kcl_stdlib::KclStdLibFn;
use crate::{
ast::types::parse_json_number_as_f64,
docs::StdLibFn,
@ -92,12 +95,16 @@ pub fn name_in_stdlib(name: &str) -> bool {
}
pub struct StdLib {
pub fns: HashMap<String, Box<(dyn StdLibFn)>>,
pub fns: HashMap<String, Box<dyn StdLibFn>>,
pub kcl_fns: HashMap<String, Box<dyn KclStdLibFn>>,
}
impl std::fmt::Debug for StdLib {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("StdLib").field("fns.len()", &self.fns.len()).finish()
f.debug_struct("StdLib")
.field("fns.len()", &self.fns.len())
.field("kcl_fns.len()", &self.kcl_fns.len())
.finish()
}
}
@ -109,12 +116,36 @@ impl StdLib {
.map(|internal_fn| (internal_fn.name(), internal_fn))
.collect();
Self { fns }
let kcl_internal_fns: [Box<dyn KclStdLibFn>; 1] = [Box::<shapes::Circle>::default()];
let kcl_fns = kcl_internal_fns
.into_iter()
.map(|internal_fn| (internal_fn.name(), internal_fn))
.collect();
Self { fns, kcl_fns }
}
pub fn get(&self, name: &str) -> Option<Box<dyn StdLibFn>> {
self.fns.get(name).cloned()
}
pub fn get_kcl(&self, name: &str) -> Option<Box<dyn KclStdLibFn>> {
self.kcl_fns.get(name).cloned()
}
pub fn get_either(&self, name: &str) -> FunctionKind {
if let Some(f) = self.get(name) {
FunctionKind::Core(f)
} else if let Some(f) = self.get_kcl(name) {
FunctionKind::Std(f)
} else {
FunctionKind::UserDefined
}
}
pub fn contains_key(&self, key: &str) -> bool {
self.fns.contains_key(key) || self.kcl_fns.contains_key(key)
}
}
impl Default for StdLib {
@ -123,6 +154,12 @@ impl Default for StdLib {
}
}
pub enum FunctionKind {
Core(Box<dyn StdLibFn>),
Std(Box<dyn KclStdLibFn>),
UserDefined,
}
#[derive(Debug, Clone)]
pub struct Args {
pub args: Vec<MemoryItem>,