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:
Nick Cameron
2025-05-29 16:48:47 +12:00
committed by GitHub
parent c4d2e33a99
commit 87e3588ceb
18 changed files with 84 additions and 96 deletions

View File

@ -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>(

View File

@ -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);

View File

@ -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())
}

View File

@ -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)?;

View File

@ -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")?;

View File

@ -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.

View File

@ -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",

View File

@ -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")?;

View File

@ -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,

View File

@ -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) })

View File

@ -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)?;

View File

@ -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())))

View File

@ -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,

View File

@ -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)?;

View File

@ -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")?;

View File

@ -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() {