Type check and coerce arguments to user functions and return values from std Rust functions (#6958)
* Shuffle around function call code Signed-off-by: Nick Cameron <nrc@ncameron.org> * Refactor function calls to share more code Signed-off-by: Nick Cameron <nrc@ncameron.org> * Hack to leave the result of revolve as a singleton rather than array Signed-off-by: Nick Cameron <nrc@ncameron.org> --------- Signed-off-by: Nick Cameron <nrc@ncameron.org>
This commit is contained in:
@ -1,7 +1,6 @@
|
||||
use std::num::NonZeroU32;
|
||||
|
||||
use anyhow::Result;
|
||||
use indexmap::IndexMap;
|
||||
use kcmc::{
|
||||
websocket::{ModelingCmdReq, OkWebSocketResponseData},
|
||||
ModelingCmd,
|
||||
@ -15,8 +14,8 @@ use crate::{
|
||||
execution::{
|
||||
kcl_value::FunctionSource,
|
||||
types::{NumericType, PrimitiveType, RuntimeType, UnitAngle, UnitLen, UnitType},
|
||||
ExecState, ExecutorContext, ExtrudeSurface, Helix, KclObjectFields, KclValue, Metadata, PlaneInfo, Sketch,
|
||||
SketchSurface, Solid, TagIdentifier,
|
||||
ExecState, ExtrudeSurface, Helix, KclObjectFields, KclValue, Metadata, PlaneInfo, Sketch, SketchSurface, Solid,
|
||||
TagIdentifier,
|
||||
},
|
||||
parsing::ast::types::TagNode,
|
||||
source_range::SourceRange,
|
||||
@ -28,56 +27,11 @@ use crate::{
|
||||
ModuleId,
|
||||
};
|
||||
|
||||
pub use crate::execution::fn_call::Args;
|
||||
|
||||
const ERROR_STRING_SKETCH_TO_SOLID_HELPER: &str =
|
||||
"You can convert a sketch (2D) into a Solid (3D) by calling a function like `extrude` or `revolve`";
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Arg {
|
||||
/// The evaluated argument.
|
||||
pub value: KclValue,
|
||||
/// The source range of the unevaluated argument.
|
||||
pub source_range: SourceRange,
|
||||
}
|
||||
|
||||
impl Arg {
|
||||
pub fn new(value: KclValue, source_range: SourceRange) -> Self {
|
||||
Self { value, source_range }
|
||||
}
|
||||
|
||||
pub fn synthetic(value: KclValue) -> Self {
|
||||
Self {
|
||||
value,
|
||||
source_range: SourceRange::synthetic(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn source_ranges(&self) -> Vec<SourceRange> {
|
||||
vec![self.source_range]
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct KwArgs {
|
||||
/// Unlabeled keyword args. Currently only the first arg can be unlabeled.
|
||||
/// If the argument was a local variable, then the first element of the tuple is its name
|
||||
/// which may be used to treat this arg as a labelled arg.
|
||||
pub unlabeled: Option<(Option<String>, Arg)>,
|
||||
/// Labeled args.
|
||||
pub labeled: IndexMap<String, Arg>,
|
||||
pub errors: Vec<Arg>,
|
||||
}
|
||||
|
||||
impl KwArgs {
|
||||
/// How many arguments are there?
|
||||
pub fn len(&self) -> usize {
|
||||
self.labeled.len() + if self.unlabeled.is_some() { 1 } else { 0 }
|
||||
}
|
||||
/// Are there no arguments?
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.labeled.len() == 0 && self.unlabeled.is_none()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, PartialEq, ts_rs::TS)]
|
||||
#[ts(export)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
@ -153,41 +107,7 @@ impl JsonSchema for TyF64 {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Args {
|
||||
/// Positional args.
|
||||
pub args: Vec<Arg>,
|
||||
/// Keyword arguments
|
||||
pub kw_args: KwArgs,
|
||||
pub source_range: SourceRange,
|
||||
pub ctx: ExecutorContext,
|
||||
/// If this call happens inside a pipe (|>) expression, this holds the LHS of that |>.
|
||||
/// Otherwise it's None.
|
||||
pub pipe_value: Option<Arg>,
|
||||
}
|
||||
|
||||
impl Args {
|
||||
pub fn new(args: Vec<Arg>, source_range: SourceRange, ctx: ExecutorContext, pipe_value: Option<Arg>) -> Self {
|
||||
Self {
|
||||
args,
|
||||
kw_args: Default::default(),
|
||||
source_range,
|
||||
ctx,
|
||||
pipe_value,
|
||||
}
|
||||
}
|
||||
|
||||
/// Collect the given keyword arguments.
|
||||
pub fn new_kw(kw_args: KwArgs, source_range: SourceRange, ctx: ExecutorContext, pipe_value: Option<Arg>) -> Self {
|
||||
Self {
|
||||
args: Default::default(),
|
||||
kw_args,
|
||||
source_range,
|
||||
ctx,
|
||||
pipe_value,
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a keyword argument. If not set, returns None.
|
||||
pub(crate) fn get_kw_arg_opt<'a, T>(&'a self, label: &str) -> Result<Option<T>, KclError>
|
||||
where
|
||||
@ -339,16 +259,6 @@ impl Args {
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
}
|
||||
|
||||
/// Get the unlabeled keyword argument. If not set, returns None.
|
||||
pub(crate) fn unlabeled_kw_arg_unconverted(&self) -> Option<&Arg> {
|
||||
self.kw_args
|
||||
.unlabeled
|
||||
.as_ref()
|
||||
.map(|(_, a)| a)
|
||||
.or(self.args.first())
|
||||
.or(self.pipe_value.as_ref())
|
||||
}
|
||||
|
||||
/// Get the unlabeled keyword argument. If not set, returns Err. If it
|
||||
/// can't be converted to the given type, returns Err.
|
||||
pub(crate) fn get_unlabeled_kw_arg<'a, T>(&'a self, label: &str) -> Result<T, KclError>
|
||||
|
@ -1,12 +1,9 @@
|
||||
use indexmap::IndexMap;
|
||||
|
||||
use super::{
|
||||
args::{Arg, KwArgs},
|
||||
Args,
|
||||
};
|
||||
use crate::{
|
||||
errors::{KclError, KclErrorDetails},
|
||||
execution::{
|
||||
fn_call::{Arg, Args, KwArgs},
|
||||
kcl_value::{FunctionSource, KclValue},
|
||||
types::RuntimeType,
|
||||
ExecState,
|
||||
|
@ -59,10 +59,7 @@ async fn inner_clone(
|
||||
let mut new_sketch = sketch.clone();
|
||||
new_sketch.id = new_id;
|
||||
new_sketch.original_id = new_id;
|
||||
#[cfg(feature = "artifact-graph")]
|
||||
{
|
||||
new_sketch.artifact_id = new_id.into();
|
||||
}
|
||||
new_sketch.artifact_id = new_id.into();
|
||||
GeometryWithImportedGeometry::Sketch(new_sketch)
|
||||
}
|
||||
GeometryWithImportedGeometry::Solid(solid) => {
|
||||
@ -72,10 +69,7 @@ async fn inner_clone(
|
||||
let mut new_solid = solid.clone();
|
||||
new_solid.id = new_id;
|
||||
new_solid.sketch.original_id = new_id;
|
||||
#[cfg(feature = "artifact-graph")]
|
||||
{
|
||||
new_solid.artifact_id = new_id.into();
|
||||
}
|
||||
new_solid.artifact_id = new_id.into();
|
||||
GeometryWithImportedGeometry::Solid(new_solid)
|
||||
}
|
||||
};
|
||||
@ -118,10 +112,7 @@ async fn fix_tags_and_references(
|
||||
// Make the sketch id the new geometry id.
|
||||
solid.sketch.id = new_geometry_id;
|
||||
solid.sketch.original_id = new_geometry_id;
|
||||
#[cfg(feature = "artifact-graph")]
|
||||
{
|
||||
solid.sketch.artifact_id = new_geometry_id.into();
|
||||
}
|
||||
solid.sketch.artifact_id = new_geometry_id.into();
|
||||
|
||||
fix_sketch_tags_and_references(&mut solid.sketch, &entity_id_map, exec_state).await?;
|
||||
|
||||
@ -148,7 +139,6 @@ async fn fix_tags_and_references(
|
||||
// information.
|
||||
let new_solid = do_post_extrude(
|
||||
&solid.sketch,
|
||||
#[cfg(feature = "artifact-graph")]
|
||||
new_geometry_id.into(),
|
||||
crate::std::args::TyF64::new(
|
||||
solid.height,
|
||||
@ -332,10 +322,8 @@ clonedCube = clone(cube)
|
||||
|
||||
assert_ne!(cube.id, cloned_cube.id);
|
||||
assert_ne!(cube.original_id, cloned_cube.original_id);
|
||||
#[cfg(feature = "artifact-graph")]
|
||||
assert_ne!(cube.artifact_id, cloned_cube.artifact_id);
|
||||
|
||||
#[cfg(feature = "artifact-graph")]
|
||||
assert_eq!(cloned_cube.artifact_id, cloned_cube.id.into());
|
||||
assert_eq!(cloned_cube.original_id, cloned_cube.id);
|
||||
|
||||
@ -384,12 +372,9 @@ clonedCube = clone(cube)
|
||||
assert_ne!(cube.id, cloned_cube.id);
|
||||
assert_ne!(cube.sketch.id, cloned_cube.sketch.id);
|
||||
assert_ne!(cube.sketch.original_id, cloned_cube.sketch.original_id);
|
||||
#[cfg(feature = "artifact-graph")]
|
||||
assert_ne!(cube.artifact_id, cloned_cube.artifact_id);
|
||||
#[cfg(feature = "artifact-graph")]
|
||||
assert_ne!(cube.sketch.artifact_id, cloned_cube.sketch.artifact_id);
|
||||
|
||||
#[cfg(feature = "artifact-graph")]
|
||||
assert_eq!(cloned_cube.artifact_id, cloned_cube.id.into());
|
||||
|
||||
for (path, cloned_path) in cube.sketch.paths.iter().zip(cloned_cube.sketch.paths.iter()) {
|
||||
@ -501,12 +486,9 @@ clonedCube = clone(cube)
|
||||
assert_ne!(cube.id, cloned_cube.id);
|
||||
assert_ne!(cube.sketch.id, cloned_cube.sketch.id);
|
||||
assert_ne!(cube.sketch.original_id, cloned_cube.sketch.original_id);
|
||||
#[cfg(feature = "artifact-graph")]
|
||||
assert_ne!(cube.artifact_id, cloned_cube.artifact_id);
|
||||
#[cfg(feature = "artifact-graph")]
|
||||
assert_ne!(cube.sketch.artifact_id, cloned_cube.sketch.artifact_id);
|
||||
|
||||
#[cfg(feature = "artifact-graph")]
|
||||
assert_eq!(cloned_cube.artifact_id, cloned_cube.id.into());
|
||||
|
||||
for (path, cloned_path) in cube.sketch.paths.iter().zip(cloned_cube.sketch.paths.iter()) {
|
||||
@ -576,12 +558,9 @@ clonedCube = clone(cube)
|
||||
assert_ne!(cube.id, cloned_cube.id);
|
||||
assert_ne!(cube.sketch.id, cloned_cube.sketch.id);
|
||||
assert_ne!(cube.sketch.original_id, cloned_cube.sketch.original_id);
|
||||
#[cfg(feature = "artifact-graph")]
|
||||
assert_ne!(cube.artifact_id, cloned_cube.artifact_id);
|
||||
#[cfg(feature = "artifact-graph")]
|
||||
assert_ne!(cube.sketch.artifact_id, cloned_cube.sketch.artifact_id);
|
||||
|
||||
#[cfg(feature = "artifact-graph")]
|
||||
assert_eq!(cloned_cube.artifact_id, cloned_cube.id.into());
|
||||
|
||||
for (path, cloned_path) in cube.sketch.paths.iter().zip(cloned_cube.sketch.paths.iter()) {
|
||||
@ -679,12 +658,9 @@ clonedCube = clone(cube)
|
||||
assert_ne!(cube.id, cloned_cube.id);
|
||||
assert_ne!(cube.sketch.id, cloned_cube.sketch.id);
|
||||
assert_ne!(cube.sketch.original_id, cloned_cube.sketch.original_id);
|
||||
#[cfg(feature = "artifact-graph")]
|
||||
assert_ne!(cube.artifact_id, cloned_cube.artifact_id);
|
||||
#[cfg(feature = "artifact-graph")]
|
||||
assert_ne!(cube.sketch.artifact_id, cloned_cube.sketch.artifact_id);
|
||||
|
||||
#[cfg(feature = "artifact-graph")]
|
||||
assert_eq!(cloned_cube.artifact_id, cloned_cube.id.into());
|
||||
|
||||
for (value, cloned_value) in cube.value.iter().zip(cloned_cube.value.iter()) {
|
||||
|
@ -17,11 +17,12 @@ use kittycad_modeling_cmds::{self as kcmc};
|
||||
use uuid::Uuid;
|
||||
|
||||
use super::args::TyF64;
|
||||
#[cfg(feature = "artifact-graph")]
|
||||
use crate::execution::ArtifactId;
|
||||
use crate::{
|
||||
errors::{KclError, KclErrorDetails},
|
||||
execution::{types::RuntimeType, ExecState, ExtrudeSurface, GeoMeta, KclValue, Path, Sketch, SketchSurface, Solid},
|
||||
execution::{
|
||||
types::RuntimeType, ArtifactId, ExecState, ExtrudeSurface, GeoMeta, KclValue, Path, Sketch, SketchSurface,
|
||||
Solid,
|
||||
},
|
||||
parsing::ast::types::TagNode,
|
||||
std::Args,
|
||||
};
|
||||
@ -210,7 +211,6 @@ async fn inner_extrude(
|
||||
solids.push(
|
||||
do_post_extrude(
|
||||
sketch,
|
||||
#[cfg(feature = "artifact-graph")]
|
||||
id.into(),
|
||||
length.clone(),
|
||||
false,
|
||||
@ -238,7 +238,7 @@ pub(crate) struct NamedCapTags<'a> {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub(crate) async fn do_post_extrude<'a>(
|
||||
sketch: &Sketch,
|
||||
#[cfg(feature = "artifact-graph")] solid_id: ArtifactId,
|
||||
solid_id: ArtifactId,
|
||||
length: TyF64,
|
||||
sectional: bool,
|
||||
named_cap_tags: &'a NamedCapTags<'a>,
|
||||
@ -431,7 +431,6 @@ pub(crate) async fn do_post_extrude<'a>(
|
||||
// that we passed in to the function, but it's actually the id of the
|
||||
// sketch.
|
||||
id: sketch.id,
|
||||
#[cfg(feature = "artifact-graph")]
|
||||
artifact_id: solid_id,
|
||||
value: new_value,
|
||||
meta: sketch.meta.clone(),
|
||||
|
@ -110,7 +110,6 @@ async fn inner_helix(
|
||||
|
||||
let helix_result = Box::new(HelixValue {
|
||||
value: id,
|
||||
#[cfg(feature = "artifact-graph")]
|
||||
artifact_id: id.into(),
|
||||
revolutions,
|
||||
angle_start,
|
||||
|
@ -177,7 +177,6 @@ async fn inner_loft(
|
||||
Ok(Box::new(
|
||||
do_post_extrude(
|
||||
&sketch,
|
||||
#[cfg(feature = "artifact-graph")]
|
||||
id.into(),
|
||||
TyF64::new(0.0, NumericType::mm()),
|
||||
false,
|
||||
|
@ -328,14 +328,14 @@ impl StdLib {
|
||||
self.fns.get(name).cloned()
|
||||
}
|
||||
|
||||
pub fn get_either(&self, name: &Name) -> FunctionKind {
|
||||
pub fn get_rust_function(&self, name: &Name) -> Option<Box<dyn StdLibFn>> {
|
||||
if let Some(name) = name.local_ident() {
|
||||
if let Some(f) = self.get(name.inner) {
|
||||
return FunctionKind::Core(f);
|
||||
return Some(f);
|
||||
}
|
||||
}
|
||||
|
||||
FunctionKind::UserDefined
|
||||
None
|
||||
}
|
||||
|
||||
pub fn contains_key(&self, key: &str) -> bool {
|
||||
@ -349,11 +349,5 @@ impl Default for StdLib {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum FunctionKind {
|
||||
Core(Box<dyn StdLibFn>),
|
||||
UserDefined,
|
||||
}
|
||||
|
||||
/// The default tolerance for modeling commands in [`kittycad_modeling_cmds::length_unit::LengthUnit`].
|
||||
const DEFAULT_TOLERANCE: f64 = 0.0000001;
|
||||
|
@ -18,15 +18,15 @@ use uuid::Uuid;
|
||||
use crate::{
|
||||
errors::{KclError, KclErrorDetails},
|
||||
execution::{
|
||||
fn_call::{Arg, Args, KwArgs},
|
||||
kcl_value::FunctionSource,
|
||||
types::{NumericType, PrimitiveType, RuntimeType},
|
||||
ExecState, Geometries, Geometry, KclObjectFields, KclValue, Sketch, Solid,
|
||||
},
|
||||
std::{
|
||||
args::{Arg, KwArgs, TyF64},
|
||||
args::TyF64,
|
||||
axis_or_reference::Axis2dOrPoint2d,
|
||||
utils::{point_3d_to_mm, point_to_mm},
|
||||
Args,
|
||||
},
|
||||
ExecutorContext, SourceRange,
|
||||
};
|
||||
|
@ -196,7 +196,6 @@ async fn inner_revolve(
|
||||
solids.push(
|
||||
do_post_extrude(
|
||||
sketch,
|
||||
#[cfg(feature = "artifact-graph")]
|
||||
id.into(),
|
||||
TyF64::new(0.0, NumericType::mm()),
|
||||
false,
|
||||
|
@ -1233,7 +1233,6 @@ async fn start_sketch_on_face(
|
||||
|
||||
Ok(Box::new(Face {
|
||||
id: extrude_plane_id,
|
||||
#[cfg(feature = "artifact-graph")]
|
||||
artifact_id: extrude_plane_id.into(),
|
||||
value: tag.to_string(),
|
||||
// TODO: get this from the extrude plane data.
|
||||
@ -1414,7 +1413,6 @@ pub(crate) async fn inner_start_profile(
|
||||
let sketch = Sketch {
|
||||
id: path_id,
|
||||
original_id: path_id,
|
||||
#[cfg(feature = "artifact-graph")]
|
||||
artifact_id: path_id.into(),
|
||||
on: sketch_surface.clone(),
|
||||
paths: vec![],
|
||||
|
@ -218,7 +218,6 @@ async fn inner_sweep(
|
||||
solids.push(
|
||||
do_post_extrude(
|
||||
sketch,
|
||||
#[cfg(feature = "artifact-graph")]
|
||||
id.into(),
|
||||
TyF64::new(0.0, NumericType::mm()),
|
||||
sectional.unwrap_or(false),
|
||||
|
Reference in New Issue
Block a user