Show KCL backtraces (#7033)
* Add backtrace to errors * Add display of backtraces with hints * Change pane badge to only show count of errors * Fix property name to not collide with Error superclass * Increase min stack again * Add e2e test that checks that the diagnostics are created in CodeMirror * Remove unneeded code * Change to the new hotness
This commit is contained in:
@ -32,10 +32,10 @@ pub async fn appearance(exec_state: &mut ExecState, args: Args) -> Result<KclVal
|
||||
|
||||
// Make sure the color if set is valid.
|
||||
if !HEX_REGEX.is_match(&color) {
|
||||
return Err(KclError::Semantic(KclErrorDetails {
|
||||
message: format!("Invalid hex color (`{}`), try something like `#fff000`", color),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
return Err(KclError::Semantic(KclErrorDetails::new(
|
||||
format!("Invalid hex color (`{}`), try something like `#fff000`", color),
|
||||
vec![args.source_range],
|
||||
)));
|
||||
}
|
||||
|
||||
let result = inner_appearance(
|
||||
@ -282,10 +282,10 @@ async fn inner_appearance(
|
||||
for solid_id in solids.ids(&args.ctx).await? {
|
||||
// Set the material properties.
|
||||
let rgb = rgba_simple::RGB::<f32>::from_hex(&color).map_err(|err| {
|
||||
KclError::Semantic(KclErrorDetails {
|
||||
message: format!("Invalid hex color (`{color}`): {err}"),
|
||||
source_ranges: vec![args.source_range],
|
||||
})
|
||||
KclError::Semantic(KclErrorDetails::new(
|
||||
format!("Invalid hex color (`{color}`): {err}"),
|
||||
vec![args.source_range],
|
||||
))
|
||||
})?;
|
||||
|
||||
let color = Color {
|
||||
|
@ -122,14 +122,14 @@ impl Args {
|
||||
}
|
||||
|
||||
T::from_kcl_val(&arg.value).map(Some).ok_or_else(|| {
|
||||
KclError::Type(KclErrorDetails {
|
||||
source_ranges: vec![self.source_range],
|
||||
message: format!(
|
||||
KclError::Type(KclErrorDetails::new(
|
||||
format!(
|
||||
"The arg {label} was given, but it was the wrong type. It should be type {} but it was {}",
|
||||
tynm::type_name::<T>(),
|
||||
arg.value.human_friendly_type(),
|
||||
),
|
||||
})
|
||||
vec![self.source_range],
|
||||
))
|
||||
})
|
||||
}
|
||||
|
||||
@ -155,10 +155,10 @@ impl Args {
|
||||
T: FromKclValue<'a>,
|
||||
{
|
||||
self.get_kw_arg_opt(label)?.ok_or_else(|| {
|
||||
KclError::Semantic(KclErrorDetails {
|
||||
source_ranges: vec![self.source_range],
|
||||
message: format!("This function requires a keyword argument '{label}'"),
|
||||
})
|
||||
KclError::Semantic(KclErrorDetails::new(
|
||||
format!("This function requires a keyword argument '{label}'"),
|
||||
vec![self.source_range],
|
||||
))
|
||||
})
|
||||
}
|
||||
|
||||
@ -172,10 +172,10 @@ impl Args {
|
||||
T: for<'a> FromKclValue<'a>,
|
||||
{
|
||||
let Some(arg) = self.kw_args.labeled.get(label) else {
|
||||
return Err(KclError::Semantic(KclErrorDetails {
|
||||
source_ranges: vec![self.source_range],
|
||||
message: format!("This function requires a keyword argument '{label}'"),
|
||||
}));
|
||||
return Err(KclError::Semantic(KclErrorDetails::new(
|
||||
format!("This function requires a keyword argument '{label}'"),
|
||||
vec![self.source_range],
|
||||
)));
|
||||
};
|
||||
|
||||
let arg = arg.value.coerce(ty, exec_state).map_err(|_| {
|
||||
@ -206,10 +206,7 @@ impl Args {
|
||||
if message.contains("one or more Solids or imported geometry but it's actually of type Sketch") {
|
||||
message = format!("{message}. {ERROR_STRING_SKETCH_TO_SOLID_HELPER}");
|
||||
}
|
||||
KclError::Semantic(KclErrorDetails {
|
||||
source_ranges: arg.source_ranges(),
|
||||
message,
|
||||
})
|
||||
KclError::Semantic(KclErrorDetails::new(message, arg.source_ranges()))
|
||||
})?;
|
||||
|
||||
// TODO unnecessary cloning
|
||||
@ -223,21 +220,21 @@ impl Args {
|
||||
T: FromKclValue<'a>,
|
||||
{
|
||||
let Some(arg) = self.kw_args.labeled.get(label) else {
|
||||
let err = KclError::Semantic(KclErrorDetails {
|
||||
source_ranges: vec![self.source_range],
|
||||
message: format!("This function requires a keyword argument '{label}'"),
|
||||
});
|
||||
let err = KclError::Semantic(KclErrorDetails::new(
|
||||
format!("This function requires a keyword argument '{label}'"),
|
||||
vec![self.source_range],
|
||||
));
|
||||
return Err(err);
|
||||
};
|
||||
let Some(array) = arg.value.as_array() else {
|
||||
let err = KclError::Semantic(KclErrorDetails {
|
||||
source_ranges: vec![arg.source_range],
|
||||
message: format!(
|
||||
let err = KclError::Semantic(KclErrorDetails::new(
|
||||
format!(
|
||||
"Expected an array of {} but found {}",
|
||||
tynm::type_name::<T>(),
|
||||
arg.value.human_friendly_type()
|
||||
),
|
||||
});
|
||||
vec![arg.source_range],
|
||||
));
|
||||
return Err(err);
|
||||
};
|
||||
array
|
||||
@ -245,14 +242,14 @@ impl Args {
|
||||
.map(|item| {
|
||||
let source = SourceRange::from(item);
|
||||
let val = FromKclValue::from_kcl_val(item).ok_or_else(|| {
|
||||
KclError::Semantic(KclErrorDetails {
|
||||
source_ranges: arg.source_ranges(),
|
||||
message: format!(
|
||||
KclError::Semantic(KclErrorDetails::new(
|
||||
format!(
|
||||
"Expected a {} but found {}",
|
||||
tynm::type_name::<T>(),
|
||||
arg.value.human_friendly_type()
|
||||
),
|
||||
})
|
||||
arg.source_ranges(),
|
||||
))
|
||||
})?;
|
||||
Ok((val, source))
|
||||
})
|
||||
@ -267,19 +264,19 @@ impl Args {
|
||||
{
|
||||
let arg = self
|
||||
.unlabeled_kw_arg_unconverted()
|
||||
.ok_or(KclError::Semantic(KclErrorDetails {
|
||||
source_ranges: vec![self.source_range],
|
||||
message: format!("This function requires a value for the special unlabeled first parameter, '{label}'"),
|
||||
}))?;
|
||||
.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 {
|
||||
source_ranges: arg.source_ranges(),
|
||||
KclError::Semantic(KclErrorDetails::new(
|
||||
message,
|
||||
})
|
||||
arg.source_ranges(),
|
||||
))
|
||||
})
|
||||
}
|
||||
|
||||
@ -296,10 +293,10 @@ impl Args {
|
||||
{
|
||||
let arg = self
|
||||
.unlabeled_kw_arg_unconverted()
|
||||
.ok_or(KclError::Semantic(KclErrorDetails {
|
||||
source_ranges: vec![self.source_range],
|
||||
message: format!("This function requires a value for the special unlabeled first parameter, '{label}'"),
|
||||
}))?;
|
||||
.ok_or(KclError::Semantic(KclErrorDetails::new(
|
||||
format!("This function requires a value for the special unlabeled first parameter, '{label}'"),
|
||||
vec![self.source_range],
|
||||
)))?;
|
||||
|
||||
let arg = arg.value.coerce(ty, exec_state).map_err(|_| {
|
||||
let actual_type = arg.value.principal_type();
|
||||
@ -330,17 +327,14 @@ impl Args {
|
||||
if message.contains("one or more Solids or imported geometry but it's actually of type Sketch") {
|
||||
message = format!("{message}. {ERROR_STRING_SKETCH_TO_SOLID_HELPER}");
|
||||
}
|
||||
KclError::Semantic(KclErrorDetails {
|
||||
source_ranges: arg.source_ranges(),
|
||||
message,
|
||||
})
|
||||
KclError::Semantic(KclErrorDetails::new(message, arg.source_ranges()))
|
||||
})?;
|
||||
|
||||
T::from_kcl_val(&arg).ok_or_else(|| {
|
||||
KclError::Internal(KclErrorDetails {
|
||||
source_ranges: vec![self.source_range],
|
||||
message: "Mismatch between type coercion and value extraction (this isn't your fault).\nTo assist in bug-reporting, expected type: {ty:?}; actual value: {arg:?}".to_owned(),
|
||||
})
|
||||
KclError::Internal(KclErrorDetails::new(
|
||||
"Mismatch between type coercion and value extraction (this isn't your fault).\nTo assist in bug-reporting, expected type: {ty:?}; actual value: {arg:?}".to_owned(),
|
||||
vec![self.source_range],
|
||||
))
|
||||
})
|
||||
}
|
||||
|
||||
@ -383,17 +377,17 @@ impl Args {
|
||||
exec_state.stack().get_from_call_stack(&tag.value, self.source_range)?
|
||||
{
|
||||
let info = t.get_info(epoch).ok_or_else(|| {
|
||||
KclError::Type(KclErrorDetails {
|
||||
message: format!("Tag `{}` does not have engine info", tag.value),
|
||||
source_ranges: vec![self.source_range],
|
||||
})
|
||||
KclError::Type(KclErrorDetails::new(
|
||||
format!("Tag `{}` does not have engine info", tag.value),
|
||||
vec![self.source_range],
|
||||
))
|
||||
})?;
|
||||
Ok(info)
|
||||
} else {
|
||||
Err(KclError::Type(KclErrorDetails {
|
||||
message: format!("Tag `{}` does not exist", tag.value),
|
||||
source_ranges: vec![self.source_range],
|
||||
}))
|
||||
Err(KclError::Type(KclErrorDetails::new(
|
||||
format!("Tag `{}` does not exist", tag.value),
|
||||
vec![self.source_range],
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
||||
@ -522,19 +516,19 @@ impl Args {
|
||||
must_be_planar: bool,
|
||||
) -> Result<uuid::Uuid, KclError> {
|
||||
if tag.value.is_empty() {
|
||||
return Err(KclError::Type(KclErrorDetails {
|
||||
message: "Expected a non-empty tag for the face".to_string(),
|
||||
source_ranges: vec![self.source_range],
|
||||
}));
|
||||
return Err(KclError::Type(KclErrorDetails::new(
|
||||
"Expected a non-empty tag for the face".to_string(),
|
||||
vec![self.source_range],
|
||||
)));
|
||||
}
|
||||
|
||||
let engine_info = self.get_tag_engine_info_check_surface(exec_state, tag)?;
|
||||
|
||||
let surface = engine_info.surface.as_ref().ok_or_else(|| {
|
||||
KclError::Type(KclErrorDetails {
|
||||
message: format!("Tag `{}` does not have a surface", tag.value),
|
||||
source_ranges: vec![self.source_range],
|
||||
})
|
||||
KclError::Type(KclErrorDetails::new(
|
||||
format!("Tag `{}` does not have a surface", tag.value),
|
||||
vec![self.source_range],
|
||||
))
|
||||
})?;
|
||||
|
||||
if let Some(face_from_surface) = match surface {
|
||||
@ -550,10 +544,10 @@ impl Args {
|
||||
}
|
||||
}
|
||||
// The must be planar check must be called before the arc check.
|
||||
ExtrudeSurface::ExtrudeArc(_) if must_be_planar => Some(Err(KclError::Type(KclErrorDetails {
|
||||
message: format!("Tag `{}` is a non-planar surface", tag.value),
|
||||
source_ranges: vec![self.source_range],
|
||||
}))),
|
||||
ExtrudeSurface::ExtrudeArc(_) if must_be_planar => Some(Err(KclError::Type(KclErrorDetails::new(
|
||||
format!("Tag `{}` is a non-planar surface", tag.value),
|
||||
vec![self.source_range],
|
||||
)))),
|
||||
ExtrudeSurface::ExtrudeArc(extrude_arc) => {
|
||||
if let Some(arc_tag) = &extrude_arc.tag {
|
||||
if arc_tag.name == tag.value {
|
||||
@ -577,10 +571,10 @@ impl Args {
|
||||
}
|
||||
}
|
||||
// The must be planar check must be called before the fillet check.
|
||||
ExtrudeSurface::Fillet(_) if must_be_planar => Some(Err(KclError::Type(KclErrorDetails {
|
||||
message: format!("Tag `{}` is a non-planar surface", tag.value),
|
||||
source_ranges: vec![self.source_range],
|
||||
}))),
|
||||
ExtrudeSurface::Fillet(_) if must_be_planar => Some(Err(KclError::Type(KclErrorDetails::new(
|
||||
format!("Tag `{}` is a non-planar surface", tag.value),
|
||||
vec![self.source_range],
|
||||
)))),
|
||||
ExtrudeSurface::Fillet(fillet) => {
|
||||
if let Some(fillet_tag) = &fillet.tag {
|
||||
if fillet_tag.name == tag.value {
|
||||
@ -597,10 +591,10 @@ impl Args {
|
||||
}
|
||||
|
||||
// If we still haven't found the face, return an error.
|
||||
Err(KclError::Type(KclErrorDetails {
|
||||
message: format!("Expected a face with the tag `{}`", tag.value),
|
||||
source_ranges: vec![self.source_range],
|
||||
}))
|
||||
Err(KclError::Type(KclErrorDetails::new(
|
||||
format!("Expected a face with the tag `{}`", tag.value),
|
||||
vec![self.source_range],
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
||||
@ -622,20 +616,20 @@ where
|
||||
{
|
||||
fn from_args(args: &'a Args, i: usize) -> Result<Self, KclError> {
|
||||
let Some(arg) = args.args.get(i) else {
|
||||
return Err(KclError::Semantic(KclErrorDetails {
|
||||
message: format!("Expected an argument at index {i}"),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
return Err(KclError::Semantic(KclErrorDetails::new(
|
||||
format!("Expected an argument at index {i}"),
|
||||
vec![args.source_range],
|
||||
)));
|
||||
};
|
||||
let Some(val) = T::from_kcl_val(&arg.value) else {
|
||||
return Err(KclError::Semantic(KclErrorDetails {
|
||||
message: format!(
|
||||
return Err(KclError::Semantic(KclErrorDetails::new(
|
||||
format!(
|
||||
"Argument at index {i} was supposed to be type {} but found {}",
|
||||
tynm::type_name::<T>(),
|
||||
arg.value.human_friendly_type(),
|
||||
),
|
||||
source_ranges: arg.source_ranges(),
|
||||
}));
|
||||
arg.source_ranges(),
|
||||
)));
|
||||
};
|
||||
Ok(val)
|
||||
}
|
||||
@ -651,14 +645,14 @@ where
|
||||
return Ok(None);
|
||||
}
|
||||
let Some(val) = T::from_kcl_val(&arg.value) else {
|
||||
return Err(KclError::Semantic(KclErrorDetails {
|
||||
message: format!(
|
||||
return Err(KclError::Semantic(KclErrorDetails::new(
|
||||
format!(
|
||||
"Argument at index {i} was supposed to be type Option<{}> but found {}",
|
||||
tynm::type_name::<T>(),
|
||||
arg.value.human_friendly_type()
|
||||
),
|
||||
source_ranges: arg.source_ranges(),
|
||||
}));
|
||||
arg.source_ranges(),
|
||||
)));
|
||||
};
|
||||
Ok(Some(val))
|
||||
}
|
||||
|
@ -58,10 +58,10 @@ async fn call_map_closure(
|
||||
let output = map_fn.call_kw(None, exec_state, ctxt, args, source_range).await?;
|
||||
let source_ranges = vec![source_range];
|
||||
let output = output.ok_or_else(|| {
|
||||
KclError::Semantic(KclErrorDetails {
|
||||
message: "Map function must return a value".to_string(),
|
||||
KclError::Semantic(KclErrorDetails::new(
|
||||
"Map function must return a value".to_owned(),
|
||||
source_ranges,
|
||||
})
|
||||
))
|
||||
})?;
|
||||
Ok(output)
|
||||
}
|
||||
@ -118,10 +118,10 @@ async fn call_reduce_closure(
|
||||
// Unpack the returned transform object.
|
||||
let source_ranges = vec![source_range];
|
||||
let out = transform_fn_return.ok_or_else(|| {
|
||||
KclError::Semantic(KclErrorDetails {
|
||||
message: "Reducer function must return a value".to_string(),
|
||||
source_ranges: source_ranges.clone(),
|
||||
})
|
||||
KclError::Semantic(KclErrorDetails::new(
|
||||
"Reducer function must return a value".to_string(),
|
||||
source_ranges.clone(),
|
||||
))
|
||||
})?;
|
||||
Ok(out)
|
||||
}
|
||||
@ -133,10 +133,10 @@ pub async fn push(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
|
||||
let KclValue::HomArray { value: values, ty } = array else {
|
||||
let meta = vec![args.source_range];
|
||||
let actual_type = array.human_friendly_type();
|
||||
return Err(KclError::Semantic(KclErrorDetails {
|
||||
source_ranges: meta,
|
||||
message: format!("You can't push to a value of type {actual_type}, only an array"),
|
||||
}));
|
||||
return Err(KclError::Semantic(KclErrorDetails::new(
|
||||
format!("You can't push to a value of type {actual_type}, only an array"),
|
||||
meta,
|
||||
)));
|
||||
};
|
||||
let ty = if item.has_type(&ty) {
|
||||
ty
|
||||
@ -161,10 +161,10 @@ pub async fn pop(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, Kc
|
||||
let KclValue::HomArray { value: values, ty } = array else {
|
||||
let meta = vec![args.source_range];
|
||||
let actual_type = array.human_friendly_type();
|
||||
return Err(KclError::Semantic(KclErrorDetails {
|
||||
source_ranges: meta,
|
||||
message: format!("You can't pop from a value of type {actual_type}, only an array"),
|
||||
}));
|
||||
return Err(KclError::Semantic(KclErrorDetails::new(
|
||||
format!("You can't pop from a value of type {actual_type}, only an array"),
|
||||
meta,
|
||||
)));
|
||||
};
|
||||
|
||||
let new_array = inner_pop(values, &args)?;
|
||||
@ -173,10 +173,10 @@ pub async fn pop(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, Kc
|
||||
|
||||
fn inner_pop(array: Vec<KclValue>, args: &Args) -> Result<Vec<KclValue>, KclError> {
|
||||
if array.is_empty() {
|
||||
return Err(KclError::Semantic(KclErrorDetails {
|
||||
message: "Cannot pop from an empty array".to_string(),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
return Err(KclError::Semantic(KclErrorDetails::new(
|
||||
"Cannot pop from an empty array".to_string(),
|
||||
vec![args.source_range],
|
||||
)));
|
||||
}
|
||||
|
||||
// Create a new array with all elements except the last one
|
||||
|
@ -12,10 +12,10 @@ use crate::{
|
||||
|
||||
async fn _assert(value: bool, message: &str, args: &Args) -> Result<(), KclError> {
|
||||
if !value {
|
||||
return Err(KclError::Type(KclErrorDetails {
|
||||
message: format!("assert failed: {}", message),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
return Err(KclError::Type(KclErrorDetails::new(
|
||||
format!("assert failed: {}", message),
|
||||
vec![args.source_range],
|
||||
)));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@ -111,19 +111,18 @@ async fn inner_assert(
|
||||
.iter()
|
||||
.all(|cond| cond.is_none());
|
||||
if no_condition_given {
|
||||
return Err(KclError::Type(KclErrorDetails {
|
||||
message: "You must provide at least one condition in this assert (for example, isEqualTo)".to_owned(),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
return Err(KclError::Type(KclErrorDetails::new(
|
||||
"You must provide at least one condition in this assert (for example, isEqualTo)".to_owned(),
|
||||
vec![args.source_range],
|
||||
)));
|
||||
}
|
||||
|
||||
if tolerance.is_some() && is_equal_to.is_none() {
|
||||
return Err(KclError::Type(KclErrorDetails {
|
||||
message:
|
||||
"The `tolerance` arg is only used with `isEqualTo`. Either remove `tolerance` or add an `isEqualTo` arg."
|
||||
.to_owned(),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
return Err(KclError::Type(KclErrorDetails::new(
|
||||
"The `tolerance` arg is only used with `isEqualTo`. Either remove `tolerance` or add an `isEqualTo` arg."
|
||||
.to_owned(),
|
||||
vec![args.source_range],
|
||||
)));
|
||||
}
|
||||
|
||||
let suffix = if let Some(err_string) = error {
|
||||
|
@ -41,10 +41,10 @@ async fn inner_chamfer(
|
||||
// If you try and tag multiple edges with a tagged chamfer, we want to return an
|
||||
// error to the user that they can only tag one edge at a time.
|
||||
if tag.is_some() && tags.len() > 1 {
|
||||
return Err(KclError::Type(KclErrorDetails {
|
||||
message: "You can only tag one edge at a time with a tagged chamfer. Either delete the tag for the chamfer fn if you don't need it OR separate into individual chamfer functions for each tag.".to_string(),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
return Err(KclError::Type(KclErrorDetails::new(
|
||||
"You can only tag one edge at a time with a tagged chamfer. Either delete the tag for the chamfer fn if you don't need it OR separate into individual chamfer functions for each tag.".to_string(),
|
||||
vec![args.source_range],
|
||||
)));
|
||||
}
|
||||
|
||||
let mut solid = solid.clone();
|
||||
|
@ -84,10 +84,10 @@ async fn inner_clone(
|
||||
fix_tags_and_references(&mut new_geometry, old_id, exec_state, &args)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
KclError::Internal(KclErrorDetails {
|
||||
message: format!("failed to fix tags and references: {:?}", e),
|
||||
source_ranges: vec![args.source_range],
|
||||
})
|
||||
KclError::Internal(KclErrorDetails::new(
|
||||
format!("failed to fix tags and references: {:?}", e),
|
||||
vec![args.source_range],
|
||||
))
|
||||
})?;
|
||||
|
||||
Ok(new_geometry)
|
||||
|
@ -24,10 +24,10 @@ pub async fn union(exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
|
||||
let tolerance: Option<TyF64> = args.get_kw_arg_opt_typed("tolerance", &RuntimeType::length(), exec_state)?;
|
||||
|
||||
if solids.len() < 2 {
|
||||
return Err(KclError::UndefinedValue(KclErrorDetails {
|
||||
message: "At least two solids are required for a union operation.".to_string(),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
return Err(KclError::UndefinedValue(KclErrorDetails::new(
|
||||
"At least two solids are required for a union operation.".to_string(),
|
||||
vec![args.source_range],
|
||||
)));
|
||||
}
|
||||
|
||||
let solids = inner_union(solids, tolerance, exec_state, args).await?;
|
||||
@ -147,10 +147,10 @@ pub(crate) async fn inner_union(
|
||||
modeling_response: OkModelingCmdResponse::BooleanUnion(BooleanUnion { extra_solid_ids }),
|
||||
} = result
|
||||
else {
|
||||
return Err(KclError::Internal(KclErrorDetails {
|
||||
message: "Failed to get the result of the union operation.".to_string(),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
return Err(KclError::Internal(KclErrorDetails::new(
|
||||
"Failed to get the result of the union operation.".to_string(),
|
||||
vec![args.source_range],
|
||||
)));
|
||||
};
|
||||
|
||||
// If we have more solids, set those as well.
|
||||
@ -169,10 +169,10 @@ pub async fn intersect(exec_state: &mut ExecState, args: Args) -> Result<KclValu
|
||||
let tolerance: Option<TyF64> = args.get_kw_arg_opt_typed("tolerance", &RuntimeType::length(), exec_state)?;
|
||||
|
||||
if solids.len() < 2 {
|
||||
return Err(KclError::UndefinedValue(KclErrorDetails {
|
||||
message: "At least two solids are required for an intersect operation.".to_string(),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
return Err(KclError::UndefinedValue(KclErrorDetails::new(
|
||||
"At least two solids are required for an intersect operation.".to_string(),
|
||||
vec![args.source_range],
|
||||
)));
|
||||
}
|
||||
|
||||
let solids = inner_intersect(solids, tolerance, exec_state, args).await?;
|
||||
@ -273,10 +273,10 @@ pub(crate) async fn inner_intersect(
|
||||
modeling_response: OkModelingCmdResponse::BooleanIntersection(BooleanIntersection { extra_solid_ids }),
|
||||
} = result
|
||||
else {
|
||||
return Err(KclError::Internal(KclErrorDetails {
|
||||
message: "Failed to get the result of the intersection operation.".to_string(),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
return Err(KclError::Internal(KclErrorDetails::new(
|
||||
"Failed to get the result of the intersection operation.".to_string(),
|
||||
vec![args.source_range],
|
||||
)));
|
||||
};
|
||||
|
||||
// If we have more solids, set those as well.
|
||||
@ -397,10 +397,10 @@ pub(crate) async fn inner_subtract(
|
||||
modeling_response: OkModelingCmdResponse::BooleanSubtract(BooleanSubtract { extra_solid_ids }),
|
||||
} = result
|
||||
else {
|
||||
return Err(KclError::Internal(KclErrorDetails {
|
||||
message: "Failed to get the result of the subtract operation.".to_string(),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
return Err(KclError::Internal(KclErrorDetails::new(
|
||||
"Failed to get the result of the subtract operation.".to_string(),
|
||||
vec![args.source_range],
|
||||
)));
|
||||
};
|
||||
|
||||
// If we have more solids, set those as well.
|
||||
|
@ -87,10 +87,10 @@ async fn inner_get_opposite_edge(
|
||||
modeling_response: OkModelingCmdResponse::Solid3dGetOppositeEdge(opposite_edge),
|
||||
} = &resp
|
||||
else {
|
||||
return Err(KclError::Engine(KclErrorDetails {
|
||||
message: format!("mcmd::Solid3dGetOppositeEdge response was not as expected: {:?}", resp),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
return Err(KclError::Engine(KclErrorDetails::new(
|
||||
format!("mcmd::Solid3dGetOppositeEdge response was not as expected: {:?}", resp),
|
||||
vec![args.source_range],
|
||||
)));
|
||||
};
|
||||
|
||||
Ok(opposite_edge.edge)
|
||||
@ -172,20 +172,20 @@ async fn inner_get_next_adjacent_edge(
|
||||
modeling_response: OkModelingCmdResponse::Solid3dGetNextAdjacentEdge(adjacent_edge),
|
||||
} = &resp
|
||||
else {
|
||||
return Err(KclError::Engine(KclErrorDetails {
|
||||
message: format!(
|
||||
return Err(KclError::Engine(KclErrorDetails::new(
|
||||
format!(
|
||||
"mcmd::Solid3dGetNextAdjacentEdge response was not as expected: {:?}",
|
||||
resp
|
||||
),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
vec![args.source_range],
|
||||
)));
|
||||
};
|
||||
|
||||
adjacent_edge.edge.ok_or_else(|| {
|
||||
KclError::Type(KclErrorDetails {
|
||||
message: format!("No edge found next adjacent to tag: `{}`", edge.value),
|
||||
source_ranges: vec![args.source_range],
|
||||
})
|
||||
KclError::Type(KclErrorDetails::new(
|
||||
format!("No edge found next adjacent to tag: `{}`", edge.value),
|
||||
vec![args.source_range],
|
||||
))
|
||||
})
|
||||
}
|
||||
|
||||
@ -264,20 +264,20 @@ async fn inner_get_previous_adjacent_edge(
|
||||
modeling_response: OkModelingCmdResponse::Solid3dGetPrevAdjacentEdge(adjacent_edge),
|
||||
} = &resp
|
||||
else {
|
||||
return Err(KclError::Engine(KclErrorDetails {
|
||||
message: format!(
|
||||
return Err(KclError::Engine(KclErrorDetails::new(
|
||||
format!(
|
||||
"mcmd::Solid3dGetPrevAdjacentEdge response was not as expected: {:?}",
|
||||
resp
|
||||
),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
vec![args.source_range],
|
||||
)));
|
||||
};
|
||||
|
||||
adjacent_edge.edge.ok_or_else(|| {
|
||||
KclError::Type(KclErrorDetails {
|
||||
message: format!("No edge found previous adjacent to tag: `{}`", edge.value),
|
||||
source_ranges: vec![args.source_range],
|
||||
})
|
||||
KclError::Type(KclErrorDetails::new(
|
||||
format!("No edge found previous adjacent to tag: `{}`", edge.value),
|
||||
vec![args.source_range],
|
||||
))
|
||||
})
|
||||
}
|
||||
|
||||
@ -336,10 +336,10 @@ async fn inner_get_common_edge(
|
||||
}
|
||||
|
||||
if faces.len() != 2 {
|
||||
return Err(KclError::Type(KclErrorDetails {
|
||||
message: "getCommonEdge requires exactly two tags for faces".to_string(),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
return Err(KclError::Type(KclErrorDetails::new(
|
||||
"getCommonEdge requires exactly two tags for faces".to_string(),
|
||||
vec![args.source_range],
|
||||
)));
|
||||
}
|
||||
let first_face_id = args.get_adjacent_face_to_tag(exec_state, &faces[0], false).await?;
|
||||
let second_face_id = args.get_adjacent_face_to_tag(exec_state, &faces[1], false).await?;
|
||||
@ -348,10 +348,10 @@ async fn inner_get_common_edge(
|
||||
let second_tagged_path = args.get_tag_engine_info(exec_state, &faces[1])?;
|
||||
|
||||
if first_tagged_path.sketch != second_tagged_path.sketch {
|
||||
return Err(KclError::Type(KclErrorDetails {
|
||||
message: "getCommonEdge requires the faces to be in the same original sketch".to_string(),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
return Err(KclError::Type(KclErrorDetails::new(
|
||||
"getCommonEdge requires the faces to be in the same original sketch".to_string(),
|
||||
vec![args.source_range],
|
||||
)));
|
||||
}
|
||||
|
||||
// Flush the batch for our fillets/chamfers if there are any.
|
||||
@ -377,19 +377,19 @@ async fn inner_get_common_edge(
|
||||
modeling_response: OkModelingCmdResponse::Solid3dGetCommonEdge(common_edge),
|
||||
} = &resp
|
||||
else {
|
||||
return Err(KclError::Engine(KclErrorDetails {
|
||||
message: format!("mcmd::Solid3dGetCommonEdge response was not as expected: {:?}", resp),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
return Err(KclError::Engine(KclErrorDetails::new(
|
||||
format!("mcmd::Solid3dGetCommonEdge response was not as expected: {:?}", resp),
|
||||
vec![args.source_range],
|
||||
)));
|
||||
};
|
||||
|
||||
common_edge.edge.ok_or_else(|| {
|
||||
KclError::Type(KclErrorDetails {
|
||||
message: format!(
|
||||
KclError::Type(KclErrorDetails::new(
|
||||
format!(
|
||||
"No common edge was found between `{}` and `{}`",
|
||||
faces[0].value, faces[1].value
|
||||
),
|
||||
source_ranges: vec![args.source_range],
|
||||
})
|
||||
vec![args.source_range],
|
||||
))
|
||||
})
|
||||
}
|
||||
|
@ -175,11 +175,11 @@ async fn inner_extrude(
|
||||
let mut solids = Vec::new();
|
||||
|
||||
if symmetric.unwrap_or(false) && bidirectional_length.is_some() {
|
||||
return Err(KclError::Semantic(KclErrorDetails {
|
||||
source_ranges: vec![args.source_range],
|
||||
message: "You cannot give both `symmetric` and `bidirectional` params, you have to choose one or the other"
|
||||
return Err(KclError::Semantic(KclErrorDetails::new(
|
||||
"You cannot give both `symmetric` and `bidirectional` params, you have to choose one or the other"
|
||||
.to_owned(),
|
||||
}));
|
||||
vec![args.source_range],
|
||||
)));
|
||||
}
|
||||
|
||||
let bidirection = bidirectional_length.map(|l| LengthUnit(l.to_mm()));
|
||||
@ -262,10 +262,10 @@ pub(crate) async fn do_post_extrude<'a>(
|
||||
// The "get extrusion face info" API call requires *any* edge on the sketch being extruded.
|
||||
// So, let's just use the first one.
|
||||
let Some(any_edge_id) = sketch.paths.first().map(|edge| edge.get_base().geo_meta.id) else {
|
||||
return Err(KclError::Type(KclErrorDetails {
|
||||
message: "Expected a non-empty sketch".to_string(),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
return Err(KclError::Type(KclErrorDetails::new(
|
||||
"Expected a non-empty sketch".to_owned(),
|
||||
vec![args.source_range],
|
||||
)));
|
||||
};
|
||||
any_edge_id
|
||||
};
|
||||
@ -387,13 +387,13 @@ pub(crate) async fn do_post_extrude<'a>(
|
||||
// Add the tags for the start or end caps.
|
||||
if let Some(tag_start) = named_cap_tags.start {
|
||||
let Some(start_cap_id) = start_cap_id else {
|
||||
return Err(KclError::Type(KclErrorDetails {
|
||||
message: format!(
|
||||
return Err(KclError::Type(KclErrorDetails::new(
|
||||
format!(
|
||||
"Expected a start cap ID for tag `{}` for extrusion of sketch {:?}",
|
||||
tag_start.name, sketch.id
|
||||
),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
vec![args.source_range],
|
||||
)));
|
||||
};
|
||||
|
||||
new_value.push(ExtrudeSurface::ExtrudePlane(crate::execution::ExtrudePlane {
|
||||
@ -407,13 +407,13 @@ pub(crate) async fn do_post_extrude<'a>(
|
||||
}
|
||||
if let Some(tag_end) = named_cap_tags.end {
|
||||
let Some(end_cap_id) = end_cap_id else {
|
||||
return Err(KclError::Type(KclErrorDetails {
|
||||
message: format!(
|
||||
return Err(KclError::Type(KclErrorDetails::new(
|
||||
format!(
|
||||
"Expected an end cap ID for tag `{}` for extrusion of sketch {:?}",
|
||||
tag_end.name, sketch.id
|
||||
),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
vec![args.source_range],
|
||||
)));
|
||||
};
|
||||
|
||||
new_value.push(ExtrudeSurface::ExtrudePlane(crate::execution::ExtrudePlane {
|
||||
|
@ -49,10 +49,11 @@ pub(super) fn validate_unique<T: Eq + std::hash::Hash>(tags: &[(T, SourceRange)]
|
||||
}
|
||||
}
|
||||
if !duplicate_tags_source.is_empty() {
|
||||
return Err(KclError::Type(KclErrorDetails {
|
||||
message: "The same edge ID is being referenced multiple times, which is not allowed. Please select a different edge".to_string(),
|
||||
source_ranges: duplicate_tags_source,
|
||||
}));
|
||||
return Err(KclError::Type(KclErrorDetails::new(
|
||||
"The same edge ID is being referenced multiple times, which is not allowed. Please select a different edge"
|
||||
.to_string(),
|
||||
duplicate_tags_source,
|
||||
)));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ use kittycad_modeling_cmds::{self as kcmc, shared::Point3d};
|
||||
|
||||
use super::args::TyF64;
|
||||
use crate::{
|
||||
errors::KclError,
|
||||
errors::{KclError, KclErrorDetails},
|
||||
execution::{
|
||||
types::{PrimitiveType, RuntimeType},
|
||||
ExecState, Helix as HelixValue, KclValue, Solid,
|
||||
@ -33,50 +33,50 @@ pub async fn helix(exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
|
||||
|
||||
// Make sure we have a radius if we don't have a cylinder.
|
||||
if radius.is_none() && cylinder.is_none() {
|
||||
return Err(KclError::Semantic(crate::errors::KclErrorDetails {
|
||||
message: "Radius is required when creating a helix without a cylinder.".to_string(),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
return Err(KclError::Semantic(crate::errors::KclErrorDetails::new(
|
||||
"Radius is required when creating a helix without a cylinder.".to_string(),
|
||||
vec![args.source_range],
|
||||
)));
|
||||
}
|
||||
|
||||
// Make sure we don't have a radius if we have a cylinder.
|
||||
if radius.is_some() && cylinder.is_some() {
|
||||
return Err(KclError::Semantic(crate::errors::KclErrorDetails {
|
||||
message: "Radius is not allowed when creating a helix with a cylinder.".to_string(),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
return Err(KclError::Semantic(crate::errors::KclErrorDetails::new(
|
||||
"Radius is not allowed when creating a helix with a cylinder.".to_string(),
|
||||
vec![args.source_range],
|
||||
)));
|
||||
}
|
||||
|
||||
// Make sure we have an axis if we don't have a cylinder.
|
||||
if axis.is_none() && cylinder.is_none() {
|
||||
return Err(KclError::Semantic(crate::errors::KclErrorDetails {
|
||||
message: "Axis is required when creating a helix without a cylinder.".to_string(),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
return Err(KclError::Semantic(crate::errors::KclErrorDetails::new(
|
||||
"Axis is required when creating a helix without a cylinder.".to_string(),
|
||||
vec![args.source_range],
|
||||
)));
|
||||
}
|
||||
|
||||
// Make sure we don't have an axis if we have a cylinder.
|
||||
if axis.is_some() && cylinder.is_some() {
|
||||
return Err(KclError::Semantic(crate::errors::KclErrorDetails {
|
||||
message: "Axis is not allowed when creating a helix with a cylinder.".to_string(),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
return Err(KclError::Semantic(crate::errors::KclErrorDetails::new(
|
||||
"Axis is not allowed when creating a helix with a cylinder.".to_string(),
|
||||
vec![args.source_range],
|
||||
)));
|
||||
}
|
||||
|
||||
// Make sure we have a radius if we have an axis.
|
||||
if radius.is_none() && axis.is_some() {
|
||||
return Err(KclError::Semantic(crate::errors::KclErrorDetails {
|
||||
message: "Radius is required when creating a helix around an axis.".to_string(),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
return Err(KclError::Semantic(crate::errors::KclErrorDetails::new(
|
||||
"Radius is required when creating a helix around an axis.".to_string(),
|
||||
vec![args.source_range],
|
||||
)));
|
||||
}
|
||||
|
||||
// Make sure we have an axis if we have a radius.
|
||||
if axis.is_none() && radius.is_some() {
|
||||
return Err(KclError::Semantic(crate::errors::KclErrorDetails {
|
||||
message: "Axis is required when creating a helix around an axis.".to_string(),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
return Err(KclError::Semantic(crate::errors::KclErrorDetails::new(
|
||||
"Axis is required when creating a helix around an axis.".to_string(),
|
||||
vec![args.source_range],
|
||||
)));
|
||||
}
|
||||
|
||||
let value = inner_helix(
|
||||
@ -140,10 +140,10 @@ async fn inner_helix(
|
||||
Axis3dOrEdgeReference::Axis { direction, origin } => {
|
||||
// Make sure they gave us a length.
|
||||
let Some(length) = length else {
|
||||
return Err(KclError::Semantic(crate::errors::KclErrorDetails {
|
||||
message: "Length is required when creating a helix around an axis.".to_string(),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
return Err(KclError::Semantic(KclErrorDetails::new(
|
||||
"Length is required when creating a helix around an axis.".to_owned(),
|
||||
vec![args.source_range],
|
||||
)));
|
||||
};
|
||||
|
||||
args.batch_modeling_cmd(
|
||||
|
@ -148,13 +148,13 @@ async fn inner_loft(
|
||||
) -> Result<Box<Solid>, KclError> {
|
||||
// Make sure we have at least two sketches.
|
||||
if sketches.len() < 2 {
|
||||
return Err(KclError::Semantic(KclErrorDetails {
|
||||
message: format!(
|
||||
return Err(KclError::Semantic(KclErrorDetails::new(
|
||||
format!(
|
||||
"Loft requires at least two sketches, but only {} were provided.",
|
||||
sketches.len()
|
||||
),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
vec![args.source_range],
|
||||
)));
|
||||
}
|
||||
|
||||
let id = exec_state.next_uuid();
|
||||
|
@ -56,13 +56,13 @@ pub async fn sqrt(exec_state: &mut ExecState, args: Args) -> Result<KclValue, Kc
|
||||
let input: TyF64 = args.get_unlabeled_kw_arg_typed("input", &RuntimeType::num_any(), exec_state)?;
|
||||
|
||||
if input.n < 0.0 {
|
||||
return Err(KclError::Semantic(KclErrorDetails {
|
||||
source_ranges: vec![args.source_range],
|
||||
message: format!(
|
||||
return Err(KclError::Semantic(KclErrorDetails::new(
|
||||
format!(
|
||||
"Attempt to take square root (`sqrt`) of a number less than zero ({})",
|
||||
input.n
|
||||
),
|
||||
}));
|
||||
vec![args.source_range],
|
||||
)));
|
||||
}
|
||||
|
||||
let result = input.n.sqrt();
|
||||
|
@ -101,10 +101,10 @@ async fn inner_mirror_2d(
|
||||
OkModelingCmdResponse::EntityGetAllChildUuids(EntityGetAllChildUuids { entity_ids: child_ids }),
|
||||
} = response
|
||||
else {
|
||||
return Err(KclError::Internal(KclErrorDetails {
|
||||
message: "Expected a successful response from EntityGetAllChildUuids".to_string(),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
return Err(KclError::Internal(KclErrorDetails::new(
|
||||
"Expected a successful response from EntityGetAllChildUuids".to_string(),
|
||||
vec![args.source_range],
|
||||
)));
|
||||
};
|
||||
|
||||
if child_ids.len() >= 2 {
|
||||
@ -112,10 +112,10 @@ async fn inner_mirror_2d(
|
||||
let child_id = child_ids[1];
|
||||
sketch.mirror = Some(child_id);
|
||||
} else {
|
||||
return Err(KclError::Type(KclErrorDetails {
|
||||
message: "Expected child uuids to be >= 2".to_string(),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
return Err(KclError::Type(KclErrorDetails::new(
|
||||
"Expected child uuids to be >= 2".to_string(),
|
||||
vec![args.source_range],
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -264,10 +264,10 @@ async fn inner_pattern_transform<'a>(
|
||||
// Build the vec of transforms, one for each repetition.
|
||||
let mut transform_vec = Vec::with_capacity(usize::try_from(instances).unwrap());
|
||||
if instances < 1 {
|
||||
return Err(KclError::Semantic(KclErrorDetails {
|
||||
source_ranges: vec![args.source_range],
|
||||
message: MUST_HAVE_ONE_INSTANCE.to_owned(),
|
||||
}));
|
||||
return Err(KclError::Semantic(KclErrorDetails::new(
|
||||
MUST_HAVE_ONE_INSTANCE.to_owned(),
|
||||
vec![args.source_range],
|
||||
)));
|
||||
}
|
||||
for i in 1..instances {
|
||||
let t = make_transform::<Solid>(i, transform, args.source_range, exec_state, &args.ctx).await?;
|
||||
@ -318,10 +318,10 @@ async fn inner_pattern_transform_2d<'a>(
|
||||
// Build the vec of transforms, one for each repetition.
|
||||
let mut transform_vec = Vec::with_capacity(usize::try_from(instances).unwrap());
|
||||
if instances < 1 {
|
||||
return Err(KclError::Semantic(KclErrorDetails {
|
||||
source_ranges: vec![args.source_range],
|
||||
message: MUST_HAVE_ONE_INSTANCE.to_owned(),
|
||||
}));
|
||||
return Err(KclError::Semantic(KclErrorDetails::new(
|
||||
MUST_HAVE_ONE_INSTANCE.to_owned(),
|
||||
vec![args.source_range],
|
||||
)));
|
||||
}
|
||||
for i in 1..instances {
|
||||
let t = make_transform::<Sketch>(i, transform, args.source_range, exec_state, &args.ctx).await?;
|
||||
@ -398,10 +398,10 @@ async fn send_pattern_transform<T: GeometryTrait>(
|
||||
}
|
||||
&mock_ids
|
||||
} else {
|
||||
return Err(KclError::Engine(KclErrorDetails {
|
||||
message: format!("EntityLinearPattern response was not as expected: {:?}", resp),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
return Err(KclError::Engine(KclErrorDetails::new(
|
||||
format!("EntityLinearPattern response was not as expected: {:?}", resp),
|
||||
vec![args.source_range],
|
||||
)));
|
||||
};
|
||||
|
||||
let mut geometries = vec![solid.clone()];
|
||||
@ -444,10 +444,10 @@ async fn make_transform<T: GeometryTrait>(
|
||||
// Unpack the returned transform object.
|
||||
let source_ranges = vec![source_range];
|
||||
let transform_fn_return = transform_fn_return.ok_or_else(|| {
|
||||
KclError::Semantic(KclErrorDetails {
|
||||
message: "Transform function must return a value".to_string(),
|
||||
source_ranges: source_ranges.clone(),
|
||||
})
|
||||
KclError::Semantic(KclErrorDetails::new(
|
||||
"Transform function must return a value".to_string(),
|
||||
source_ranges.clone(),
|
||||
))
|
||||
})?;
|
||||
let transforms = match transform_fn_return {
|
||||
KclValue::Object { value, meta: _ } => vec![value],
|
||||
@ -455,19 +455,19 @@ async fn make_transform<T: GeometryTrait>(
|
||||
let transforms: Vec<_> = value
|
||||
.into_iter()
|
||||
.map(|val| {
|
||||
val.into_object().ok_or(KclError::Semantic(KclErrorDetails {
|
||||
message: "Transform function must return a transform object".to_string(),
|
||||
source_ranges: source_ranges.clone(),
|
||||
}))
|
||||
val.into_object().ok_or(KclError::Semantic(KclErrorDetails::new(
|
||||
"Transform function must return a transform object".to_string(),
|
||||
source_ranges.clone(),
|
||||
)))
|
||||
})
|
||||
.collect::<Result<_, _>>()?;
|
||||
transforms
|
||||
}
|
||||
_ => {
|
||||
return Err(KclError::Semantic(KclErrorDetails {
|
||||
message: "Transform function must return a transform object".to_string(),
|
||||
source_ranges: source_ranges.clone(),
|
||||
}))
|
||||
return Err(KclError::Semantic(KclErrorDetails::new(
|
||||
"Transform function must return a transform object".to_string(),
|
||||
source_ranges.clone(),
|
||||
)))
|
||||
}
|
||||
};
|
||||
|
||||
@ -487,10 +487,10 @@ fn transform_from_obj_fields<T: GeometryTrait>(
|
||||
Some(KclValue::Bool { value: true, .. }) => true,
|
||||
Some(KclValue::Bool { value: false, .. }) => false,
|
||||
Some(_) => {
|
||||
return Err(KclError::Semantic(KclErrorDetails {
|
||||
message: "The 'replicate' key must be a bool".to_string(),
|
||||
source_ranges: source_ranges.clone(),
|
||||
}));
|
||||
return Err(KclError::Semantic(KclErrorDetails::new(
|
||||
"The 'replicate' key must be a bool".to_string(),
|
||||
source_ranges.clone(),
|
||||
)));
|
||||
}
|
||||
None => true,
|
||||
};
|
||||
@ -519,11 +519,10 @@ fn transform_from_obj_fields<T: GeometryTrait>(
|
||||
let mut rotation = Rotation::default();
|
||||
if let Some(rot) = transform.get("rotation") {
|
||||
let KclValue::Object { value: rot, meta: _ } = rot else {
|
||||
return Err(KclError::Semantic(KclErrorDetails {
|
||||
message: "The 'rotation' key must be an object (with optional fields 'angle', 'axis' and 'origin')"
|
||||
.to_string(),
|
||||
source_ranges: source_ranges.clone(),
|
||||
}));
|
||||
return Err(KclError::Semantic(KclErrorDetails::new(
|
||||
"The 'rotation' key must be an object (with optional fields 'angle', 'axis' and 'origin')".to_owned(),
|
||||
source_ranges.clone(),
|
||||
)));
|
||||
};
|
||||
if let Some(axis) = rot.get("axis") {
|
||||
rotation.axis = point_3d_to_mm(T::array_to_point3d(axis, source_ranges.clone(), exec_state)?).into();
|
||||
@ -534,10 +533,10 @@ fn transform_from_obj_fields<T: GeometryTrait>(
|
||||
rotation.angle = Angle::from_degrees(*number);
|
||||
}
|
||||
_ => {
|
||||
return Err(KclError::Semantic(KclErrorDetails {
|
||||
message: "The 'rotation.angle' key must be a number (of degrees)".to_string(),
|
||||
source_ranges: source_ranges.clone(),
|
||||
}));
|
||||
return Err(KclError::Semantic(KclErrorDetails::new(
|
||||
"The 'rotation.angle' key must be a number (of degrees)".to_owned(),
|
||||
source_ranges.clone(),
|
||||
)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -568,15 +567,15 @@ fn array_to_point3d(
|
||||
) -> Result<[TyF64; 3], KclError> {
|
||||
val.coerce(&RuntimeType::point3d(), exec_state)
|
||||
.map_err(|e| {
|
||||
KclError::Semantic(KclErrorDetails {
|
||||
message: format!(
|
||||
KclError::Semantic(KclErrorDetails::new(
|
||||
format!(
|
||||
"Expected an array of 3 numbers (i.e., a 3D point), found {}",
|
||||
e.found
|
||||
.map(|t| t.human_friendly_type())
|
||||
.unwrap_or_else(|| val.human_friendly_type().to_owned())
|
||||
),
|
||||
source_ranges,
|
||||
})
|
||||
))
|
||||
})
|
||||
.map(|val| val.as_point3d().unwrap())
|
||||
}
|
||||
@ -588,15 +587,15 @@ fn array_to_point2d(
|
||||
) -> Result<[TyF64; 2], KclError> {
|
||||
val.coerce(&RuntimeType::point2d(), exec_state)
|
||||
.map_err(|e| {
|
||||
KclError::Semantic(KclErrorDetails {
|
||||
message: format!(
|
||||
KclError::Semantic(KclErrorDetails::new(
|
||||
format!(
|
||||
"Expected an array of 2 numbers (i.e., a 2D point), found {}",
|
||||
e.found
|
||||
.map(|t| t.human_friendly_type())
|
||||
.unwrap_or_else(|| val.human_friendly_type().to_owned())
|
||||
),
|
||||
source_ranges,
|
||||
})
|
||||
))
|
||||
})
|
||||
.map(|val| val.as_point2d().unwrap())
|
||||
}
|
||||
@ -757,12 +756,11 @@ pub async fn pattern_linear_2d(exec_state: &mut ExecState, args: Args) -> Result
|
||||
|
||||
let axis = axis.to_point2d();
|
||||
if axis[0].n == 0.0 && axis[1].n == 0.0 {
|
||||
return Err(KclError::Semantic(KclErrorDetails {
|
||||
message:
|
||||
"The axis of the linear pattern cannot be the zero vector. Otherwise they will just duplicate in place."
|
||||
.to_string(),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
return Err(KclError::Semantic(KclErrorDetails::new(
|
||||
"The axis of the linear pattern cannot be the zero vector. Otherwise they will just duplicate in place."
|
||||
.to_owned(),
|
||||
vec![args.source_range],
|
||||
)));
|
||||
}
|
||||
|
||||
let sketches = inner_pattern_linear_2d(sketches, instances, distance, axis, use_original, exec_state, args).await?;
|
||||
@ -860,12 +858,11 @@ pub async fn pattern_linear_3d(exec_state: &mut ExecState, args: Args) -> Result
|
||||
|
||||
let axis = axis.to_point3d();
|
||||
if axis[0].n == 0.0 && axis[1].n == 0.0 && axis[2].n == 0.0 {
|
||||
return Err(KclError::Semantic(KclErrorDetails {
|
||||
message:
|
||||
"The axis of the linear pattern cannot be the zero vector. Otherwise they will just duplicate in place."
|
||||
.to_string(),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
return Err(KclError::Semantic(KclErrorDetails::new(
|
||||
"The axis of the linear pattern cannot be the zero vector. Otherwise they will just duplicate in place."
|
||||
.to_owned(),
|
||||
vec![args.source_range],
|
||||
)));
|
||||
}
|
||||
|
||||
let solids = inner_pattern_linear_3d(solids, instances, distance, axis, use_original, exec_state, args).await?;
|
||||
@ -1210,10 +1207,10 @@ async fn inner_pattern_circular_2d(
|
||||
.await?;
|
||||
|
||||
let Geometries::Sketches(new_sketches) = geometries else {
|
||||
return Err(KclError::Semantic(KclErrorDetails {
|
||||
message: "Expected a vec of sketches".to_string(),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
return Err(KclError::Semantic(KclErrorDetails::new(
|
||||
"Expected a vec of sketches".to_string(),
|
||||
vec![args.source_range],
|
||||
)));
|
||||
};
|
||||
|
||||
sketches.extend(new_sketches);
|
||||
@ -1333,10 +1330,10 @@ async fn inner_pattern_circular_3d(
|
||||
.await?;
|
||||
|
||||
let Geometries::Solids(new_solids) = geometries else {
|
||||
return Err(KclError::Semantic(KclErrorDetails {
|
||||
message: "Expected a vec of solids".to_string(),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
return Err(KclError::Semantic(KclErrorDetails::new(
|
||||
"Expected a vec of solids".to_string(),
|
||||
vec![args.source_range],
|
||||
)));
|
||||
};
|
||||
|
||||
solids.extend(new_solids);
|
||||
@ -1358,10 +1355,10 @@ async fn pattern_circular(
|
||||
return Ok(Geometries::from(geometry));
|
||||
}
|
||||
RepetitionsNeeded::Invalid => {
|
||||
return Err(KclError::Semantic(KclErrorDetails {
|
||||
source_ranges: vec![args.source_range],
|
||||
message: MUST_HAVE_ONE_INSTANCE.to_owned(),
|
||||
}));
|
||||
return Err(KclError::Semantic(KclErrorDetails::new(
|
||||
MUST_HAVE_ONE_INSTANCE.to_owned(),
|
||||
vec![args.source_range],
|
||||
)));
|
||||
}
|
||||
};
|
||||
|
||||
@ -1403,10 +1400,10 @@ async fn pattern_circular(
|
||||
}
|
||||
&mock_ids
|
||||
} else {
|
||||
return Err(KclError::Engine(KclErrorDetails {
|
||||
message: format!("EntityCircularPattern response was not as expected: {:?}", resp),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
return Err(KclError::Engine(KclErrorDetails::new(
|
||||
format!("EntityCircularPattern response was not as expected: {:?}", resp),
|
||||
vec![args.source_range],
|
||||
)));
|
||||
};
|
||||
|
||||
let geometries = match geometry {
|
||||
|
@ -75,10 +75,10 @@ async fn inner_revolve(
|
||||
// We don't use validate() here because we want to return a specific error message that is
|
||||
// nice and we use the other data in the docs, so we still need use the derive above for the json schema.
|
||||
if !(-360.0..=360.0).contains(&angle) || angle == 0.0 {
|
||||
return Err(KclError::Semantic(KclErrorDetails {
|
||||
message: format!("Expected angle to be between -360 and 360 and not 0, found `{}`", angle),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
return Err(KclError::Semantic(KclErrorDetails::new(
|
||||
format!("Expected angle to be between -360 and 360 and not 0, found `{}`", angle),
|
||||
vec![args.source_range],
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
||||
@ -87,35 +87,35 @@ async fn inner_revolve(
|
||||
// We don't use validate() here because we want to return a specific error message that is
|
||||
// nice and we use the other data in the docs, so we still need use the derive above for the json schema.
|
||||
if !(-360.0..=360.0).contains(&bidirectional_angle) || bidirectional_angle == 0.0 {
|
||||
return Err(KclError::Semantic(KclErrorDetails {
|
||||
message: format!(
|
||||
return Err(KclError::Semantic(KclErrorDetails::new(
|
||||
format!(
|
||||
"Expected bidirectional angle to be between -360 and 360 and not 0, found `{}`",
|
||||
bidirectional_angle
|
||||
),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
vec![args.source_range],
|
||||
)));
|
||||
}
|
||||
|
||||
if let Some(angle) = angle {
|
||||
let ang = angle.signum() * bidirectional_angle + angle;
|
||||
if !(-360.0..=360.0).contains(&ang) {
|
||||
return Err(KclError::Semantic(KclErrorDetails {
|
||||
message: format!(
|
||||
return Err(KclError::Semantic(KclErrorDetails::new(
|
||||
format!(
|
||||
"Combined angle and bidirectional must be between -360 and 360, found '{}'",
|
||||
ang
|
||||
),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
vec![args.source_range],
|
||||
)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if symmetric.unwrap_or(false) && bidirectional_angle.is_some() {
|
||||
return Err(KclError::Semantic(KclErrorDetails {
|
||||
source_ranges: vec![args.source_range],
|
||||
message: "You cannot give both `symmetric` and `bidirectional` params, you have to choose one or the other"
|
||||
return Err(KclError::Semantic(KclErrorDetails::new(
|
||||
"You cannot give both `symmetric` and `bidirectional` params, you have to choose one or the other"
|
||||
.to_owned(),
|
||||
}));
|
||||
vec![args.source_range],
|
||||
)));
|
||||
}
|
||||
|
||||
let angle = Angle::from_degrees(angle.unwrap_or(360.0));
|
||||
|
@ -59,10 +59,10 @@ pub async fn segment_end(exec_state: &mut ExecState, args: Args) -> Result<KclVa
|
||||
fn inner_segment_end(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<[TyF64; 2], KclError> {
|
||||
let line = args.get_tag_engine_info(exec_state, tag)?;
|
||||
let path = line.path.clone().ok_or_else(|| {
|
||||
KclError::Type(KclErrorDetails {
|
||||
message: format!("Expected a line segment with a path, found `{:?}`", line),
|
||||
source_ranges: vec![args.source_range],
|
||||
})
|
||||
KclError::Type(KclErrorDetails::new(
|
||||
format!("Expected a line segment with a path, found `{:?}`", line),
|
||||
vec![args.source_range],
|
||||
))
|
||||
})?;
|
||||
let (p, ty) = path.end_point_components();
|
||||
// Docs generation isn't smart enough to handle ([f64; 2], NumericType).
|
||||
@ -104,10 +104,10 @@ pub async fn segment_end_x(exec_state: &mut ExecState, args: Args) -> Result<Kcl
|
||||
fn inner_segment_end_x(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<TyF64, KclError> {
|
||||
let line = args.get_tag_engine_info(exec_state, tag)?;
|
||||
let path = line.path.clone().ok_or_else(|| {
|
||||
KclError::Type(KclErrorDetails {
|
||||
message: format!("Expected a line segment with a path, found `{:?}`", line),
|
||||
source_ranges: vec![args.source_range],
|
||||
})
|
||||
KclError::Type(KclErrorDetails::new(
|
||||
format!("Expected a line segment with a path, found `{:?}`", line),
|
||||
vec![args.source_range],
|
||||
))
|
||||
})?;
|
||||
|
||||
Ok(TyF64::new(path.get_base().to[0], path.get_base().units.into()))
|
||||
@ -147,10 +147,10 @@ pub async fn segment_end_y(exec_state: &mut ExecState, args: Args) -> Result<Kcl
|
||||
fn inner_segment_end_y(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<TyF64, KclError> {
|
||||
let line = args.get_tag_engine_info(exec_state, tag)?;
|
||||
let path = line.path.clone().ok_or_else(|| {
|
||||
KclError::Type(KclErrorDetails {
|
||||
message: format!("Expected a line segment with a path, found `{:?}`", line),
|
||||
source_ranges: vec![args.source_range],
|
||||
})
|
||||
KclError::Type(KclErrorDetails::new(
|
||||
format!("Expected a line segment with a path, found `{:?}`", line),
|
||||
vec![args.source_range],
|
||||
))
|
||||
})?;
|
||||
|
||||
Ok(path.get_to()[1].clone())
|
||||
@ -201,10 +201,10 @@ pub async fn segment_start(exec_state: &mut ExecState, args: Args) -> Result<Kcl
|
||||
fn inner_segment_start(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<[TyF64; 2], KclError> {
|
||||
let line = args.get_tag_engine_info(exec_state, tag)?;
|
||||
let path = line.path.clone().ok_or_else(|| {
|
||||
KclError::Type(KclErrorDetails {
|
||||
message: format!("Expected a line segment with a path, found `{:?}`", line),
|
||||
source_ranges: vec![args.source_range],
|
||||
})
|
||||
KclError::Type(KclErrorDetails::new(
|
||||
format!("Expected a line segment with a path, found `{:?}`", line),
|
||||
vec![args.source_range],
|
||||
))
|
||||
})?;
|
||||
let (p, ty) = path.start_point_components();
|
||||
// Docs generation isn't smart enough to handle ([f64; 2], NumericType).
|
||||
@ -246,10 +246,10 @@ pub async fn segment_start_x(exec_state: &mut ExecState, args: Args) -> Result<K
|
||||
fn inner_segment_start_x(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<TyF64, KclError> {
|
||||
let line = args.get_tag_engine_info(exec_state, tag)?;
|
||||
let path = line.path.clone().ok_or_else(|| {
|
||||
KclError::Type(KclErrorDetails {
|
||||
message: format!("Expected a line segment with a path, found `{:?}`", line),
|
||||
source_ranges: vec![args.source_range],
|
||||
})
|
||||
KclError::Type(KclErrorDetails::new(
|
||||
format!("Expected a line segment with a path, found `{:?}`", line),
|
||||
vec![args.source_range],
|
||||
))
|
||||
})?;
|
||||
|
||||
Ok(path.get_from()[0].clone())
|
||||
@ -289,10 +289,10 @@ pub async fn segment_start_y(exec_state: &mut ExecState, args: Args) -> Result<K
|
||||
fn inner_segment_start_y(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<TyF64, KclError> {
|
||||
let line = args.get_tag_engine_info(exec_state, tag)?;
|
||||
let path = line.path.clone().ok_or_else(|| {
|
||||
KclError::Type(KclErrorDetails {
|
||||
message: format!("Expected a line segment with a path, found `{:?}`", line),
|
||||
source_ranges: vec![args.source_range],
|
||||
})
|
||||
KclError::Type(KclErrorDetails::new(
|
||||
format!("Expected a line segment with a path, found `{:?}`", line),
|
||||
vec![args.source_range],
|
||||
))
|
||||
})?;
|
||||
|
||||
Ok(path.get_from()[1].clone())
|
||||
@ -334,10 +334,10 @@ fn inner_last_segment_x(sketch: Sketch, args: Args) -> Result<TyF64, KclError> {
|
||||
.paths
|
||||
.last()
|
||||
.ok_or_else(|| {
|
||||
KclError::Type(KclErrorDetails {
|
||||
message: format!("Expected a Sketch with at least one segment, found `{:?}`", sketch),
|
||||
source_ranges: vec![args.source_range],
|
||||
})
|
||||
KclError::Type(KclErrorDetails::new(
|
||||
format!("Expected a Sketch with at least one segment, found `{:?}`", sketch),
|
||||
vec![args.source_range],
|
||||
))
|
||||
})?
|
||||
.get_base();
|
||||
|
||||
@ -381,10 +381,10 @@ fn inner_last_segment_y(sketch: Sketch, args: Args) -> Result<TyF64, KclError> {
|
||||
.paths
|
||||
.last()
|
||||
.ok_or_else(|| {
|
||||
KclError::Type(KclErrorDetails {
|
||||
message: format!("Expected a Sketch with at least one segment, found `{:?}`", sketch),
|
||||
source_ranges: vec![args.source_range],
|
||||
})
|
||||
KclError::Type(KclErrorDetails::new(
|
||||
format!("Expected a Sketch with at least one segment, found `{:?}`", sketch),
|
||||
vec![args.source_range],
|
||||
))
|
||||
})?
|
||||
.get_base();
|
||||
|
||||
@ -429,10 +429,10 @@ pub async fn segment_length(exec_state: &mut ExecState, args: Args) -> Result<Kc
|
||||
fn inner_segment_length(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<TyF64, KclError> {
|
||||
let line = args.get_tag_engine_info(exec_state, tag)?;
|
||||
let path = line.path.clone().ok_or_else(|| {
|
||||
KclError::Type(KclErrorDetails {
|
||||
message: format!("Expected a line segment with a path, found `{:?}`", line),
|
||||
source_ranges: vec![args.source_range],
|
||||
})
|
||||
KclError::Type(KclErrorDetails::new(
|
||||
format!("Expected a line segment with a path, found `{:?}`", line),
|
||||
vec![args.source_range],
|
||||
))
|
||||
})?;
|
||||
|
||||
Ok(path.length())
|
||||
@ -473,10 +473,10 @@ pub async fn segment_angle(exec_state: &mut ExecState, args: Args) -> Result<Kcl
|
||||
fn inner_segment_angle(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<f64, KclError> {
|
||||
let line = args.get_tag_engine_info(exec_state, tag)?;
|
||||
let path = line.path.clone().ok_or_else(|| {
|
||||
KclError::Type(KclErrorDetails {
|
||||
message: format!("Expected a line segment with a path, found `{:?}`", line),
|
||||
source_ranges: vec![args.source_range],
|
||||
})
|
||||
KclError::Type(KclErrorDetails::new(
|
||||
format!("Expected a line segment with a path, found `{:?}`", line),
|
||||
vec![args.source_range],
|
||||
))
|
||||
})?;
|
||||
|
||||
let result = between(path.get_base().from, path.get_base().to);
|
||||
@ -575,10 +575,10 @@ pub async fn tangent_to_end(exec_state: &mut ExecState, args: Args) -> Result<Kc
|
||||
async fn inner_tangent_to_end(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<f64, KclError> {
|
||||
let line = args.get_tag_engine_info(exec_state, tag)?;
|
||||
let path = line.path.clone().ok_or_else(|| {
|
||||
KclError::Type(KclErrorDetails {
|
||||
message: format!("Expected a line segment with a path, found `{:?}`", line),
|
||||
source_ranges: vec![args.source_range],
|
||||
})
|
||||
KclError::Type(KclErrorDetails::new(
|
||||
format!("Expected a line segment with a path, found `{:?}`", line),
|
||||
vec![args.source_range],
|
||||
))
|
||||
})?;
|
||||
|
||||
let from = untype_point(path.get_to()).0;
|
||||
|
@ -325,17 +325,17 @@ async fn inner_polygon(
|
||||
args: Args,
|
||||
) -> Result<Sketch, KclError> {
|
||||
if num_sides < 3 {
|
||||
return Err(KclError::Type(KclErrorDetails {
|
||||
message: "Polygon must have at least 3 sides".to_string(),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
return Err(KclError::Type(KclErrorDetails::new(
|
||||
"Polygon must have at least 3 sides".to_string(),
|
||||
vec![args.source_range],
|
||||
)));
|
||||
}
|
||||
|
||||
if radius.n <= 0.0 {
|
||||
return Err(KclError::Type(KclErrorDetails {
|
||||
message: "Radius must be greater than 0".to_string(),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
return Err(KclError::Type(KclErrorDetails::new(
|
||||
"Radius must be greater than 0".to_string(),
|
||||
vec![args.source_range],
|
||||
)));
|
||||
}
|
||||
|
||||
let (sketch_surface, units) = match sketch_surface_or_group {
|
||||
|
@ -36,17 +36,17 @@ async fn inner_shell(
|
||||
args: Args,
|
||||
) -> Result<Vec<Solid>, KclError> {
|
||||
if faces.is_empty() {
|
||||
return Err(KclError::Type(KclErrorDetails {
|
||||
message: "You must shell at least one face".to_string(),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
return Err(KclError::Type(KclErrorDetails::new(
|
||||
"You must shell at least one face".to_owned(),
|
||||
vec![args.source_range],
|
||||
)));
|
||||
}
|
||||
|
||||
if solids.is_empty() {
|
||||
return Err(KclError::Type(KclErrorDetails {
|
||||
message: "You must shell at least one solid".to_string(),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
return Err(KclError::Type(KclErrorDetails::new(
|
||||
"You must shell at least one solid".to_owned(),
|
||||
vec![args.source_range],
|
||||
)));
|
||||
}
|
||||
|
||||
let mut face_ids = Vec::new();
|
||||
@ -63,20 +63,19 @@ async fn inner_shell(
|
||||
}
|
||||
|
||||
if face_ids.is_empty() {
|
||||
return Err(KclError::Type(KclErrorDetails {
|
||||
message: "Expected at least one valid face".to_string(),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
return Err(KclError::Type(KclErrorDetails::new(
|
||||
"Expected at least one valid face".to_owned(),
|
||||
vec![args.source_range],
|
||||
)));
|
||||
}
|
||||
|
||||
// Make sure all the solids have the same id, as we are going to shell them all at
|
||||
// once.
|
||||
if !solids.iter().all(|eg| eg.id == solids[0].id) {
|
||||
return Err(KclError::Type(KclErrorDetails {
|
||||
message: "All solids stem from the same root object, like multiple sketch on face extrusions, etc."
|
||||
.to_string(),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
return Err(KclError::Type(KclErrorDetails::new(
|
||||
"All solids stem from the same root object, like multiple sketch on face extrusions, etc.".to_owned(),
|
||||
vec![args.source_range],
|
||||
)));
|
||||
}
|
||||
|
||||
args.batch_modeling_cmd(
|
||||
|
@ -64,16 +64,16 @@ impl FaceTag {
|
||||
match self {
|
||||
FaceTag::Tag(ref t) => args.get_adjacent_face_to_tag(exec_state, t, must_be_planar).await,
|
||||
FaceTag::StartOrEnd(StartOrEnd::Start) => solid.start_cap_id.ok_or_else(|| {
|
||||
KclError::Type(KclErrorDetails {
|
||||
message: "Expected a start face".to_string(),
|
||||
source_ranges: vec![args.source_range],
|
||||
})
|
||||
KclError::Type(KclErrorDetails::new(
|
||||
"Expected a start face".to_string(),
|
||||
vec![args.source_range],
|
||||
))
|
||||
}),
|
||||
FaceTag::StartOrEnd(StartOrEnd::End) => solid.end_cap_id.ok_or_else(|| {
|
||||
KclError::Type(KclErrorDetails {
|
||||
message: "Expected an end face".to_string(),
|
||||
source_ranges: vec![args.source_range],
|
||||
})
|
||||
KclError::Type(KclErrorDetails::new(
|
||||
"Expected an end face".to_string(),
|
||||
vec![args.source_range],
|
||||
))
|
||||
}),
|
||||
}
|
||||
}
|
||||
@ -329,19 +329,18 @@ async fn straight_line(
|
||||
let from = sketch.current_pen_position()?;
|
||||
let (point, is_absolute) = match (end_absolute, end) {
|
||||
(Some(_), Some(_)) => {
|
||||
return Err(KclError::Semantic(KclErrorDetails {
|
||||
source_ranges: vec![args.source_range],
|
||||
message: "You cannot give both `end` and `endAbsolute` params, you have to choose one or the other"
|
||||
.to_owned(),
|
||||
}));
|
||||
return Err(KclError::Semantic(KclErrorDetails::new(
|
||||
"You cannot give both `end` and `endAbsolute` params, you have to choose one or the other".to_owned(),
|
||||
vec![args.source_range],
|
||||
)));
|
||||
}
|
||||
(Some(end_absolute), None) => (end_absolute, true),
|
||||
(None, Some(end)) => (end, false),
|
||||
(None, None) => {
|
||||
return Err(KclError::Semantic(KclErrorDetails {
|
||||
source_ranges: vec![args.source_range],
|
||||
message: format!("You must supply either `{relative_name}` or `endAbsolute` arguments"),
|
||||
}));
|
||||
return Err(KclError::Semantic(KclErrorDetails::new(
|
||||
format!("You must supply either `{relative_name}` or `endAbsolute` arguments"),
|
||||
vec![args.source_range],
|
||||
)));
|
||||
}
|
||||
};
|
||||
|
||||
@ -608,10 +607,10 @@ async fn inner_angled_line(
|
||||
.filter(|x| x.is_some())
|
||||
.count();
|
||||
if options_given > 1 {
|
||||
return Err(KclError::Type(KclErrorDetails {
|
||||
message: " one of `length`, `lengthX`, `lengthY`, `endAbsoluteX`, `endAbsoluteY` can be given".to_string(),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
return Err(KclError::Type(KclErrorDetails::new(
|
||||
" one of `length`, `lengthX`, `lengthY`, `endAbsoluteX`, `endAbsoluteY` can be given".to_string(),
|
||||
vec![args.source_range],
|
||||
)));
|
||||
}
|
||||
if let Some(length_x) = length_x {
|
||||
return inner_angled_line_of_x_length(angle, length_x, sketch, tag, exec_state, args).await;
|
||||
@ -636,15 +635,14 @@ async fn inner_angled_line(
|
||||
(None, None, None, None, Some(end_absolute_y)) => {
|
||||
inner_angled_line_to_y(angle_degrees, end_absolute_y, sketch, tag, exec_state, args).await
|
||||
}
|
||||
(None, None, None, None, None) => Err(KclError::Type(KclErrorDetails {
|
||||
message: "One of `length`, `lengthX`, `lengthY`, `endAbsoluteX`, `endAbsoluteY` must be given".to_string(),
|
||||
source_ranges: vec![args.source_range],
|
||||
})),
|
||||
_ => Err(KclError::Type(KclErrorDetails {
|
||||
message: "Only One of `length`, `lengthX`, `lengthY`, `endAbsoluteX`, `endAbsoluteY` can be given"
|
||||
.to_string(),
|
||||
source_ranges: vec![args.source_range],
|
||||
})),
|
||||
(None, None, None, None, None) => Err(KclError::Type(KclErrorDetails::new(
|
||||
"One of `length`, `lengthX`, `lengthY`, `endAbsoluteX`, `endAbsoluteY` must be given".to_string(),
|
||||
vec![args.source_range],
|
||||
))),
|
||||
_ => Err(KclError::Type(KclErrorDetails::new(
|
||||
"Only One of `length`, `lengthX`, `lengthY`, `endAbsoluteX`, `endAbsoluteY` can be given".to_owned(),
|
||||
vec![args.source_range],
|
||||
))),
|
||||
}
|
||||
}
|
||||
|
||||
@ -715,17 +713,17 @@ async fn inner_angled_line_of_x_length(
|
||||
args: Args,
|
||||
) -> Result<Sketch, KclError> {
|
||||
if angle_degrees.abs() == 270.0 {
|
||||
return Err(KclError::Type(KclErrorDetails {
|
||||
message: "Cannot have an x constrained angle of 270 degrees".to_string(),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
return Err(KclError::Type(KclErrorDetails::new(
|
||||
"Cannot have an x constrained angle of 270 degrees".to_string(),
|
||||
vec![args.source_range],
|
||||
)));
|
||||
}
|
||||
|
||||
if angle_degrees.abs() == 90.0 {
|
||||
return Err(KclError::Type(KclErrorDetails {
|
||||
message: "Cannot have an x constrained angle of 90 degrees".to_string(),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
return Err(KclError::Type(KclErrorDetails::new(
|
||||
"Cannot have an x constrained angle of 90 degrees".to_string(),
|
||||
vec![args.source_range],
|
||||
)));
|
||||
}
|
||||
|
||||
let to = get_y_component(Angle::from_degrees(angle_degrees), length.n);
|
||||
@ -747,17 +745,17 @@ async fn inner_angled_line_to_x(
|
||||
let from = sketch.current_pen_position()?;
|
||||
|
||||
if angle_degrees.abs() == 270.0 {
|
||||
return Err(KclError::Type(KclErrorDetails {
|
||||
message: "Cannot have an x constrained angle of 270 degrees".to_string(),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
return Err(KclError::Type(KclErrorDetails::new(
|
||||
"Cannot have an x constrained angle of 270 degrees".to_string(),
|
||||
vec![args.source_range],
|
||||
)));
|
||||
}
|
||||
|
||||
if angle_degrees.abs() == 90.0 {
|
||||
return Err(KclError::Type(KclErrorDetails {
|
||||
message: "Cannot have an x constrained angle of 90 degrees".to_string(),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
return Err(KclError::Type(KclErrorDetails::new(
|
||||
"Cannot have an x constrained angle of 90 degrees".to_string(),
|
||||
vec![args.source_range],
|
||||
)));
|
||||
}
|
||||
|
||||
let x_component = x_to.to_length_units(from.units) - from.x;
|
||||
@ -782,17 +780,17 @@ async fn inner_angled_line_of_y_length(
|
||||
args: Args,
|
||||
) -> Result<Sketch, KclError> {
|
||||
if angle_degrees.abs() == 0.0 {
|
||||
return Err(KclError::Type(KclErrorDetails {
|
||||
message: "Cannot have a y constrained angle of 0 degrees".to_string(),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
return Err(KclError::Type(KclErrorDetails::new(
|
||||
"Cannot have a y constrained angle of 0 degrees".to_string(),
|
||||
vec![args.source_range],
|
||||
)));
|
||||
}
|
||||
|
||||
if angle_degrees.abs() == 180.0 {
|
||||
return Err(KclError::Type(KclErrorDetails {
|
||||
message: "Cannot have a y constrained angle of 180 degrees".to_string(),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
return Err(KclError::Type(KclErrorDetails::new(
|
||||
"Cannot have a y constrained angle of 180 degrees".to_string(),
|
||||
vec![args.source_range],
|
||||
)));
|
||||
}
|
||||
|
||||
let to = get_x_component(Angle::from_degrees(angle_degrees), length.n);
|
||||
@ -814,17 +812,17 @@ async fn inner_angled_line_to_y(
|
||||
let from = sketch.current_pen_position()?;
|
||||
|
||||
if angle_degrees.abs() == 0.0 {
|
||||
return Err(KclError::Type(KclErrorDetails {
|
||||
message: "Cannot have a y constrained angle of 0 degrees".to_string(),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
return Err(KclError::Type(KclErrorDetails::new(
|
||||
"Cannot have a y constrained angle of 0 degrees".to_string(),
|
||||
vec![args.source_range],
|
||||
)));
|
||||
}
|
||||
|
||||
if angle_degrees.abs() == 180.0 {
|
||||
return Err(KclError::Type(KclErrorDetails {
|
||||
message: "Cannot have a y constrained angle of 180 degrees".to_string(),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
return Err(KclError::Type(KclErrorDetails::new(
|
||||
"Cannot have a y constrained angle of 180 degrees".to_string(),
|
||||
vec![args.source_range],
|
||||
)));
|
||||
}
|
||||
|
||||
let y_component = y_to.to_length_units(from.units) - from.y;
|
||||
@ -898,10 +896,10 @@ pub async fn inner_angled_line_that_intersects(
|
||||
) -> Result<Sketch, KclError> {
|
||||
let intersect_path = args.get_tag_engine_info(exec_state, &intersect_tag)?;
|
||||
let path = intersect_path.path.clone().ok_or_else(|| {
|
||||
KclError::Type(KclErrorDetails {
|
||||
message: format!("Expected an intersect path with a path, found `{:?}`", intersect_path),
|
||||
source_ranges: vec![args.source_range],
|
||||
})
|
||||
KclError::Type(KclErrorDetails::new(
|
||||
format!("Expected an intersect path with a path, found `{:?}`", intersect_path),
|
||||
vec![args.source_range],
|
||||
))
|
||||
})?;
|
||||
|
||||
let from = sketch.current_pen_position()?;
|
||||
@ -1176,10 +1174,10 @@ async fn inner_start_sketch_on(
|
||||
SketchData::Plane(plane) => {
|
||||
if plane.value == crate::exec::PlaneType::Uninit {
|
||||
if plane.info.origin.units == UnitLen::Unknown {
|
||||
return Err(KclError::Semantic(KclErrorDetails {
|
||||
message: "Origin of plane has unknown units".to_string(),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
return Err(KclError::Semantic(KclErrorDetails::new(
|
||||
"Origin of plane has unknown units".to_string(),
|
||||
vec![args.source_range],
|
||||
)));
|
||||
}
|
||||
let plane = make_sketch_plane_from_orientation(plane.info.into_plane_data(), exec_state, args).await?;
|
||||
Ok(SketchSurface::Plane(plane))
|
||||
@ -1200,10 +1198,10 @@ async fn inner_start_sketch_on(
|
||||
}
|
||||
SketchData::Solid(solid) => {
|
||||
let Some(tag) = face else {
|
||||
return Err(KclError::Type(KclErrorDetails {
|
||||
message: "Expected a tag for the face to sketch on".to_string(),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
return Err(KclError::Type(KclErrorDetails::new(
|
||||
"Expected a tag for the face to sketch on".to_string(),
|
||||
vec![args.source_range],
|
||||
)));
|
||||
};
|
||||
let face = start_sketch_on_face(solid, tag, exec_state, args).await?;
|
||||
|
||||
@ -1715,12 +1713,10 @@ pub(crate) async fn inner_arc(
|
||||
absolute_arc(&args, id, exec_state, sketch, from, interior_absolute, end_absolute, tag).await
|
||||
}
|
||||
_ => {
|
||||
Err(KclError::Type(KclErrorDetails {
|
||||
message:
|
||||
"Invalid combination of arguments. Either provide (angleStart, angleEnd, radius) or (endAbsolute, interiorAbsolute)"
|
||||
.to_string(),
|
||||
source_ranges: vec![args.source_range],
|
||||
}))
|
||||
Err(KclError::Type(KclErrorDetails::new(
|
||||
"Invalid combination of arguments. Either provide (angleStart, angleEnd, radius) or (endAbsolute, interiorAbsolute)".to_owned(),
|
||||
vec![args.source_range],
|
||||
)))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1804,10 +1800,10 @@ pub async fn relative_arc(
|
||||
let radius = radius.to_length_units(from.units);
|
||||
let (center, end) = arc_center_and_end(from.ignore_units(), a_start, a_end, radius);
|
||||
if a_start == a_end {
|
||||
return Err(KclError::Type(KclErrorDetails {
|
||||
message: "Arc start and end angles must be different".to_string(),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
return Err(KclError::Type(KclErrorDetails::new(
|
||||
"Arc start and end angles must be different".to_string(),
|
||||
vec![args.source_range],
|
||||
)));
|
||||
}
|
||||
let ccw = a_start < a_end;
|
||||
|
||||
@ -1958,19 +1954,18 @@ async fn inner_tangential_arc(
|
||||
let data = TangentialArcData::RadiusAndOffset { radius, offset: angle };
|
||||
inner_tangential_arc_radius_angle(data, sketch, tag, exec_state, args).await
|
||||
}
|
||||
(Some(_), Some(_), None, None) => Err(KclError::Semantic(KclErrorDetails {
|
||||
source_ranges: vec![args.source_range],
|
||||
message: "You cannot give both `end` and `endAbsolute` params, you have to choose one or the other"
|
||||
.to_owned(),
|
||||
})),
|
||||
(None, None, Some(_), None) | (None, None, None, Some(_)) => Err(KclError::Semantic(KclErrorDetails {
|
||||
source_ranges: vec![args.source_range],
|
||||
message: "You must supply both `radius` and `angle` arguments".to_owned(),
|
||||
})),
|
||||
(_, _, _, _) => Err(KclError::Semantic(KclErrorDetails {
|
||||
source_ranges: vec![args.source_range],
|
||||
message: "You must supply `end`, `endAbsolute`, or both `radius` and `angle` arguments".to_owned(),
|
||||
})),
|
||||
(Some(_), Some(_), None, None) => Err(KclError::Semantic(KclErrorDetails::new(
|
||||
"You cannot give both `end` and `endAbsolute` params, you have to choose one or the other".to_owned(),
|
||||
vec![args.source_range],
|
||||
))),
|
||||
(None, None, Some(_), None) | (None, None, None, Some(_)) => Err(KclError::Semantic(KclErrorDetails::new(
|
||||
"You must supply both `radius` and `angle` arguments".to_owned(),
|
||||
vec![args.source_range],
|
||||
))),
|
||||
(_, _, _, _) => Err(KclError::Semantic(KclErrorDetails::new(
|
||||
"You must supply `end`, `endAbsolute`, or both `radius` and `angle` arguments".to_owned(),
|
||||
vec![args.source_range],
|
||||
))),
|
||||
}
|
||||
}
|
||||
|
||||
@ -2121,19 +2116,17 @@ async fn inner_tangential_arc_to_point(
|
||||
});
|
||||
|
||||
if result.center[0].is_infinite() {
|
||||
return Err(KclError::Semantic(KclErrorDetails {
|
||||
source_ranges: vec![args.source_range],
|
||||
message:
|
||||
"could not sketch tangential arc, because its center would be infinitely far away in the X direction"
|
||||
.to_owned(),
|
||||
}));
|
||||
return Err(KclError::Semantic(KclErrorDetails::new(
|
||||
"could not sketch tangential arc, because its center would be infinitely far away in the X direction"
|
||||
.to_owned(),
|
||||
vec![args.source_range],
|
||||
)));
|
||||
} else if result.center[1].is_infinite() {
|
||||
return Err(KclError::Semantic(KclErrorDetails {
|
||||
source_ranges: vec![args.source_range],
|
||||
message:
|
||||
"could not sketch tangential arc, because its center would be infinitely far away in the Y direction"
|
||||
.to_owned(),
|
||||
}));
|
||||
return Err(KclError::Semantic(KclErrorDetails::new(
|
||||
"could not sketch tangential arc, because its center would be infinitely far away in the Y direction"
|
||||
.to_owned(),
|
||||
vec![args.source_range],
|
||||
)));
|
||||
}
|
||||
|
||||
let delta = if is_absolute {
|
||||
|
@ -193,10 +193,10 @@ async fn inner_sweep(
|
||||
Some("sketchPlane") => RelativeTo::SketchPlane,
|
||||
Some("trajectoryCurve") | None => RelativeTo::TrajectoryCurve,
|
||||
Some(_) => {
|
||||
return Err(KclError::Syntax(crate::errors::KclErrorDetails {
|
||||
source_ranges: vec![args.source_range],
|
||||
message: "If you provide relativeTo, it must either be 'sketchPlane' or 'trajectoryCurve'".to_owned(),
|
||||
}))
|
||||
return Err(KclError::Syntax(crate::errors::KclErrorDetails::new(
|
||||
"If you provide relativeTo, it must either be 'sketchPlane' or 'trajectoryCurve'".to_owned(),
|
||||
vec![args.source_range],
|
||||
)))
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -36,10 +36,10 @@ pub async fn scale(exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
|
||||
|
||||
// Ensure at least one scale value is provided.
|
||||
if scale_x.is_none() && scale_y.is_none() && scale_z.is_none() {
|
||||
return Err(KclError::Semantic(KclErrorDetails {
|
||||
message: "Expected `x`, `y`, or `z` to be provided.".to_string(),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
return Err(KclError::Semantic(KclErrorDetails::new(
|
||||
"Expected `x`, `y`, or `z` to be provided.".to_string(),
|
||||
vec![args.source_range],
|
||||
)));
|
||||
}
|
||||
|
||||
let objects = inner_scale(
|
||||
@ -219,10 +219,10 @@ pub async fn translate(exec_state: &mut ExecState, args: Args) -> Result<KclValu
|
||||
|
||||
// Ensure at least one translation value is provided.
|
||||
if translate_x.is_none() && translate_y.is_none() && translate_z.is_none() {
|
||||
return Err(KclError::Semantic(KclErrorDetails {
|
||||
message: "Expected `x`, `y`, or `z` to be provided.".to_string(),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
return Err(KclError::Semantic(KclErrorDetails::new(
|
||||
"Expected `x`, `y`, or `z` to be provided.".to_string(),
|
||||
vec![args.source_range],
|
||||
)));
|
||||
}
|
||||
|
||||
let objects = inner_translate(objects, translate_x, translate_y, translate_z, global, exec_state, args).await?;
|
||||
@ -452,82 +452,82 @@ pub async fn rotate(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
|
||||
|
||||
// Check if no rotation values are provided.
|
||||
if roll.is_none() && pitch.is_none() && yaw.is_none() && axis.is_none() && angle.is_none() {
|
||||
return Err(KclError::Semantic(KclErrorDetails {
|
||||
message: "Expected `roll`, `pitch`, and `yaw` or `axis` and `angle` to be provided.".to_string(),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
return Err(KclError::Semantic(KclErrorDetails::new(
|
||||
"Expected `roll`, `pitch`, and `yaw` or `axis` and `angle` to be provided.".to_string(),
|
||||
vec![args.source_range],
|
||||
)));
|
||||
}
|
||||
|
||||
// If they give us a roll, pitch, or yaw, they must give us at least one of them.
|
||||
if roll.is_some() || pitch.is_some() || yaw.is_some() {
|
||||
// Ensure they didn't also provide an axis or angle.
|
||||
if axis.is_some() || angle.is_some() {
|
||||
return Err(KclError::Semantic(KclErrorDetails {
|
||||
message: "Expected `axis` and `angle` to not be provided when `roll`, `pitch`, and `yaw` are provided."
|
||||
.to_string(),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
return Err(KclError::Semantic(KclErrorDetails::new(
|
||||
"Expected `axis` and `angle` to not be provided when `roll`, `pitch`, and `yaw` are provided."
|
||||
.to_owned(),
|
||||
vec![args.source_range],
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
||||
// If they give us an axis or angle, they must give us both.
|
||||
if axis.is_some() || angle.is_some() {
|
||||
if axis.is_none() {
|
||||
return Err(KclError::Semantic(KclErrorDetails {
|
||||
message: "Expected `axis` to be provided when `angle` is provided.".to_string(),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
return Err(KclError::Semantic(KclErrorDetails::new(
|
||||
"Expected `axis` to be provided when `angle` is provided.".to_string(),
|
||||
vec![args.source_range],
|
||||
)));
|
||||
}
|
||||
if angle.is_none() {
|
||||
return Err(KclError::Semantic(KclErrorDetails {
|
||||
message: "Expected `angle` to be provided when `axis` is provided.".to_string(),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
return Err(KclError::Semantic(KclErrorDetails::new(
|
||||
"Expected `angle` to be provided when `axis` is provided.".to_string(),
|
||||
vec![args.source_range],
|
||||
)));
|
||||
}
|
||||
|
||||
// Ensure they didn't also provide a roll, pitch, or yaw.
|
||||
if roll.is_some() || pitch.is_some() || yaw.is_some() {
|
||||
return Err(KclError::Semantic(KclErrorDetails {
|
||||
message: "Expected `roll`, `pitch`, and `yaw` to not be provided when `axis` and `angle` are provided."
|
||||
.to_string(),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
return Err(KclError::Semantic(KclErrorDetails::new(
|
||||
"Expected `roll`, `pitch`, and `yaw` to not be provided when `axis` and `angle` are provided."
|
||||
.to_owned(),
|
||||
vec![args.source_range],
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
||||
// Validate the roll, pitch, and yaw values.
|
||||
if let Some(roll) = &roll {
|
||||
if !(-360.0..=360.0).contains(&roll.n) {
|
||||
return Err(KclError::Semantic(KclErrorDetails {
|
||||
message: format!("Expected roll to be between -360 and 360, found `{}`", roll.n),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
return Err(KclError::Semantic(KclErrorDetails::new(
|
||||
format!("Expected roll to be between -360 and 360, found `{}`", roll.n),
|
||||
vec![args.source_range],
|
||||
)));
|
||||
}
|
||||
}
|
||||
if let Some(pitch) = &pitch {
|
||||
if !(-360.0..=360.0).contains(&pitch.n) {
|
||||
return Err(KclError::Semantic(KclErrorDetails {
|
||||
message: format!("Expected pitch to be between -360 and 360, found `{}`", pitch.n),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
return Err(KclError::Semantic(KclErrorDetails::new(
|
||||
format!("Expected pitch to be between -360 and 360, found `{}`", pitch.n),
|
||||
vec![args.source_range],
|
||||
)));
|
||||
}
|
||||
}
|
||||
if let Some(yaw) = &yaw {
|
||||
if !(-360.0..=360.0).contains(&yaw.n) {
|
||||
return Err(KclError::Semantic(KclErrorDetails {
|
||||
message: format!("Expected yaw to be between -360 and 360, found `{}`", yaw.n),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
return Err(KclError::Semantic(KclErrorDetails::new(
|
||||
format!("Expected yaw to be between -360 and 360, found `{}`", yaw.n),
|
||||
vec![args.source_range],
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
||||
// Validate the axis and angle values.
|
||||
if let Some(angle) = &angle {
|
||||
if !(-360.0..=360.0).contains(&angle.n) {
|
||||
return Err(KclError::Semantic(KclErrorDetails {
|
||||
message: format!("Expected angle to be between -360 and 360, found `{}`", angle.n),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
return Err(KclError::Semantic(KclErrorDetails::new(
|
||||
format!("Expected angle to be between -360 and 360, found `{}`", angle.n),
|
||||
vec![args.source_range],
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user