Refactoring: use typed versions of args getters (#7262)
* Replace uses of get_unlabeled_kw_arg with _typed version Signed-off-by: Nick Cameron <nrc@ncameron.org> * Remove more untyped arg getters Signed-off-by: Nick Cameron <nrc@ncameron.org> --------- Signed-off-by: Nick Cameron <nrc@ncameron.org>
This commit is contained in:
		@ -1232,7 +1232,7 @@ secondSketch = startSketchOn(part001, face = '')
 | 
			
		||||
    let err = err.as_kcl_error().unwrap();
 | 
			
		||||
    assert_eq!(
 | 
			
		||||
        err.message(),
 | 
			
		||||
        "The arg face was given, but it was the wrong type. It should be type FaceTag but it was string"
 | 
			
		||||
        "This function expected the input argument to be tag but it's actually of type string"
 | 
			
		||||
    );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -44,6 +44,10 @@ impl RuntimeType {
 | 
			
		||||
        RuntimeType::Primitive(PrimitiveType::Sketch)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn sketch_or_surface() -> Self {
 | 
			
		||||
        RuntimeType::Union(vec![Self::sketch(), Self::plane(), Self::face()])
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// `[Sketch; 1+]`
 | 
			
		||||
    pub fn sketches() -> Self {
 | 
			
		||||
        RuntimeType::Array(
 | 
			
		||||
 | 
			
		||||
@ -28,6 +28,8 @@ use crate::{
 | 
			
		||||
    ModuleId,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
use super::fillet::EdgeReference;
 | 
			
		||||
 | 
			
		||||
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`";
 | 
			
		||||
 | 
			
		||||
@ -214,10 +216,10 @@ impl Args {
 | 
			
		||||
 | 
			
		||||
    /// Get a labelled keyword arg, check it's an array, and return all items in the array
 | 
			
		||||
    /// plus their source range.
 | 
			
		||||
    pub(crate) fn kw_arg_array_and_source<T>(&self, label: &str) -> Result<Vec<(T, SourceRange)>, KclError>
 | 
			
		||||
    where
 | 
			
		||||
        T: for<'a> FromKclValue<'a>,
 | 
			
		||||
    {
 | 
			
		||||
    pub(crate) fn kw_arg_edge_array_and_source(
 | 
			
		||||
        &self,
 | 
			
		||||
        label: &str,
 | 
			
		||||
    ) -> Result<Vec<(EdgeReference, SourceRange)>, KclError> {
 | 
			
		||||
        let Some(arg) = self.kw_args.labeled.get(label) else {
 | 
			
		||||
            let err = KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
                format!("This function requires a keyword argument '{label}'"),
 | 
			
		||||
@ -233,11 +235,7 @@ impl Args {
 | 
			
		||||
                let source = SourceRange::from(item);
 | 
			
		||||
                let val = FromKclValue::from_kcl_val(item).ok_or_else(|| {
 | 
			
		||||
                    KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
                        format!(
 | 
			
		||||
                            "Expected a {} but found {}",
 | 
			
		||||
                            tynm::type_name::<T>(),
 | 
			
		||||
                            arg.value.human_friendly_type()
 | 
			
		||||
                        ),
 | 
			
		||||
                        format!("Expected an Edge but found {}", arg.value.human_friendly_type()),
 | 
			
		||||
                        arg.source_ranges(),
 | 
			
		||||
                    ))
 | 
			
		||||
                })?;
 | 
			
		||||
@ -259,30 +257,6 @@ impl Args {
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// 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>
 | 
			
		||||
    where
 | 
			
		||||
        T: FromKclValue<'a>,
 | 
			
		||||
    {
 | 
			
		||||
        let arg = self
 | 
			
		||||
            .unlabeled_kw_arg_unconverted()
 | 
			
		||||
            .ok_or(KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
                format!("This function requires a value for the special unlabeled first parameter, '{label}'"),
 | 
			
		||||
                vec![self.source_range],
 | 
			
		||||
            )))?;
 | 
			
		||||
 | 
			
		||||
        T::from_kcl_val(&arg.value).ok_or_else(|| {
 | 
			
		||||
            let expected_type_name = tynm::type_name::<T>();
 | 
			
		||||
            let actual_type_name = arg.value.human_friendly_type();
 | 
			
		||||
            let message = format!("This function expected the input argument to be of type {expected_type_name} but it's actually of type {actual_type_name}");
 | 
			
		||||
            KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
                message,
 | 
			
		||||
                arg.source_ranges(),
 | 
			
		||||
            ))
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// 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_typed<T>(
 | 
			
		||||
 | 
			
		||||
@ -70,7 +70,7 @@ async fn call_map_closure(
 | 
			
		||||
pub async fn reduce(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
 | 
			
		||||
    let array: Vec<KclValue> = args.get_unlabeled_kw_arg_typed("array", &RuntimeType::any_array(), exec_state)?;
 | 
			
		||||
    let f: &FunctionSource = args.get_kw_arg("f")?;
 | 
			
		||||
    let initial: KclValue = args.get_kw_arg("initial")?;
 | 
			
		||||
    let initial: KclValue = args.get_kw_arg_typed("initial", &RuntimeType::any(), exec_state)?;
 | 
			
		||||
    inner_reduce(array, initial, f, exec_state, &args).await
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -128,7 +128,7 @@ async fn call_reduce_closure(
 | 
			
		||||
 | 
			
		||||
pub async fn push(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
 | 
			
		||||
    let (mut array, ty) = args.get_unlabeled_kw_arg_array_and_type("array", exec_state)?;
 | 
			
		||||
    let item: KclValue = args.get_kw_arg("item")?;
 | 
			
		||||
    let item: KclValue = args.get_kw_arg_typed("item", &RuntimeType::any(), exec_state)?;
 | 
			
		||||
 | 
			
		||||
    array.push(item);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -6,7 +6,7 @@ use kcl_derive_docs::stdlib;
 | 
			
		||||
use super::args::TyF64;
 | 
			
		||||
use crate::{
 | 
			
		||||
    errors::{KclError, KclErrorDetails},
 | 
			
		||||
    execution::{ExecState, KclValue},
 | 
			
		||||
    execution::{types::RuntimeType, ExecState, KclValue},
 | 
			
		||||
    std::Args,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -20,24 +20,24 @@ async fn _assert(value: bool, message: &str, args: &Args) -> Result<(), KclError
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub async fn assert_is(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
 | 
			
		||||
    let actual = args.get_unlabeled_kw_arg("actual")?;
 | 
			
		||||
    let error = args.get_kw_arg_opt("error")?;
 | 
			
		||||
pub async fn assert_is(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
 | 
			
		||||
    let actual = args.get_unlabeled_kw_arg_typed("actual", &RuntimeType::bool(), exec_state)?;
 | 
			
		||||
    let error = args.get_kw_arg_opt_typed("error", &RuntimeType::string(), exec_state)?;
 | 
			
		||||
    inner_assert_is(actual, error, &args).await?;
 | 
			
		||||
    Ok(KclValue::none())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Check that the provided value is true, or raise a [KclError]
 | 
			
		||||
/// with the provided description.
 | 
			
		||||
pub async fn assert(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
 | 
			
		||||
    let actual = args.get_unlabeled_kw_arg("actual")?;
 | 
			
		||||
    let gt = args.get_kw_arg_opt("isGreaterThan")?;
 | 
			
		||||
    let lt = args.get_kw_arg_opt("isLessThan")?;
 | 
			
		||||
    let gte = args.get_kw_arg_opt("isGreaterThanOrEqual")?;
 | 
			
		||||
    let lte = args.get_kw_arg_opt("isLessThanOrEqual")?;
 | 
			
		||||
    let eq = args.get_kw_arg_opt("isEqualTo")?;
 | 
			
		||||
    let tolerance = args.get_kw_arg_opt("tolerance")?;
 | 
			
		||||
    let error = args.get_kw_arg_opt("error")?;
 | 
			
		||||
pub async fn assert(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
 | 
			
		||||
    let actual = args.get_unlabeled_kw_arg_typed("actual", &RuntimeType::num_any(), exec_state)?;
 | 
			
		||||
    let gt = args.get_kw_arg_opt_typed("isGreaterThan", &RuntimeType::num_any(), exec_state)?;
 | 
			
		||||
    let lt = args.get_kw_arg_opt_typed("isLessThan", &RuntimeType::num_any(), exec_state)?;
 | 
			
		||||
    let gte = args.get_kw_arg_opt_typed("isGreaterThanOrEqual", &RuntimeType::num_any(), exec_state)?;
 | 
			
		||||
    let lte = args.get_kw_arg_opt_typed("isLessThanOrEqual", &RuntimeType::num_any(), exec_state)?;
 | 
			
		||||
    let eq = args.get_kw_arg_opt_typed("isEqualTo", &RuntimeType::num_any(), exec_state)?;
 | 
			
		||||
    let tolerance = args.get_kw_arg_opt_typed("tolerance", &RuntimeType::num_any(), exec_state)?;
 | 
			
		||||
    let error = args.get_kw_arg_opt_typed("error", &RuntimeType::string(), exec_state)?;
 | 
			
		||||
    inner_assert(actual, gt, lt, gte, lte, eq, tolerance, error, &args).await?;
 | 
			
		||||
    Ok(KclValue::none())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -21,7 +21,7 @@ pub(crate) const DEFAULT_TOLERANCE: f64 = 0.0000001;
 | 
			
		||||
pub async fn chamfer(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
 | 
			
		||||
    let solid = args.get_unlabeled_kw_arg_typed("solid", &RuntimeType::Primitive(PrimitiveType::Solid), exec_state)?;
 | 
			
		||||
    let length: TyF64 = args.get_kw_arg_typed("length", &RuntimeType::length(), exec_state)?;
 | 
			
		||||
    let tags = args.kw_arg_array_and_source::<EdgeReference>("tags")?;
 | 
			
		||||
    let tags = args.kw_arg_edge_array_and_source("tags")?;
 | 
			
		||||
    let tag = args.get_kw_arg_opt("tag")?;
 | 
			
		||||
 | 
			
		||||
    super::fillet::validate_unique(&tags)?;
 | 
			
		||||
 | 
			
		||||
@ -31,7 +31,7 @@ use crate::{
 | 
			
		||||
pub async fn extrude(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
 | 
			
		||||
    let sketches = args.get_unlabeled_kw_arg_typed("sketches", &RuntimeType::sketches(), exec_state)?;
 | 
			
		||||
    let length: TyF64 = args.get_kw_arg_typed("length", &RuntimeType::length(), exec_state)?;
 | 
			
		||||
    let symmetric = args.get_kw_arg_opt("symmetric")?;
 | 
			
		||||
    let symmetric = args.get_kw_arg_opt_typed("symmetric", &RuntimeType::bool(), exec_state)?;
 | 
			
		||||
    let bidirectional_length: Option<TyF64> =
 | 
			
		||||
        args.get_kw_arg_opt_typed("bidirectionalLength", &RuntimeType::length(), exec_state)?;
 | 
			
		||||
    let tag_start = args.get_kw_arg_opt("tagStart")?;
 | 
			
		||||
 | 
			
		||||
@ -63,7 +63,7 @@ pub async fn fillet(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
 | 
			
		||||
    let solid = args.get_unlabeled_kw_arg_typed("solid", &RuntimeType::solid(), exec_state)?;
 | 
			
		||||
    let radius: TyF64 = args.get_kw_arg_typed("radius", &RuntimeType::length(), exec_state)?;
 | 
			
		||||
    let tolerance: Option<TyF64> = args.get_kw_arg_opt_typed("tolerance", &RuntimeType::length(), exec_state)?;
 | 
			
		||||
    let tags = args.kw_arg_array_and_source::<EdgeReference>("tags")?;
 | 
			
		||||
    let tags = args.kw_arg_edge_array_and_source("tags")?;
 | 
			
		||||
    let tag = args.get_kw_arg_opt("tag")?;
 | 
			
		||||
 | 
			
		||||
    // Run the function.
 | 
			
		||||
 | 
			
		||||
@ -18,7 +18,7 @@ use crate::{
 | 
			
		||||
pub async fn helix(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
 | 
			
		||||
    let angle_start: TyF64 = args.get_kw_arg_typed("angleStart", &RuntimeType::degrees(), exec_state)?;
 | 
			
		||||
    let revolutions: TyF64 = args.get_kw_arg_typed("revolutions", &RuntimeType::count(), exec_state)?;
 | 
			
		||||
    let ccw = args.get_kw_arg_opt("ccw")?;
 | 
			
		||||
    let ccw = args.get_kw_arg_opt_typed("ccw", &RuntimeType::bool(), exec_state)?;
 | 
			
		||||
    let radius: Option<TyF64> = args.get_kw_arg_opt_typed("radius", &RuntimeType::length(), exec_state)?;
 | 
			
		||||
    let axis: Option<Axis3dOrEdgeReference> = args.get_kw_arg_opt_typed(
 | 
			
		||||
        "axis",
 | 
			
		||||
 | 
			
		||||
@ -24,14 +24,17 @@ const DEFAULT_V_DEGREE: u32 = 2;
 | 
			
		||||
pub async fn loft(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
 | 
			
		||||
    let sketches = args.get_unlabeled_kw_arg_typed("sketches", &RuntimeType::sketches(), exec_state)?;
 | 
			
		||||
    let v_degree: NonZeroU32 = args
 | 
			
		||||
        .get_kw_arg_opt("vDegree")?
 | 
			
		||||
        .get_kw_arg_opt_typed("vDegree", &RuntimeType::count(), exec_state)?
 | 
			
		||||
        .unwrap_or(NonZeroU32::new(DEFAULT_V_DEGREE).unwrap());
 | 
			
		||||
    // Attempt to approximate rational curves (such as arcs) using a bezier.
 | 
			
		||||
    // This will remove banding around interpolations between arcs and non-arcs.  It may produce errors in other scenarios
 | 
			
		||||
    // Over time, this field won't be necessary.
 | 
			
		||||
    let bez_approximate_rational = args.get_kw_arg_opt("bezApproximateRational")?.unwrap_or(false);
 | 
			
		||||
    let bez_approximate_rational = args
 | 
			
		||||
        .get_kw_arg_opt_typed("bezApproximateRational", &RuntimeType::bool(), exec_state)?
 | 
			
		||||
        .unwrap_or(false);
 | 
			
		||||
    // This can be set to override the automatically determined topological base curve, which is usually the first section encountered.
 | 
			
		||||
    let base_curve_index: Option<u32> = args.get_kw_arg_opt("baseCurveIndex")?;
 | 
			
		||||
    let base_curve_index: Option<u32> =
 | 
			
		||||
        args.get_kw_arg_opt_typed("baseCurveIndex", &RuntimeType::count(), exec_state)?;
 | 
			
		||||
    // Tolerance for the loft operation.
 | 
			
		||||
    let tolerance: Option<TyF64> = args.get_kw_arg_opt_typed("tolerance", &RuntimeType::length(), exec_state)?;
 | 
			
		||||
    let tag_start = args.get_kw_arg_opt("tagStart")?;
 | 
			
		||||
 | 
			
		||||
@ -37,9 +37,9 @@ const MUST_HAVE_ONE_INSTANCE: &str = "There must be at least 1 instance of your
 | 
			
		||||
/// Repeat some 3D solid, changing each repetition slightly.
 | 
			
		||||
pub async fn pattern_transform(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
 | 
			
		||||
    let solids = args.get_unlabeled_kw_arg_typed("solids", &RuntimeType::solids(), exec_state)?;
 | 
			
		||||
    let instances: u32 = args.get_kw_arg("instances")?;
 | 
			
		||||
    let instances: u32 = args.get_kw_arg_typed("instances", &RuntimeType::count(), exec_state)?;
 | 
			
		||||
    let transform: &FunctionSource = args.get_kw_arg("transform")?;
 | 
			
		||||
    let use_original: Option<bool> = args.get_kw_arg_opt("useOriginal")?;
 | 
			
		||||
    let use_original = args.get_kw_arg_opt_typed("useOriginal", &RuntimeType::bool(), exec_state)?;
 | 
			
		||||
 | 
			
		||||
    let solids = inner_pattern_transform(solids, instances, transform, use_original, exec_state, &args).await?;
 | 
			
		||||
    Ok(solids.into())
 | 
			
		||||
@ -48,9 +48,9 @@ pub async fn pattern_transform(exec_state: &mut ExecState, args: Args) -> Result
 | 
			
		||||
/// Repeat some 2D sketch, changing each repetition slightly.
 | 
			
		||||
pub async fn pattern_transform_2d(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
 | 
			
		||||
    let sketches = args.get_unlabeled_kw_arg_typed("sketches", &RuntimeType::sketches(), exec_state)?;
 | 
			
		||||
    let instances: u32 = args.get_kw_arg("instances")?;
 | 
			
		||||
    let instances: u32 = args.get_kw_arg_typed("instances", &RuntimeType::count(), exec_state)?;
 | 
			
		||||
    let transform: &FunctionSource = args.get_kw_arg("transform")?;
 | 
			
		||||
    let use_original: Option<bool> = args.get_kw_arg_opt("useOriginal")?;
 | 
			
		||||
    let use_original = args.get_kw_arg_opt_typed("useOriginal", &RuntimeType::bool(), exec_state)?;
 | 
			
		||||
 | 
			
		||||
    let sketches = inner_pattern_transform_2d(sketches, instances, transform, use_original, exec_state, &args).await?;
 | 
			
		||||
    Ok(sketches.into())
 | 
			
		||||
@ -521,7 +521,7 @@ mod tests {
 | 
			
		||||
/// A linear pattern on a 2D sketch.
 | 
			
		||||
pub async fn pattern_linear_2d(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
 | 
			
		||||
    let sketches = args.get_unlabeled_kw_arg_typed("sketches", &RuntimeType::sketches(), exec_state)?;
 | 
			
		||||
    let instances: u32 = args.get_kw_arg("instances")?;
 | 
			
		||||
    let instances: u32 = args.get_kw_arg_typed("instances", &RuntimeType::count(), exec_state)?;
 | 
			
		||||
    let distance: TyF64 = args.get_kw_arg_typed("distance", &RuntimeType::length(), exec_state)?;
 | 
			
		||||
    let axis: Axis2dOrPoint2d = args.get_kw_arg_typed(
 | 
			
		||||
        "axis",
 | 
			
		||||
@ -531,7 +531,7 @@ pub async fn pattern_linear_2d(exec_state: &mut ExecState, args: Args) -> Result
 | 
			
		||||
        ]),
 | 
			
		||||
        exec_state,
 | 
			
		||||
    )?;
 | 
			
		||||
    let use_original: Option<bool> = args.get_kw_arg_opt("useOriginal")?;
 | 
			
		||||
    let use_original = args.get_kw_arg_opt_typed("useOriginal", &RuntimeType::bool(), exec_state)?;
 | 
			
		||||
 | 
			
		||||
    let axis = axis.to_point2d();
 | 
			
		||||
    if axis[0].n == 0.0 && axis[1].n == 0.0 {
 | 
			
		||||
@ -622,7 +622,7 @@ async fn inner_pattern_linear_2d(
 | 
			
		||||
/// A linear pattern on a 3D model.
 | 
			
		||||
pub async fn pattern_linear_3d(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
 | 
			
		||||
    let solids = args.get_unlabeled_kw_arg_typed("solids", &RuntimeType::solids(), exec_state)?;
 | 
			
		||||
    let instances: u32 = args.get_kw_arg("instances")?;
 | 
			
		||||
    let instances: u32 = args.get_kw_arg_typed("instances", &RuntimeType::count(), exec_state)?;
 | 
			
		||||
    let distance: TyF64 = args.get_kw_arg_typed("distance", &RuntimeType::length(), exec_state)?;
 | 
			
		||||
    let axis: Axis3dOrPoint3d = args.get_kw_arg_typed(
 | 
			
		||||
        "axis",
 | 
			
		||||
@ -632,7 +632,7 @@ pub async fn pattern_linear_3d(exec_state: &mut ExecState, args: Args) -> Result
 | 
			
		||||
        ]),
 | 
			
		||||
        exec_state,
 | 
			
		||||
    )?;
 | 
			
		||||
    let use_original: Option<bool> = args.get_kw_arg_opt("useOriginal")?;
 | 
			
		||||
    let use_original = args.get_kw_arg_opt_typed("useOriginal", &RuntimeType::bool(), exec_state)?;
 | 
			
		||||
 | 
			
		||||
    let axis = axis.to_point3d();
 | 
			
		||||
    if axis[0].n == 0.0 && axis[1].n == 0.0 && axis[2].n == 0.0 {
 | 
			
		||||
@ -790,11 +790,11 @@ impl CircularPattern {
 | 
			
		||||
/// A circular pattern on a 2D sketch.
 | 
			
		||||
pub async fn pattern_circular_2d(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
 | 
			
		||||
    let sketches = args.get_unlabeled_kw_arg_typed("sketches", &RuntimeType::sketches(), exec_state)?;
 | 
			
		||||
    let instances: u32 = args.get_kw_arg("instances")?;
 | 
			
		||||
    let instances: u32 = args.get_kw_arg_typed("instances", &RuntimeType::count(), exec_state)?;
 | 
			
		||||
    let center: [TyF64; 2] = args.get_kw_arg_typed("center", &RuntimeType::point2d(), exec_state)?;
 | 
			
		||||
    let arc_degrees: Option<TyF64> = args.get_kw_arg_opt_typed("arcDegrees", &RuntimeType::degrees(), exec_state)?;
 | 
			
		||||
    let rotate_duplicates: Option<bool> = args.get_kw_arg_opt("rotateDuplicates")?;
 | 
			
		||||
    let use_original: Option<bool> = args.get_kw_arg_opt("useOriginal")?;
 | 
			
		||||
    let rotate_duplicates = args.get_kw_arg_opt_typed("rotateDuplicates", &RuntimeType::bool(), exec_state)?;
 | 
			
		||||
    let use_original = args.get_kw_arg_opt_typed("useOriginal", &RuntimeType::bool(), exec_state)?;
 | 
			
		||||
 | 
			
		||||
    let sketches = inner_pattern_circular_2d(
 | 
			
		||||
        sketches,
 | 
			
		||||
@ -915,10 +915,10 @@ pub async fn pattern_circular_3d(exec_state: &mut ExecState, args: Args) -> Resu
 | 
			
		||||
    // The arc angle (in degrees) to place the repetitions. Must be greater than 0.
 | 
			
		||||
    let arc_degrees: Option<TyF64> = args.get_kw_arg_opt_typed("arcDegrees", &RuntimeType::degrees(), exec_state)?;
 | 
			
		||||
    // Whether or not to rotate the duplicates as they are copied.
 | 
			
		||||
    let rotate_duplicates: Option<bool> = args.get_kw_arg_opt("rotateDuplicates")?;
 | 
			
		||||
    let rotate_duplicates = args.get_kw_arg_opt_typed("rotateDuplicates", &RuntimeType::bool(), exec_state)?;
 | 
			
		||||
    // If the target being patterned is itself a pattern, then, should you use the original solid,
 | 
			
		||||
    // or the pattern?
 | 
			
		||||
    let use_original: Option<bool> = args.get_kw_arg_opt("useOriginal")?;
 | 
			
		||||
    let use_original = args.get_kw_arg_opt_typed("useOriginal", &RuntimeType::bool(), exec_state)?;
 | 
			
		||||
 | 
			
		||||
    let solids = inner_pattern_circular_3d(
 | 
			
		||||
        solids,
 | 
			
		||||
 | 
			
		||||
@ -12,7 +12,7 @@ use crate::{
 | 
			
		||||
 | 
			
		||||
/// Offset a plane by a distance along its normal.
 | 
			
		||||
pub async fn offset_plane(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
 | 
			
		||||
    let std_plane = args.get_unlabeled_kw_arg("plane")?;
 | 
			
		||||
    let std_plane = args.get_unlabeled_kw_arg_typed("plane", &RuntimeType::plane(), exec_state)?;
 | 
			
		||||
    let offset: TyF64 = args.get_kw_arg_typed("offset", &RuntimeType::length(), exec_state)?;
 | 
			
		||||
    let plane = inner_offset_plane(std_plane, offset, exec_state, &args).await?;
 | 
			
		||||
    Ok(KclValue::Plane { value: Box::new(plane) })
 | 
			
		||||
 | 
			
		||||
@ -37,7 +37,7 @@ pub async fn revolve(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
 | 
			
		||||
    let tolerance: Option<TyF64> = args.get_kw_arg_opt_typed("tolerance", &RuntimeType::length(), exec_state)?;
 | 
			
		||||
    let tag_start = args.get_kw_arg_opt("tagStart")?;
 | 
			
		||||
    let tag_end = args.get_kw_arg_opt("tagEnd")?;
 | 
			
		||||
    let symmetric = args.get_kw_arg_opt("symmetric")?;
 | 
			
		||||
    let symmetric = args.get_kw_arg_opt_typed("symmetric", &RuntimeType::bool(), exec_state)?;
 | 
			
		||||
    let bidirectional_angle: Option<TyF64> =
 | 
			
		||||
        args.get_kw_arg_opt_typed("bidirectionalAngle", &RuntimeType::angle(), exec_state)?;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -16,7 +16,7 @@ use crate::{
 | 
			
		||||
 | 
			
		||||
/// Returns the point at the end of the given segment.
 | 
			
		||||
pub async fn segment_end(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
 | 
			
		||||
    let tag: TagIdentifier = args.get_unlabeled_kw_arg("tag")?;
 | 
			
		||||
    let tag: TagIdentifier = args.get_unlabeled_kw_arg_typed("tag", &RuntimeType::tag_identifier(), exec_state)?;
 | 
			
		||||
    let pt = inner_segment_end(&tag, exec_state, args.clone())?;
 | 
			
		||||
 | 
			
		||||
    args.make_kcl_val_from_point([pt[0].n, pt[1].n], pt[0].ty.clone())
 | 
			
		||||
@ -72,7 +72,7 @@ fn inner_segment_end(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args
 | 
			
		||||
 | 
			
		||||
/// Returns the segment end of x.
 | 
			
		||||
pub async fn segment_end_x(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
 | 
			
		||||
    let tag: TagIdentifier = args.get_unlabeled_kw_arg("tag")?;
 | 
			
		||||
    let tag: TagIdentifier = args.get_unlabeled_kw_arg_typed("tag", &RuntimeType::tag_identifier(), exec_state)?;
 | 
			
		||||
    let result = inner_segment_end_x(&tag, exec_state, args.clone())?;
 | 
			
		||||
 | 
			
		||||
    Ok(args.make_user_val_from_f64_with_type(result))
 | 
			
		||||
@ -113,7 +113,7 @@ fn inner_segment_end_x(tag: &TagIdentifier, exec_state: &mut ExecState, args: Ar
 | 
			
		||||
 | 
			
		||||
/// Returns the segment end of y.
 | 
			
		||||
pub async fn segment_end_y(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
 | 
			
		||||
    let tag: TagIdentifier = args.get_unlabeled_kw_arg("tag")?;
 | 
			
		||||
    let tag: TagIdentifier = args.get_unlabeled_kw_arg_typed("tag", &RuntimeType::tag_identifier(), exec_state)?;
 | 
			
		||||
    let result = inner_segment_end_y(&tag, exec_state, args.clone())?;
 | 
			
		||||
 | 
			
		||||
    Ok(args.make_user_val_from_f64_with_type(result))
 | 
			
		||||
@ -155,7 +155,7 @@ fn inner_segment_end_y(tag: &TagIdentifier, exec_state: &mut ExecState, args: Ar
 | 
			
		||||
 | 
			
		||||
/// Returns the point at the start of the given segment.
 | 
			
		||||
pub async fn segment_start(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
 | 
			
		||||
    let tag: TagIdentifier = args.get_unlabeled_kw_arg("tag")?;
 | 
			
		||||
    let tag: TagIdentifier = args.get_unlabeled_kw_arg_typed("tag", &RuntimeType::tag_identifier(), exec_state)?;
 | 
			
		||||
    let pt = inner_segment_start(&tag, exec_state, args.clone())?;
 | 
			
		||||
 | 
			
		||||
    args.make_kcl_val_from_point([pt[0].n, pt[1].n], pt[0].ty.clone())
 | 
			
		||||
@ -211,7 +211,7 @@ fn inner_segment_start(tag: &TagIdentifier, exec_state: &mut ExecState, args: Ar
 | 
			
		||||
 | 
			
		||||
/// Returns the segment start of x.
 | 
			
		||||
pub async fn segment_start_x(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
 | 
			
		||||
    let tag: TagIdentifier = args.get_unlabeled_kw_arg("tag")?;
 | 
			
		||||
    let tag: TagIdentifier = args.get_unlabeled_kw_arg_typed("tag", &RuntimeType::tag_identifier(), exec_state)?;
 | 
			
		||||
    let result = inner_segment_start_x(&tag, exec_state, args.clone())?;
 | 
			
		||||
 | 
			
		||||
    Ok(args.make_user_val_from_f64_with_type(result))
 | 
			
		||||
@ -252,7 +252,7 @@ fn inner_segment_start_x(tag: &TagIdentifier, exec_state: &mut ExecState, args:
 | 
			
		||||
 | 
			
		||||
/// Returns the segment start of y.
 | 
			
		||||
pub async fn segment_start_y(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
 | 
			
		||||
    let tag: TagIdentifier = args.get_unlabeled_kw_arg("tag")?;
 | 
			
		||||
    let tag: TagIdentifier = args.get_unlabeled_kw_arg_typed("tag", &RuntimeType::tag_identifier(), exec_state)?;
 | 
			
		||||
    let result = inner_segment_start_y(&tag, exec_state, args.clone())?;
 | 
			
		||||
 | 
			
		||||
    Ok(args.make_user_val_from_f64_with_type(result))
 | 
			
		||||
@ -385,7 +385,7 @@ fn inner_last_segment_y(sketch: Sketch, args: Args) -> Result<TyF64, KclError> {
 | 
			
		||||
 | 
			
		||||
/// Returns the length of the segment.
 | 
			
		||||
pub async fn segment_length(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
 | 
			
		||||
    let tag: TagIdentifier = args.get_unlabeled_kw_arg("tag")?;
 | 
			
		||||
    let tag: TagIdentifier = args.get_unlabeled_kw_arg_typed("tag", &RuntimeType::tag_identifier(), exec_state)?;
 | 
			
		||||
    let result = inner_segment_length(&tag, exec_state, args.clone())?;
 | 
			
		||||
    Ok(args.make_user_val_from_f64_with_type(result))
 | 
			
		||||
}
 | 
			
		||||
@ -431,7 +431,7 @@ fn inner_segment_length(tag: &TagIdentifier, exec_state: &mut ExecState, args: A
 | 
			
		||||
 | 
			
		||||
/// Returns the angle of the segment.
 | 
			
		||||
pub async fn segment_angle(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
 | 
			
		||||
    let tag: TagIdentifier = args.get_unlabeled_kw_arg("tag")?;
 | 
			
		||||
    let tag: TagIdentifier = args.get_unlabeled_kw_arg_typed("tag", &RuntimeType::tag_identifier(), exec_state)?;
 | 
			
		||||
 | 
			
		||||
    let result = inner_segment_angle(&tag, exec_state, args.clone())?;
 | 
			
		||||
    Ok(args.make_user_val_from_f64_with_type(TyF64::new(result, NumericType::degrees())))
 | 
			
		||||
@ -476,7 +476,7 @@ fn inner_segment_angle(tag: &TagIdentifier, exec_state: &mut ExecState, args: Ar
 | 
			
		||||
 | 
			
		||||
/// Returns the angle coming out of the end of the segment in degrees.
 | 
			
		||||
pub async fn tangent_to_end(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
 | 
			
		||||
    let tag: TagIdentifier = args.get_unlabeled_kw_arg("tag")?;
 | 
			
		||||
    let tag: TagIdentifier = args.get_unlabeled_kw_arg_typed("tag", &RuntimeType::tag_identifier(), exec_state)?;
 | 
			
		||||
 | 
			
		||||
    let result = inner_tangent_to_end(&tag, exec_state, args.clone()).await?;
 | 
			
		||||
    Ok(args.make_user_val_from_f64_with_type(TyF64::new(result, NumericType::degrees())))
 | 
			
		||||
 | 
			
		||||
@ -43,7 +43,8 @@ pub enum SketchOrSurface {
 | 
			
		||||
 | 
			
		||||
/// Sketch a circle.
 | 
			
		||||
pub async fn circle(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
 | 
			
		||||
    let sketch_or_surface = args.get_unlabeled_kw_arg("sketchOrSurface")?;
 | 
			
		||||
    let sketch_or_surface =
 | 
			
		||||
        args.get_unlabeled_kw_arg_typed("sketchOrSurface", &RuntimeType::sketch_or_surface(), exec_state)?;
 | 
			
		||||
    let center = args.get_kw_arg_typed("center", &RuntimeType::point2d(), exec_state)?;
 | 
			
		||||
    let radius: Option<TyF64> = args.get_kw_arg_opt_typed("radius", &RuntimeType::length(), exec_state)?;
 | 
			
		||||
    let diameter: Option<TyF64> = args.get_kw_arg_opt_typed("diameter", &RuntimeType::length(), exec_state)?;
 | 
			
		||||
@ -129,13 +130,14 @@ async fn inner_circle(
 | 
			
		||||
 | 
			
		||||
/// Sketch a 3-point circle.
 | 
			
		||||
pub async fn circle_three_point(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
 | 
			
		||||
    let sketch_surface_or_group = args.get_unlabeled_kw_arg("sketch_surface_or_group")?;
 | 
			
		||||
    let sketch_or_surface =
 | 
			
		||||
        args.get_unlabeled_kw_arg_typed("sketchOrSurface", &RuntimeType::sketch_or_surface(), exec_state)?;
 | 
			
		||||
    let p1 = args.get_kw_arg_typed("p1", &RuntimeType::point2d(), exec_state)?;
 | 
			
		||||
    let p2 = args.get_kw_arg_typed("p2", &RuntimeType::point2d(), exec_state)?;
 | 
			
		||||
    let p3 = args.get_kw_arg_typed("p3", &RuntimeType::point2d(), exec_state)?;
 | 
			
		||||
    let tag = args.get_kw_arg_opt("tag")?;
 | 
			
		||||
 | 
			
		||||
    let sketch = inner_circle_three_point(sketch_surface_or_group, p1, p2, p3, tag, exec_state, args).await?;
 | 
			
		||||
    let sketch = inner_circle_three_point(sketch_or_surface, p1, p2, p3, tag, exec_state, args).await?;
 | 
			
		||||
    Ok(KclValue::Sketch {
 | 
			
		||||
        value: Box::new(sketch),
 | 
			
		||||
    })
 | 
			
		||||
@ -257,14 +259,15 @@ pub enum PolygonType {
 | 
			
		||||
 | 
			
		||||
/// Create a regular polygon with the specified number of sides and radius.
 | 
			
		||||
pub async fn polygon(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
 | 
			
		||||
    let sketch_surface_or_group = args.get_unlabeled_kw_arg("sketchOrSurface")?;
 | 
			
		||||
    let sketch_or_surface =
 | 
			
		||||
        args.get_unlabeled_kw_arg_typed("sketchOrSurface", &RuntimeType::sketch_or_surface(), exec_state)?;
 | 
			
		||||
    let radius: TyF64 = args.get_kw_arg_typed("radius", &RuntimeType::length(), exec_state)?;
 | 
			
		||||
    let num_sides: TyF64 = args.get_kw_arg_typed("numSides", &RuntimeType::count(), exec_state)?;
 | 
			
		||||
    let center = args.get_kw_arg_typed("center", &RuntimeType::point2d(), exec_state)?;
 | 
			
		||||
    let inscribed = args.get_kw_arg_opt_typed("inscribed", &RuntimeType::bool(), exec_state)?;
 | 
			
		||||
 | 
			
		||||
    let sketch = inner_polygon(
 | 
			
		||||
        sketch_surface_or_group,
 | 
			
		||||
        sketch_or_surface,
 | 
			
		||||
        radius,
 | 
			
		||||
        num_sides.n as u64,
 | 
			
		||||
        center,
 | 
			
		||||
 | 
			
		||||
@ -107,7 +107,7 @@ pub async fn involute_circular(exec_state: &mut ExecState, args: Args) -> Result
 | 
			
		||||
    let start_radius: TyF64 = args.get_kw_arg_typed("startRadius", &RuntimeType::length(), exec_state)?;
 | 
			
		||||
    let end_radius: TyF64 = args.get_kw_arg_typed("endRadius", &RuntimeType::length(), exec_state)?;
 | 
			
		||||
    let angle: TyF64 = args.get_kw_arg_typed("angle", &RuntimeType::angle(), exec_state)?;
 | 
			
		||||
    let reverse = args.get_kw_arg_opt("reverse")?;
 | 
			
		||||
    let reverse = args.get_kw_arg_opt_typed("reverse", &RuntimeType::bool(), exec_state)?;
 | 
			
		||||
    let tag = args.get_kw_arg_opt(NEW_TAG_KW)?;
 | 
			
		||||
    let new_sketch =
 | 
			
		||||
        inner_involute_circular(sketch, start_radius, end_radius, angle, reverse, tag, exec_state, args).await?;
 | 
			
		||||
@ -839,9 +839,10 @@ async fn inner_angled_line_to_y(
 | 
			
		||||
pub async fn angled_line_that_intersects(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
 | 
			
		||||
    let sketch =
 | 
			
		||||
        args.get_unlabeled_kw_arg_typed("sketch", &RuntimeType::Primitive(PrimitiveType::Sketch), exec_state)?;
 | 
			
		||||
    let angle: TyF64 = args.get_kw_arg("angle")?;
 | 
			
		||||
    let intersect_tag: TagIdentifier = args.get_kw_arg("intersectTag")?;
 | 
			
		||||
    let offset: Option<TyF64> = args.get_kw_arg_opt("offset")?;
 | 
			
		||||
    let angle: TyF64 = args.get_kw_arg_typed("angle", &RuntimeType::angle(), exec_state)?;
 | 
			
		||||
    let intersect_tag: TagIdentifier =
 | 
			
		||||
        args.get_kw_arg_typed("intersectTag", &RuntimeType::tag_identifier(), exec_state)?;
 | 
			
		||||
    let offset = args.get_kw_arg_opt_typed("offset", &RuntimeType::length(), exec_state)?;
 | 
			
		||||
    let tag: Option<TagNode> = args.get_kw_arg_opt("tag")?;
 | 
			
		||||
    let new_sketch =
 | 
			
		||||
        inner_angled_line_that_intersects(sketch, angle, intersect_tag, offset, tag, exec_state, args).await?;
 | 
			
		||||
@ -963,7 +964,7 @@ pub async fn start_sketch_on(exec_state: &mut ExecState, args: Args) -> Result<K
 | 
			
		||||
        &RuntimeType::Union(vec![RuntimeType::solid(), RuntimeType::plane()]),
 | 
			
		||||
        exec_state,
 | 
			
		||||
    )?;
 | 
			
		||||
    let face = args.get_kw_arg_opt("face")?;
 | 
			
		||||
    let face = args.get_kw_arg_opt_typed("face", &RuntimeType::tag(), exec_state)?;
 | 
			
		||||
 | 
			
		||||
    match inner_start_sketch_on(data, face, exec_state, &args).await? {
 | 
			
		||||
        SketchSurface::Plane(value) => Ok(KclValue::Plane { value }),
 | 
			
		||||
@ -1266,8 +1267,11 @@ async fn make_sketch_plane_from_orientation(
 | 
			
		||||
 | 
			
		||||
/// Start a new profile at a given point.
 | 
			
		||||
pub async fn start_profile(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
 | 
			
		||||
    // let (start, sketch_surface, tag) = args.get_data_and_sketch_surface()?;
 | 
			
		||||
    let sketch_surface = args.get_unlabeled_kw_arg("startProfileOn")?;
 | 
			
		||||
    let sketch_surface = args.get_unlabeled_kw_arg_typed(
 | 
			
		||||
        "startProfileOn",
 | 
			
		||||
        &RuntimeType::Union(vec![RuntimeType::plane(), RuntimeType::face()]),
 | 
			
		||||
        exec_state,
 | 
			
		||||
    )?;
 | 
			
		||||
    let start: [TyF64; 2] = args.get_kw_arg_typed("at", &RuntimeType::point2d(), exec_state)?;
 | 
			
		||||
    let tag = args.get_kw_arg_opt(NEW_TAG_KW)?;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -35,7 +35,7 @@ pub async fn sweep(exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
 | 
			
		||||
        &RuntimeType::Union(vec![RuntimeType::sketch(), RuntimeType::helix()]),
 | 
			
		||||
        exec_state,
 | 
			
		||||
    )?;
 | 
			
		||||
    let sectional = args.get_kw_arg_opt("sectional")?;
 | 
			
		||||
    let sectional = args.get_kw_arg_opt_typed("sectional", &RuntimeType::bool(), exec_state)?;
 | 
			
		||||
    let tolerance: Option<TyF64> = args.get_kw_arg_opt_typed("tolerance", &RuntimeType::length(), exec_state)?;
 | 
			
		||||
    let relative_to: Option<String> = args.get_kw_arg_opt_typed("relativeTo", &RuntimeType::string(), exec_state)?;
 | 
			
		||||
    let tag_start = args.get_kw_arg_opt("tagStart")?;
 | 
			
		||||
 | 
			
		||||
@ -33,7 +33,7 @@ pub async fn scale(exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
 | 
			
		||||
    let scale_x: Option<TyF64> = args.get_kw_arg_opt_typed("x", &RuntimeType::count(), exec_state)?;
 | 
			
		||||
    let scale_y: Option<TyF64> = args.get_kw_arg_opt_typed("y", &RuntimeType::count(), exec_state)?;
 | 
			
		||||
    let scale_z: Option<TyF64> = args.get_kw_arg_opt_typed("z", &RuntimeType::count(), exec_state)?;
 | 
			
		||||
    let global = args.get_kw_arg_opt("global")?;
 | 
			
		||||
    let global = args.get_kw_arg_opt_typed("global", &RuntimeType::bool(), exec_state)?;
 | 
			
		||||
 | 
			
		||||
    // Ensure at least one scale value is provided.
 | 
			
		||||
    if scale_x.is_none() && scale_y.is_none() && scale_z.is_none() {
 | 
			
		||||
@ -115,7 +115,7 @@ pub async fn translate(exec_state: &mut ExecState, args: Args) -> Result<KclValu
 | 
			
		||||
    let translate_x: Option<TyF64> = args.get_kw_arg_opt_typed("x", &RuntimeType::length(), exec_state)?;
 | 
			
		||||
    let translate_y: Option<TyF64> = args.get_kw_arg_opt_typed("y", &RuntimeType::length(), exec_state)?;
 | 
			
		||||
    let translate_z: Option<TyF64> = args.get_kw_arg_opt_typed("z", &RuntimeType::length(), exec_state)?;
 | 
			
		||||
    let global = args.get_kw_arg_opt("global")?;
 | 
			
		||||
    let global = args.get_kw_arg_opt_typed("global", &RuntimeType::bool(), exec_state)?;
 | 
			
		||||
 | 
			
		||||
    // Ensure at least one translation value is provided.
 | 
			
		||||
    if translate_x.is_none() && translate_y.is_none() && translate_z.is_none() {
 | 
			
		||||
@ -198,7 +198,7 @@ pub async fn rotate(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
 | 
			
		||||
    )?;
 | 
			
		||||
    let axis = axis.map(|a| a.to_point3d());
 | 
			
		||||
    let angle: Option<TyF64> = args.get_kw_arg_opt_typed("angle", &RuntimeType::degrees(), exec_state)?;
 | 
			
		||||
    let global = args.get_kw_arg_opt("global")?;
 | 
			
		||||
    let global = args.get_kw_arg_opt_typed("global", &RuntimeType::bool(), exec_state)?;
 | 
			
		||||
 | 
			
		||||
    // Check if no rotation values are provided.
 | 
			
		||||
    if roll.is_none() && pitch.is_none() && yaw.is_none() && axis.is_none() && angle.is_none() {
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user