Implement coercion of numeric types for ascription and arithmetic (off by default)
Signed-off-by: Nick Cameron <nrc@ncameron.org>
This commit is contained in:
		| @ -18,7 +18,7 @@ std::math::PI: number = 3.14159265358979323846264338327950288_ | ||||
| circumference = 70 | ||||
|  | ||||
| exampleSketch = startSketchOn(XZ) | ||||
|  |> circle(center = [0, 0], radius = circumference/ (2 * PI)) | ||||
|  |> circle(center = [0, 0], radius = circumference / (2 * PI)) | ||||
|  | ||||
| example = extrude(exampleSketch, length = 5) | ||||
| ``` | ||||
|  | ||||
| @ -201564,15 +201564,6 @@ | ||||
|             }, | ||||
|             "length": { | ||||
|               "description": "The length of the line.", | ||||
|               "allOf": [ | ||||
|                 { | ||||
|                   "$ref": "#/components/schemas/TyF64" | ||||
|                 } | ||||
|               ] | ||||
|             } | ||||
|           }, | ||||
|           "definitions": { | ||||
|             "TyF64": { | ||||
|               "type": "number", | ||||
|               "format": "double" | ||||
|             } | ||||
|  | ||||
| @ -120,7 +120,7 @@ impl From<KclErrorWithOutputs> for KclError { | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[derive(Error, Debug, Serialize, Deserialize, ts_rs::TS, Clone, PartialEq)] | ||||
| #[derive(Error, Debug, Serialize, ts_rs::TS, Clone, PartialEq)] | ||||
| #[error("{error}")] | ||||
| #[ts(export)] | ||||
| #[serde(rename_all = "camelCase")] | ||||
|  | ||||
| @ -3,11 +3,11 @@ use schemars::JsonSchema; | ||||
| use serde::{Deserialize, Serialize}; | ||||
|  | ||||
| use super::{types::NumericType, ArtifactId, KclValue}; | ||||
| use crate::{docs::StdLibFn, std::get_stdlib_fn, ModuleId, SourceRange}; | ||||
| use crate::{docs::StdLibFn, ModuleId, SourceRange}; | ||||
|  | ||||
| /// A CAD modeling operation for display in the feature tree, AKA operations | ||||
| /// timeline. | ||||
| #[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)] | ||||
| #[derive(Debug, Clone, Serialize, PartialEq, ts_rs::TS, JsonSchema)] | ||||
| #[ts(export_to = "Operation.ts")] | ||||
| #[serde(tag = "type")] | ||||
| pub enum Operation { | ||||
| @ -60,7 +60,7 @@ impl Operation { | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)] | ||||
| #[derive(Debug, Clone, Serialize, PartialEq, ts_rs::TS, JsonSchema)] | ||||
| #[ts(export_to = "Operation.ts")] | ||||
| #[serde(tag = "type")] | ||||
| #[expect(clippy::large_enum_variant)] | ||||
| @ -90,7 +90,7 @@ pub enum Group { | ||||
| } | ||||
|  | ||||
| /// An argument to a CAD modeling operation. | ||||
| #[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)] | ||||
| #[derive(Debug, Clone, Serialize, PartialEq, ts_rs::TS, JsonSchema)] | ||||
| #[ts(export_to = "Operation.ts")] | ||||
| #[serde(rename_all = "camelCase")] | ||||
| pub struct OpArg { | ||||
| @ -110,7 +110,7 @@ impl OpArg { | ||||
|  | ||||
| /// A reference to a standard library function.  This exists to implement | ||||
| /// `PartialEq` and `Eq` for `Operation`. | ||||
| #[derive(Debug, Clone, Deserialize, Serialize, ts_rs::TS, JsonSchema)] | ||||
| #[derive(Debug, Clone, Serialize, ts_rs::TS, JsonSchema)] | ||||
| #[ts(export_to = "Operation.ts")] | ||||
| #[serde(rename_all = "camelCase")] | ||||
| pub struct StdLibFnRef { | ||||
| @ -156,25 +156,13 @@ where | ||||
|     serializer.serialize_str(&name) | ||||
| } | ||||
|  | ||||
| fn std_lib_fn_from_name<'de, D>(deserializer: D) -> Result<Box<dyn StdLibFn>, D::Error> | ||||
| where | ||||
|     D: serde::Deserializer<'de>, | ||||
| { | ||||
|     let s = String::deserialize(deserializer)?; | ||||
|     if let Some(std_lib_fn) = get_stdlib_fn(&s) { | ||||
|         Ok(std_lib_fn) | ||||
|     } else { | ||||
|         Err(serde::de::Error::custom(format!("not a KCL stdlib function: {}", s))) | ||||
|     } | ||||
| } | ||||
|  | ||||
| fn is_false(b: &bool) -> bool { | ||||
|     !*b | ||||
| } | ||||
|  | ||||
| /// A KCL value used in Operations.  `ArtifactId`s are used to refer to the | ||||
| /// actual scene objects.  Any data not needed in the UI may be omitted. | ||||
| #[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)] | ||||
| #[derive(Debug, Clone, Serialize, PartialEq, ts_rs::TS, JsonSchema)] | ||||
| #[ts(export_to = "Operation.ts")] | ||||
| #[serde(tag = "type")] | ||||
| pub enum OpKclValue { | ||||
|  | ||||
| @ -3,7 +3,11 @@ use std::collections::HashMap; | ||||
| use async_recursion::async_recursion; | ||||
| use indexmap::IndexMap; | ||||
|  | ||||
| use super::{cad_op::Group, kcl_value::TypeDef, types::PrimitiveType}; | ||||
| use super::{ | ||||
|     cad_op::Group, | ||||
|     kcl_value::TypeDef, | ||||
|     types::{PrimitiveType, CHECK_NUMERIC_TYPES}, | ||||
| }; | ||||
| use crate::{ | ||||
|     engine::ExecutionKind, | ||||
|     errors::{KclError, KclErrorDetails}, | ||||
| @ -26,7 +30,7 @@ use crate::{ | ||||
|     }, | ||||
|     source_range::SourceRange, | ||||
|     std::{ | ||||
|         args::{Arg, KwArgs}, | ||||
|         args::{Arg, KwArgs, TyF64}, | ||||
|         FunctionKind, | ||||
|     }, | ||||
|     CompilationError, | ||||
| @ -705,14 +709,14 @@ impl ExecutorContext { | ||||
|                 let result = self | ||||
|                     .execute_expr(&expr.expr, exec_state, metadata, &[], statement_kind) | ||||
|                     .await?; | ||||
|                 coerce(&result, &expr.ty, exec_state, expr.into())? | ||||
|                 apply_ascription(&result, &expr.ty, exec_state, expr.into())? | ||||
|             } | ||||
|         }; | ||||
|         Ok(item) | ||||
|     } | ||||
| } | ||||
|  | ||||
| fn coerce( | ||||
| fn apply_ascription( | ||||
|     value: &KclValue, | ||||
|     ty: &Node<Type>, | ||||
|     exec_state: &mut ExecState, | ||||
| @ -721,7 +725,24 @@ fn coerce( | ||||
|     let ty = RuntimeType::from_parsed(ty.inner.clone(), exec_state, value.into()) | ||||
|         .map_err(|e| KclError::Semantic(e.into()))?; | ||||
|  | ||||
|     value.coerce(&ty, exec_state).ok_or_else(|| { | ||||
|     if let KclValue::Number { | ||||
|         ty: NumericType::Unknown, | ||||
|         value, | ||||
|         meta, | ||||
|     } = value | ||||
|     { | ||||
|         // If the number has unknown units but the user is explicitly specifying them, treat the value as having had it's units erased, | ||||
|         // rather than forcing the user to explicitly erase them. | ||||
|         KclValue::Number { | ||||
|             ty: NumericType::Any, | ||||
|             value: *value, | ||||
|             meta: meta.clone(), | ||||
|         } | ||||
|         .coerce(&ty, exec_state) | ||||
|     } else { | ||||
|         value.coerce(&ty, exec_state) | ||||
|     } | ||||
|     .map_err(|_| { | ||||
|         KclError::Semantic(KclErrorDetails { | ||||
|             message: format!("could not coerce {} value to type {}", value.human_friendly_type(), ty), | ||||
|             source_ranges: vec![source_range], | ||||
| @ -977,69 +998,85 @@ impl Node<BinaryExpression> { | ||||
|             return Ok(KclValue::Bool { value: raw_value, meta }); | ||||
|         } | ||||
|  | ||||
|         let (left, lty) = parse_number_as_f64(&left_value, self.left.clone().into())?; | ||||
|         let (right, rty) = parse_number_as_f64(&right_value, self.right.clone().into())?; | ||||
|         let left = number_as_f64(&left_value, self.left.clone().into())?; | ||||
|         let right = number_as_f64(&right_value, self.right.clone().into())?; | ||||
|  | ||||
|         let value = match self.operator { | ||||
|             BinaryOperator::Add => KclValue::Number { | ||||
|                 value: left + right, | ||||
|                 meta, | ||||
|                 ty: NumericType::combine_add(lty, rty), | ||||
|             }, | ||||
|             BinaryOperator::Sub => KclValue::Number { | ||||
|                 value: left - right, | ||||
|                 meta, | ||||
|                 ty: NumericType::combine_add(lty, rty), | ||||
|             }, | ||||
|             BinaryOperator::Mul => KclValue::Number { | ||||
|                 value: left * right, | ||||
|                 meta, | ||||
|                 ty: NumericType::combine_mul(lty, rty), | ||||
|             }, | ||||
|             BinaryOperator::Div => KclValue::Number { | ||||
|                 value: left / right, | ||||
|                 meta, | ||||
|                 ty: NumericType::combine_div(lty, rty), | ||||
|             }, | ||||
|             BinaryOperator::Mod => KclValue::Number { | ||||
|                 value: left % right, | ||||
|                 meta, | ||||
|                 ty: NumericType::combine_div(lty, rty), | ||||
|             }, | ||||
|             BinaryOperator::Add => { | ||||
|                 let (l, r, ty) = NumericType::combine_eq(left, right); | ||||
|                 self.warn_on_unknown(&ty, "Adding", exec_state); | ||||
|                 KclValue::Number { value: l + r, meta, ty } | ||||
|             } | ||||
|             BinaryOperator::Sub => { | ||||
|                 let (l, r, ty) = NumericType::combine_eq(left, right); | ||||
|                 self.warn_on_unknown(&ty, "Subtracting", exec_state); | ||||
|                 KclValue::Number { value: l - r, meta, ty } | ||||
|             } | ||||
|             BinaryOperator::Mul => { | ||||
|                 let (l, r, ty) = NumericType::combine_mul(left, right); | ||||
|                 self.warn_on_unknown(&ty, "Multiplying", exec_state); | ||||
|                 KclValue::Number { value: l * r, meta, ty } | ||||
|             } | ||||
|             BinaryOperator::Div => { | ||||
|                 let (l, r, ty) = NumericType::combine_div(left, right); | ||||
|                 self.warn_on_unknown(&ty, "Dividing", exec_state); | ||||
|                 KclValue::Number { value: l / r, meta, ty } | ||||
|             } | ||||
|             BinaryOperator::Mod => { | ||||
|                 let (l, r, ty) = NumericType::combine_div(left, right); | ||||
|                 self.warn_on_unknown(&ty, "Modulo of", exec_state); | ||||
|                 KclValue::Number { value: l % r, meta, ty } | ||||
|             } | ||||
|             BinaryOperator::Pow => KclValue::Number { | ||||
|                 value: left.powf(right), | ||||
|                 value: left.n.powf(right.n), | ||||
|                 meta, | ||||
|                 ty: NumericType::Unknown, | ||||
|             }, | ||||
|             BinaryOperator::Neq => KclValue::Bool { | ||||
|                 value: left != right, | ||||
|                 meta, | ||||
|             }, | ||||
|             BinaryOperator::Gt => KclValue::Bool { | ||||
|                 value: left > right, | ||||
|                 meta, | ||||
|             }, | ||||
|             BinaryOperator::Gte => KclValue::Bool { | ||||
|                 value: left >= right, | ||||
|                 meta, | ||||
|             }, | ||||
|             BinaryOperator::Lt => KclValue::Bool { | ||||
|                 value: left < right, | ||||
|                 meta, | ||||
|             }, | ||||
|             BinaryOperator::Lte => KclValue::Bool { | ||||
|                 value: left <= right, | ||||
|                 meta, | ||||
|             }, | ||||
|             BinaryOperator::Eq => KclValue::Bool { | ||||
|                 value: left == right, | ||||
|                 meta, | ||||
|             }, | ||||
|             BinaryOperator::Neq => { | ||||
|                 let (l, r, ty) = NumericType::combine_eq(left, right); | ||||
|                 self.warn_on_unknown(&ty, "Comparing", exec_state); | ||||
|                 KclValue::Bool { value: l != r, meta } | ||||
|             } | ||||
|             BinaryOperator::Gt => { | ||||
|                 let (l, r, ty) = NumericType::combine_eq(left, right); | ||||
|                 self.warn_on_unknown(&ty, "Comparing", exec_state); | ||||
|                 KclValue::Bool { value: l > r, meta } | ||||
|             } | ||||
|             BinaryOperator::Gte => { | ||||
|                 let (l, r, ty) = NumericType::combine_eq(left, right); | ||||
|                 self.warn_on_unknown(&ty, "Comparing", exec_state); | ||||
|                 KclValue::Bool { value: l >= r, meta } | ||||
|             } | ||||
|             BinaryOperator::Lt => { | ||||
|                 let (l, r, ty) = NumericType::combine_eq(left, right); | ||||
|                 self.warn_on_unknown(&ty, "Comparing", exec_state); | ||||
|                 KclValue::Bool { value: l < r, meta } | ||||
|             } | ||||
|             BinaryOperator::Lte => { | ||||
|                 let (l, r, ty) = NumericType::combine_eq(left, right); | ||||
|                 self.warn_on_unknown(&ty, "Comparing", exec_state); | ||||
|                 KclValue::Bool { value: l <= r, meta } | ||||
|             } | ||||
|             BinaryOperator::Eq => { | ||||
|                 let (l, r, ty) = NumericType::combine_eq(left, right); | ||||
|                 self.warn_on_unknown(&ty, "Comparing", exec_state); | ||||
|                 KclValue::Bool { value: l == r, meta } | ||||
|             } | ||||
|             BinaryOperator::And | BinaryOperator::Or => unreachable!(), | ||||
|         }; | ||||
|  | ||||
|         Ok(value) | ||||
|     } | ||||
|  | ||||
|     fn warn_on_unknown(&self, ty: &NumericType, verb: &str, exec_state: &mut ExecState) { | ||||
|         if *CHECK_NUMERIC_TYPES && ty == &NumericType::Unknown { | ||||
|             // TODO suggest how to fix this | ||||
|             exec_state.warn(CompilationError::err( | ||||
|                 self.as_source_range(), | ||||
|                 format!("{} numbers which have unknown or incompatible units.", verb), | ||||
|             )); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl Node<UnaryExpression> { | ||||
| @ -1759,21 +1796,15 @@ fn article_for(s: &str) -> &'static str { | ||||
|     } | ||||
| } | ||||
|  | ||||
| pub fn parse_number_as_f64(v: &KclValue, source_range: SourceRange) -> Result<(f64, NumericType), KclError> { | ||||
|     if let KclValue::Number { value: n, ty, .. } = &v { | ||||
|         Ok((*n, ty.clone())) | ||||
|     } else { | ||||
| fn number_as_f64(v: &KclValue, source_range: SourceRange) -> Result<TyF64, KclError> { | ||||
|     v.as_ty_f64().ok_or_else(|| { | ||||
|         let actual_type = v.human_friendly_type(); | ||||
|         let article = if actual_type.starts_with(['a', 'e', 'i', 'o', 'u']) { | ||||
|             "an" | ||||
|         } else { | ||||
|             "a" | ||||
|         }; | ||||
|         Err(KclError::Semantic(KclErrorDetails { | ||||
|         let article = article_for(actual_type); | ||||
|         KclError::Semantic(KclErrorDetails { | ||||
|             source_ranges: vec![source_range], | ||||
|             message: format!("Expected a number, but found {article} {actual_type}",), | ||||
|         })) | ||||
|     } | ||||
|         }) | ||||
|     }) | ||||
| } | ||||
|  | ||||
| impl Node<IfExpression> { | ||||
| @ -2196,13 +2227,18 @@ impl FunctionSource { | ||||
|                                             .unwrap(), | ||||
|                                         exec_state, | ||||
|                                     ) | ||||
|                                     .ok_or_else(|| { | ||||
|                                     .map_err(|e| { | ||||
|                                         let mut message = format!( | ||||
|                                             "{label} requires a value with type `{}`, but found {}", | ||||
|                                             ty.inner, | ||||
|                                             arg.value.human_friendly_type(), | ||||
|                                         ); | ||||
|                                         if let Some(ty) = e.explicit_coercion { | ||||
|                                             // TODO if we have access to the AST for the argument we could choose which example to suggest. | ||||
|                                             message = format!("{message}\n\nYou may need to add information about the type of the argument, for example:\n  using a numeric suffix: `42{ty}`\n  or using type ascription: `foo(): number({ty})`"); | ||||
|                                         } | ||||
|                                         KclError::Semantic(KclErrorDetails { | ||||
|                                             message: format!( | ||||
|                                                 "{label} requires a value with type `{}`, but found {}", | ||||
|                                                 ty.inner, | ||||
|                                                 arg.value.human_friendly_type() | ||||
|                                             ), | ||||
|                                             message, | ||||
|                                             source_ranges: vec![callsite], | ||||
|                                         }) | ||||
|                                     })?; | ||||
| @ -2226,13 +2262,13 @@ impl FunctionSource { | ||||
|                                     &RuntimeType::from_parsed(ty.inner.clone(), exec_state, arg.source_range).unwrap(), | ||||
|                                     exec_state, | ||||
|                                 ) | ||||
|                                 .ok_or_else(|| { | ||||
|                                 .map_err(|_| { | ||||
|                                     KclError::Semantic(KclErrorDetails { | ||||
|                                         message: format!( | ||||
|                                             "The input argument of {} requires a value with type `{}`, but found {}", | ||||
|                                             props.name, | ||||
|                                             ty.inner, | ||||
|                                             arg.value.human_friendly_type() | ||||
|                                             arg.value.human_friendly_type(), | ||||
|                                         ), | ||||
|                                         source_ranges: vec![callsite], | ||||
|                                     }) | ||||
|  | ||||
| @ -15,7 +15,7 @@ use crate::{ | ||||
|     parsing::ast::types::{ | ||||
|         DefaultParamVal, FunctionExpression, KclNone, Literal, LiteralValue, Node, TagDeclarator, TagNode, | ||||
|     }, | ||||
|     std::StdFnProps, | ||||
|     std::{args::TyF64, StdFnProps}, | ||||
|     CompilationError, KclError, ModuleId, SourceRange, | ||||
| }; | ||||
|  | ||||
| @ -495,6 +495,7 @@ impl KclValue { | ||||
|             None | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     pub fn as_f64(&self) -> Option<f64> { | ||||
|         if let KclValue::Number { value, .. } = &self { | ||||
|             Some(*value) | ||||
| @ -503,6 +504,14 @@ impl KclValue { | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     pub fn as_ty_f64(&self) -> Option<TyF64> { | ||||
|         if let KclValue::Number { value, ty, .. } = &self { | ||||
|             Some(TyF64::new(*value, ty.clone())) | ||||
|         } else { | ||||
|             None | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     pub fn as_bool(&self) -> Option<bool> { | ||||
|         if let KclValue::Bool { value, meta: _ } = &self { | ||||
|             Some(*value) | ||||
|  | ||||
| @ -14,10 +14,20 @@ use crate::{ | ||||
|         ast::types::{PrimitiveType as AstPrimitiveType, Type}, | ||||
|         token::NumericSuffix, | ||||
|     }, | ||||
|     std::args::FromKclValue, | ||||
|     std::args::{FromKclValue, TyF64}, | ||||
|     CompilationError, SourceRange, | ||||
| }; | ||||
|  | ||||
| lazy_static::lazy_static! { | ||||
|     pub(super) static ref CHECK_NUMERIC_TYPES: bool = { | ||||
|         let env_var = std::env::var("ZOO_NUM_TYS"); | ||||
|         let Ok(env_var) = env_var else { | ||||
|             return false; | ||||
|         }; | ||||
|         !env_var.is_empty() | ||||
|     }; | ||||
| } | ||||
|  | ||||
| #[derive(Debug, Clone, PartialEq)] | ||||
| pub enum RuntimeType { | ||||
|     Primitive(PrimitiveType), | ||||
| @ -337,7 +347,7 @@ impl fmt::Display for PrimitiveType { | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)] | ||||
| #[derive(Debug, Clone, Serialize, PartialEq, ts_rs::TS, JsonSchema)] | ||||
| #[ts(export)] | ||||
| #[serde(tag = "type")] | ||||
| pub enum NumericType { | ||||
| @ -351,6 +361,15 @@ pub enum NumericType { | ||||
|     Any, | ||||
| } | ||||
|  | ||||
| impl Default for NumericType { | ||||
|     fn default() -> Self { | ||||
|         NumericType::Default { | ||||
|             len: UnitLen::default(), | ||||
|             angle: UnitAngle::default(), | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl NumericType { | ||||
|     pub fn count() -> Self { | ||||
|         NumericType::Known(UnitType::Count) | ||||
| @ -361,52 +380,67 @@ impl NumericType { | ||||
|     } | ||||
|  | ||||
|     /// Combine two types when we expect them to be equal. | ||||
|     pub fn combine_eq(self, other: &NumericType) -> NumericType { | ||||
|         if &self == other { | ||||
|             self | ||||
|         } else { | ||||
|             NumericType::Unknown | ||||
|         } | ||||
|     } | ||||
|     pub fn combine_eq(a: TyF64, b: TyF64) -> (f64, f64, NumericType) { | ||||
|         use NumericType::*; | ||||
|         match (a.ty, b.ty) { | ||||
|             (at, bt) if at == bt => (a.n, b.n, at), | ||||
|             (at, Any) => (a.n, b.n, at), | ||||
|             (Any, bt) => (a.n, b.n, bt), | ||||
|             (Default { .. }, Default { .. }) | (_, Unknown) | (Unknown, _) => (a.n, b.n, Unknown), | ||||
|  | ||||
|     /// Combine n types when we expect them to be equal. | ||||
|     /// | ||||
|     /// Precondition: tys.len() > 0 | ||||
|     pub fn combine_n_eq(tys: &[NumericType]) -> NumericType { | ||||
|         let ty0 = tys[0].clone(); | ||||
|         for t in &tys[1..] { | ||||
|             if t != &ty0 { | ||||
|                 return NumericType::Unknown; | ||||
|             // Known types and compatible, but needs adjustment. | ||||
|             (t @ Known(UnitType::Length(l1)), Known(UnitType::Length(l2))) => (a.n, l2.adjust_to(b.n, l1), t), | ||||
|             (t @ Known(UnitType::Angle(a1)), Known(UnitType::Angle(a2))) => (a.n, a2.adjust_to(b.n, a1), t), | ||||
|  | ||||
|             // Known but incompatible. | ||||
|             (Known(_), Known(_)) => (a.n, b.n, Unknown), | ||||
|  | ||||
|             // Known and unknown => we assume the known one, possibly with adjustment | ||||
|             (Known(UnitType::Count), Default { .. }) | (Default { .. }, Known(UnitType::Count)) => { | ||||
|                 (a.n, b.n, Known(UnitType::Count)) | ||||
|             } | ||||
|  | ||||
|             (t @ Known(UnitType::Length(l1)), Default { len: l2, .. }) => (a.n, l2.adjust_to(b.n, l1), t), | ||||
|             (Default { len: l1, .. }, t @ Known(UnitType::Length(l2))) => (l1.adjust_to(a.n, l2), b.n, t), | ||||
|  | ||||
|             (t @ Known(UnitType::Angle(a1)), Default { angle: a2, .. }) => (a.n, a2.adjust_to(b.n, a1), t), | ||||
|             (Default { angle: a1, .. }, t @ Known(UnitType::Angle(a2))) => (a1.adjust_to(a.n, a2), b.n, t), | ||||
|         } | ||||
|         ty0 | ||||
|     } | ||||
|  | ||||
|     /// Combine two types in addition-like operations. | ||||
|     pub fn combine_add(a: NumericType, b: NumericType) -> NumericType { | ||||
|         if a == b { | ||||
|             return a; | ||||
|     /// Combine two types for multiplication-like operations. | ||||
|     pub fn combine_mul(a: TyF64, b: TyF64) -> (f64, f64, NumericType) { | ||||
|         use NumericType::*; | ||||
|         match (a.ty, b.ty) { | ||||
|             (at @ Default { .. }, bt @ Default { .. }) if at != bt => (a.n, b.n, Unknown), | ||||
|             (Known(UnitType::Count) | Default { .. }, bt) => (a.n, b.n, bt), | ||||
|             (at, Known(UnitType::Count) | Default { .. }) => (a.n, b.n, at), | ||||
|             (Any, Any) => (a.n, b.n, Any), | ||||
|             _ => (a.n, b.n, Unknown), | ||||
|         } | ||||
|         NumericType::Unknown | ||||
|     } | ||||
|  | ||||
|     /// Combine two types in multiplication-like operations. | ||||
|     pub fn combine_mul(a: NumericType, b: NumericType) -> NumericType { | ||||
|         if a == NumericType::count() { | ||||
|             return b; | ||||
|     /// Combine two types for division-like operations. | ||||
|     pub fn combine_div(a: TyF64, b: TyF64) -> (f64, f64, NumericType) { | ||||
|         use NumericType::*; | ||||
|         match (a.ty, b.ty) { | ||||
|             (at, bt) if at == bt => (a.n, b.n, Known(UnitType::Count)), | ||||
|             (Default { .. }, Default { .. }) => (a.n, b.n, Unknown), | ||||
|             (at, Known(UnitType::Count) | Default { .. } | Any) => (a.n, b.n, at), | ||||
|             (Known(UnitType::Length(l1)), Known(UnitType::Length(l2))) => { | ||||
|                 (a.n, l2.adjust_to(b.n, l1), Known(UnitType::Count)) | ||||
|             } | ||||
|             (Known(UnitType::Angle(a1)), Known(UnitType::Angle(a2))) => { | ||||
|                 (a.n, a2.adjust_to(b.n, a1), Known(UnitType::Count)) | ||||
|             } | ||||
|             (Default { len: l1, .. }, Known(UnitType::Length(l2))) => { | ||||
|                 (l1.adjust_to(a.n, l2), b.n, Known(UnitType::Count)) | ||||
|             } | ||||
|             (Default { angle: a1, .. }, Known(UnitType::Angle(a2))) => { | ||||
|                 (a1.adjust_to(a.n, a2), b.n, Known(UnitType::Count)) | ||||
|             } | ||||
|             _ => (a.n, b.n, Unknown), | ||||
|         } | ||||
|         if b == NumericType::count() { | ||||
|             return a; | ||||
|         } | ||||
|         NumericType::Unknown | ||||
|     } | ||||
|  | ||||
|     /// Combine two types in division-like operations. | ||||
|     pub fn combine_div(a: NumericType, b: NumericType) -> NumericType { | ||||
|         if b == NumericType::count() { | ||||
|             return a; | ||||
|         } | ||||
|         NumericType::Unknown | ||||
|     } | ||||
|  | ||||
|     pub fn from_parsed(suffix: NumericSuffix, settings: &super::MetaSettings) -> Self { | ||||
| @ -431,12 +465,104 @@ impl NumericType { | ||||
|         use NumericType::*; | ||||
|  | ||||
|         match (self, other) { | ||||
|             (Unknown, _) | (_, Unknown) => false, | ||||
|             (a, b) if a == b => true, | ||||
|             (_, Any) => true, | ||||
|             (a, b) if a == b => true, | ||||
|             (Unknown, _) | (_, Unknown) => false, | ||||
|             (_, _) => false, | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     fn example_ty(&self) -> Option<String> { | ||||
|         match self { | ||||
|             Self::Known(t) => Some(t.to_string()), | ||||
|             Self::Default { len, .. } => Some(len.to_string()), | ||||
|             _ => None, | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     fn coerce(&self, val: &KclValue) -> Result<KclValue, CoercionError> { | ||||
|         let KclValue::Number { value, ty, meta } = val else { | ||||
|             return Err(val.into()); | ||||
|         }; | ||||
|  | ||||
|         if !*CHECK_NUMERIC_TYPES { | ||||
|             return Ok(val.clone()); | ||||
|         } | ||||
|  | ||||
|         if ty.subtype(self) { | ||||
|             return Ok(KclValue::Number { | ||||
|                 value: *value, | ||||
|                 ty: ty.clone(), | ||||
|                 meta: meta.clone(), | ||||
|             }); | ||||
|         } | ||||
|  | ||||
|         // Not subtypes, but might be able to coerce | ||||
|         use NumericType::*; | ||||
|         match (ty, self) { | ||||
|             // We don't have enough information to coerce. | ||||
|             (Unknown, _) => Err(CoercionError::from(val).with_explicit(self.example_ty().unwrap_or("mm".to_owned()))), | ||||
|             (_, Unknown) => Err(val.into()), | ||||
|             (Any, _) => Ok(KclValue::Number { | ||||
|                 value: *value, | ||||
|                 ty: self.clone(), | ||||
|                 meta: meta.clone(), | ||||
|             }), | ||||
|  | ||||
|             // We don't actually need to coerce, since we just keep the partially-known type with the value. | ||||
|             (Default { .. }, Default { .. }) => Ok(KclValue::Number { | ||||
|                 value: *value, | ||||
|                 ty: ty.clone(), | ||||
|                 meta: meta.clone(), | ||||
|             }), | ||||
|  | ||||
|             // Known types and compatible, but needs adjustment. | ||||
|             (Known(UnitType::Length(l1)), Known(UnitType::Length(l2))) => Ok(KclValue::Number { | ||||
|                 value: l1.adjust_to(*value, *l2), | ||||
|                 ty: self.clone(), | ||||
|                 meta: meta.clone(), | ||||
|             }), | ||||
|             (Known(UnitType::Angle(a1)), Known(UnitType::Angle(a2))) => Ok(KclValue::Number { | ||||
|                 value: a1.adjust_to(*value, *a2), | ||||
|                 ty: self.clone(), | ||||
|                 meta: meta.clone(), | ||||
|             }), | ||||
|  | ||||
|             // Known but incompatible. | ||||
|             (Known(_), Known(_)) => Err(val.into()), | ||||
|  | ||||
|             // Known and unknown => we assume the rhs, possibly with adjustment | ||||
|             (Known(UnitType::Count), Default { .. }) | (Default { .. }, Known(UnitType::Count)) => { | ||||
|                 Ok(KclValue::Number { | ||||
|                     value: *value, | ||||
|                     ty: Known(UnitType::Count), | ||||
|                     meta: meta.clone(), | ||||
|                 }) | ||||
|             } | ||||
|  | ||||
|             (Known(UnitType::Length(l1)), Default { len: l2, .. }) | ||||
|             | (Default { len: l1, .. }, Known(UnitType::Length(l2))) => Ok(KclValue::Number { | ||||
|                 value: l1.adjust_to(*value, *l2), | ||||
|                 ty: Known(UnitType::Length(*l2)), | ||||
|                 meta: meta.clone(), | ||||
|             }), | ||||
|  | ||||
|             (Known(UnitType::Angle(a1)), Default { angle: a2, .. }) | ||||
|             | (Default { angle: a1, .. }, Known(UnitType::Angle(a2))) => Ok(KclValue::Number { | ||||
|                 value: a1.adjust_to(*value, *a2), | ||||
|                 ty: Known(UnitType::Angle(*a2)), | ||||
|                 meta: meta.clone(), | ||||
|             }), | ||||
|  | ||||
|             (_, _) => unreachable!(), | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl From<NumericType> for RuntimeType { | ||||
|     fn from(t: NumericType) -> RuntimeType { | ||||
|         RuntimeType::Primitive(PrimitiveType::Number(t)) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl From<UnitLen> for NumericType { | ||||
| @ -485,6 +611,39 @@ pub enum UnitLen { | ||||
|     Yards, | ||||
| } | ||||
|  | ||||
| impl UnitLen { | ||||
|     fn adjust_to(self, value: f64, to: UnitLen) -> f64 { | ||||
|         if self == to { | ||||
|             return value; | ||||
|         } | ||||
|  | ||||
|         use UnitLen::*; | ||||
|         let (base, base_unit) = match self { | ||||
|             Mm => (value, Mm), | ||||
|             Cm => (value * 10.0, Mm), | ||||
|             M => (value * 1000.0, Mm), | ||||
|             Inches => (value, Inches), | ||||
|             Feet => (value * 12.0, Inches), | ||||
|             Yards => (value * 36.0, Inches), | ||||
|         }; | ||||
|         let (base, base_unit) = match (base_unit, to) { | ||||
|             (Mm, Inches) | (Mm, Feet) | (Mm, Yards) => (base / 25.4, Inches), | ||||
|             (Inches, Mm) | (Inches, Cm) | (Inches, M) => (base * 25.4, Mm), | ||||
|             _ => (base, base_unit), | ||||
|         }; | ||||
|  | ||||
|         match (base_unit, to) { | ||||
|             (Mm, Mm) => base, | ||||
|             (Mm, Cm) => base / 10.0, | ||||
|             (Mm, M) => base / 1000.0, | ||||
|             (Inches, Inches) => base, | ||||
|             (Inches, Feet) => base / 12.0, | ||||
|             (Inches, Yards) => base / 36.0, | ||||
|             _ => unreachable!(), | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl std::fmt::Display for UnitLen { | ||||
|     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||||
|         match self { | ||||
| @ -563,6 +722,19 @@ pub enum UnitAngle { | ||||
|     Radians, | ||||
| } | ||||
|  | ||||
| impl UnitAngle { | ||||
|     fn adjust_to(self, value: f64, to: UnitAngle) -> f64 { | ||||
|         use std::f64::consts::PI; | ||||
|         use UnitAngle::*; | ||||
|         match (self, to) { | ||||
|             (Degrees, Degrees) => value, | ||||
|             (Degrees, Radians) => (value / 180.0) * PI, | ||||
|             (Radians, Degrees) => 180.0 * value / PI, | ||||
|             (Radians, Radians) => value, | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl std::fmt::Display for UnitAngle { | ||||
|     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||||
|         match self { | ||||
| @ -584,6 +756,28 @@ impl TryFrom<NumericSuffix> for UnitAngle { | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[derive(Debug, Clone)] | ||||
| pub struct CoercionError { | ||||
|     pub found: Option<RuntimeType>, | ||||
|     pub explicit_coercion: Option<String>, | ||||
| } | ||||
|  | ||||
| impl CoercionError { | ||||
|     fn with_explicit(mut self, c: String) -> Self { | ||||
|         self.explicit_coercion = Some(c); | ||||
|         self | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl From<&'_ KclValue> for CoercionError { | ||||
|     fn from(value: &'_ KclValue) -> Self { | ||||
|         CoercionError { | ||||
|             found: value.principal_type(), | ||||
|             explicit_coercion: None, | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl KclValue { | ||||
|     /// True if `self` has a type which is a subtype of `ty` without coercion. | ||||
|     pub fn has_type(&self, ty: &RuntimeType) -> bool { | ||||
| @ -600,7 +794,7 @@ impl KclValue { | ||||
|     ///   - result.principal_type().unwrap().subtype(ty) | ||||
|     /// | ||||
|     /// If self.principal_type() == ty then result == self | ||||
|     pub fn coerce(&self, ty: &RuntimeType, exec_state: &mut ExecState) -> Option<KclValue> { | ||||
|     pub fn coerce(&self, ty: &RuntimeType, exec_state: &mut ExecState) -> Result<KclValue, CoercionError> { | ||||
|         match ty { | ||||
|             RuntimeType::Primitive(ty) => self.coerce_to_primitive_type(ty, exec_state), | ||||
|             RuntimeType::Array(ty, len) => self.coerce_to_array_type(ty, *len, exec_state, false), | ||||
| @ -610,40 +804,52 @@ impl KclValue { | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     fn coerce_to_primitive_type(&self, ty: &PrimitiveType, exec_state: &mut ExecState) -> Option<KclValue> { | ||||
|     fn coerce_to_primitive_type( | ||||
|         &self, | ||||
|         ty: &PrimitiveType, | ||||
|         exec_state: &mut ExecState, | ||||
|     ) -> Result<KclValue, CoercionError> { | ||||
|         let value = match self { | ||||
|             KclValue::MixedArray { value, .. } | KclValue::HomArray { value, .. } if value.len() == 1 => &value[0], | ||||
|             _ => self, | ||||
|         }; | ||||
|         match ty { | ||||
|             // TODO numeric type coercions | ||||
|             PrimitiveType::Number(_ty) => match value { | ||||
|                 KclValue::Number { .. } => Some(value.clone()), | ||||
|                 _ => None, | ||||
|             }, | ||||
|             PrimitiveType::Number(ty) => ty.coerce(value), | ||||
|             PrimitiveType::String => match value { | ||||
|                 KclValue::String { .. } => Some(value.clone()), | ||||
|                 _ => None, | ||||
|                 KclValue::String { .. } => Ok(value.clone()), | ||||
|                 _ => Err(self.into()), | ||||
|             }, | ||||
|             PrimitiveType::Boolean => match value { | ||||
|                 KclValue::Bool { .. } => Some(value.clone()), | ||||
|                 _ => None, | ||||
|                 KclValue::Bool { .. } => Ok(value.clone()), | ||||
|                 _ => Err(self.into()), | ||||
|             }, | ||||
|             PrimitiveType::Sketch => match value { | ||||
|                 KclValue::Sketch { .. } => Some(value.clone()), | ||||
|                 _ => None, | ||||
|                 KclValue::Sketch { .. } => Ok(value.clone()), | ||||
|                 _ => Err(self.into()), | ||||
|             }, | ||||
|             PrimitiveType::Solid => match value { | ||||
|                 KclValue::Solid { .. } => Some(value.clone()), | ||||
|                 _ => None, | ||||
|                 KclValue::Solid { .. } => Ok(value.clone()), | ||||
|                 _ => Err(self.into()), | ||||
|             }, | ||||
|             PrimitiveType::Plane => match value { | ||||
|                 KclValue::Plane { .. } => Some(value.clone()), | ||||
|                 KclValue::Plane { .. } => Ok(value.clone()), | ||||
|                 KclValue::Object { value, meta } => { | ||||
|                     let origin = value.get("origin").and_then(Point3d::from_kcl_val)?; | ||||
|                     let x_axis = value.get("xAxis").and_then(Point3d::from_kcl_val)?; | ||||
|                     let y_axis = value.get("yAxis").and_then(Point3d::from_kcl_val)?; | ||||
|                     let z_axis = value.get("zAxis").and_then(Point3d::from_kcl_val)?; | ||||
|                     let origin = value | ||||
|                         .get("origin") | ||||
|                         .and_then(Point3d::from_kcl_val) | ||||
|                         .ok_or(CoercionError::from(self))?; | ||||
|                     let x_axis = value | ||||
|                         .get("xAxis") | ||||
|                         .and_then(Point3d::from_kcl_val) | ||||
|                         .ok_or(CoercionError::from(self))?; | ||||
|                     let y_axis = value | ||||
|                         .get("yAxis") | ||||
|                         .and_then(Point3d::from_kcl_val) | ||||
|                         .ok_or(CoercionError::from(self))?; | ||||
|                     let z_axis = value | ||||
|                         .get("zAxis") | ||||
|                         .and_then(Point3d::from_kcl_val) | ||||
|                         .ok_or(CoercionError::from(self))?; | ||||
|  | ||||
|                     let id = exec_state.mod_local.id_generator.next_uuid(); | ||||
|                     let plane = Plane { | ||||
| @ -659,75 +865,87 @@ impl KclValue { | ||||
|                         meta: meta.clone(), | ||||
|                     }; | ||||
|  | ||||
|                     Some(KclValue::Plane { value: Box::new(plane) }) | ||||
|                     Ok(KclValue::Plane { value: Box::new(plane) }) | ||||
|                 } | ||||
|                 _ => None, | ||||
|                 _ => Err(self.into()), | ||||
|             }, | ||||
|             PrimitiveType::Face => match value { | ||||
|                 KclValue::Face { .. } => Some(value.clone()), | ||||
|                 _ => None, | ||||
|                 KclValue::Face { .. } => Ok(value.clone()), | ||||
|                 _ => Err(self.into()), | ||||
|             }, | ||||
|             PrimitiveType::Helix => match value { | ||||
|                 KclValue::Helix { .. } => Some(value.clone()), | ||||
|                 _ => None, | ||||
|                 KclValue::Helix { .. } => Ok(value.clone()), | ||||
|                 _ => Err(self.into()), | ||||
|             }, | ||||
|             PrimitiveType::Edge => match value { | ||||
|                 KclValue::Uuid { .. } => Some(value.clone()), | ||||
|                 KclValue::TagIdentifier { .. } => Some(value.clone()), | ||||
|                 _ => None, | ||||
|                 KclValue::Uuid { .. } => Ok(value.clone()), | ||||
|                 KclValue::TagIdentifier { .. } => Ok(value.clone()), | ||||
|                 _ => Err(self.into()), | ||||
|             }, | ||||
|             PrimitiveType::Axis2d => match value { | ||||
|                 KclValue::Object { value: values, meta } => { | ||||
|                     if values.get("origin")?.has_type(&RuntimeType::point2d()) | ||||
|                         && values.get("direction")?.has_type(&RuntimeType::point2d()) | ||||
|                     if values | ||||
|                         .get("origin") | ||||
|                         .ok_or(CoercionError::from(self))? | ||||
|                         .has_type(&RuntimeType::point2d()) | ||||
|                         && values | ||||
|                             .get("direction") | ||||
|                             .ok_or(CoercionError::from(self))? | ||||
|                             .has_type(&RuntimeType::point2d()) | ||||
|                     { | ||||
|                         return Some(value.clone()); | ||||
|                         return Ok(value.clone()); | ||||
|                     } | ||||
|  | ||||
|                     let origin = values.get("origin").and_then(|p| { | ||||
|                     let origin = values.get("origin").ok_or(self.into()).and_then(|p| { | ||||
|                         p.coerce_to_array_type(&RuntimeType::number_any(), ArrayLen::Known(2), exec_state, true) | ||||
|                     })?; | ||||
|                     let direction = values.get("direction").and_then(|p| { | ||||
|                     let direction = values.get("direction").ok_or(self.into()).and_then(|p| { | ||||
|                         p.coerce_to_array_type(&RuntimeType::number_any(), ArrayLen::Known(2), exec_state, true) | ||||
|                     })?; | ||||
|  | ||||
|                     Some(KclValue::Object { | ||||
|                     Ok(KclValue::Object { | ||||
|                         value: [("origin".to_owned(), origin), ("direction".to_owned(), direction)].into(), | ||||
|                         meta: meta.clone(), | ||||
|                     }) | ||||
|                 } | ||||
|                 _ => None, | ||||
|                 _ => Err(self.into()), | ||||
|             }, | ||||
|             PrimitiveType::Axis3d => match value { | ||||
|                 KclValue::Object { value: values, meta } => { | ||||
|                     if values.get("origin")?.has_type(&RuntimeType::point3d()) | ||||
|                         && values.get("direction")?.has_type(&RuntimeType::point3d()) | ||||
|                     if values | ||||
|                         .get("origin") | ||||
|                         .ok_or(CoercionError::from(self))? | ||||
|                         .has_type(&RuntimeType::point3d()) | ||||
|                         && values | ||||
|                             .get("direction") | ||||
|                             .ok_or(CoercionError::from(self))? | ||||
|                             .has_type(&RuntimeType::point3d()) | ||||
|                     { | ||||
|                         return Some(value.clone()); | ||||
|                         return Ok(value.clone()); | ||||
|                     } | ||||
|  | ||||
|                     let origin = values.get("origin").and_then(|p| { | ||||
|                     let origin = values.get("origin").ok_or(self.into()).and_then(|p| { | ||||
|                         p.coerce_to_array_type(&RuntimeType::number_any(), ArrayLen::Known(3), exec_state, true) | ||||
|                     })?; | ||||
|                     let direction = values.get("direction").and_then(|p| { | ||||
|                     let direction = values.get("direction").ok_or(self.into()).and_then(|p| { | ||||
|                         p.coerce_to_array_type(&RuntimeType::number_any(), ArrayLen::Known(3), exec_state, true) | ||||
|                     })?; | ||||
|  | ||||
|                     Some(KclValue::Object { | ||||
|                     Ok(KclValue::Object { | ||||
|                         value: [("origin".to_owned(), origin), ("direction".to_owned(), direction)].into(), | ||||
|                         meta: meta.clone(), | ||||
|                     }) | ||||
|                 } | ||||
|                 _ => None, | ||||
|                 _ => Err(self.into()), | ||||
|             }, | ||||
|             PrimitiveType::ImportedGeometry => match value { | ||||
|                 KclValue::ImportedGeometry { .. } => Some(value.clone()), | ||||
|                 _ => None, | ||||
|                 KclValue::ImportedGeometry { .. } => Ok(value.clone()), | ||||
|                 _ => Err(self.into()), | ||||
|             }, | ||||
|             PrimitiveType::Tag => match value { | ||||
|                 KclValue::TagDeclarator { .. } => Some(value.clone()), | ||||
|                 KclValue::TagIdentifier { .. } => Some(value.clone()), | ||||
|                 _ => None, | ||||
|                 KclValue::TagDeclarator { .. } => Ok(value.clone()), | ||||
|                 KclValue::TagIdentifier { .. } => Ok(value.clone()), | ||||
|                 _ => Err(self.into()), | ||||
|             }, | ||||
|         } | ||||
|     } | ||||
| @ -738,37 +956,40 @@ impl KclValue { | ||||
|         len: ArrayLen, | ||||
|         exec_state: &mut ExecState, | ||||
|         allow_shrink: bool, | ||||
|     ) -> Option<KclValue> { | ||||
|     ) -> Result<KclValue, CoercionError> { | ||||
|         match self { | ||||
|             KclValue::HomArray { value, ty: aty } if aty.subtype(ty) => { | ||||
|                 len.satisfied(value.len(), allow_shrink).map(|len| KclValue::HomArray { | ||||
|             KclValue::HomArray { value, ty: aty } if aty.subtype(ty) => len | ||||
|                 .satisfied(value.len(), allow_shrink) | ||||
|                 .map(|len| KclValue::HomArray { | ||||
|                     value: value[..len].to_vec(), | ||||
|                     ty: aty.clone(), | ||||
|                 }) | ||||
|             } | ||||
|             value if len.satisfied(1, false).is_some() && value.has_type(ty) => Some(KclValue::HomArray { | ||||
|                 .ok_or(self.into()), | ||||
|             value if len.satisfied(1, false).is_some() && value.has_type(ty) => Ok(KclValue::HomArray { | ||||
|                 value: vec![value.clone()], | ||||
|                 ty: ty.clone(), | ||||
|             }), | ||||
|             KclValue::MixedArray { value, .. } => { | ||||
|                 let len = len.satisfied(value.len(), allow_shrink)?; | ||||
|                 let len = len | ||||
|                     .satisfied(value.len(), allow_shrink) | ||||
|                     .ok_or(CoercionError::from(self))?; | ||||
|  | ||||
|                 let value = value[..len] | ||||
|                     .iter() | ||||
|                     .map(|v| v.coerce(ty, exec_state)) | ||||
|                     .collect::<Option<Vec<_>>>()?; | ||||
|                     .collect::<Result<Vec<_>, _>>()?; | ||||
|  | ||||
|                 Some(KclValue::HomArray { value, ty: ty.clone() }) | ||||
|                 Ok(KclValue::HomArray { value, ty: ty.clone() }) | ||||
|             } | ||||
|             KclValue::KclNone { .. } if len.satisfied(0, false).is_some() => Some(KclValue::HomArray { | ||||
|             KclValue::KclNone { .. } if len.satisfied(0, false).is_some() => Ok(KclValue::HomArray { | ||||
|                 value: Vec::new(), | ||||
|                 ty: ty.clone(), | ||||
|             }), | ||||
|             _ => None, | ||||
|             _ => Err(self.into()), | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     fn coerce_to_tuple_type(&self, tys: &[RuntimeType], exec_state: &mut ExecState) -> Option<KclValue> { | ||||
|     fn coerce_to_tuple_type(&self, tys: &[RuntimeType], exec_state: &mut ExecState) -> Result<KclValue, CoercionError> { | ||||
|         match self { | ||||
|             KclValue::MixedArray { value, .. } | KclValue::HomArray { value, .. } if value.len() == tys.len() => { | ||||
|                 let mut result = Vec::new(); | ||||
| @ -776,50 +997,54 @@ impl KclValue { | ||||
|                     result.push(value[i].coerce(t, exec_state)?); | ||||
|                 } | ||||
|  | ||||
|                 Some(KclValue::MixedArray { | ||||
|                 Ok(KclValue::MixedArray { | ||||
|                     value: result, | ||||
|                     meta: Vec::new(), | ||||
|                 }) | ||||
|             } | ||||
|             KclValue::KclNone { meta, .. } if tys.is_empty() => Some(KclValue::MixedArray { | ||||
|             KclValue::KclNone { meta, .. } if tys.is_empty() => Ok(KclValue::MixedArray { | ||||
|                 value: Vec::new(), | ||||
|                 meta: meta.clone(), | ||||
|             }), | ||||
|             value if tys.len() == 1 && value.has_type(&tys[0]) => Some(KclValue::MixedArray { | ||||
|             value if tys.len() == 1 && value.has_type(&tys[0]) => Ok(KclValue::MixedArray { | ||||
|                 value: vec![value.clone()], | ||||
|                 meta: Vec::new(), | ||||
|             }), | ||||
|             _ => None, | ||||
|             _ => Err(self.into()), | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     fn coerce_to_union_type(&self, tys: &[RuntimeType], exec_state: &mut ExecState) -> Option<KclValue> { | ||||
|     fn coerce_to_union_type(&self, tys: &[RuntimeType], exec_state: &mut ExecState) -> Result<KclValue, CoercionError> { | ||||
|         for t in tys { | ||||
|             if let Some(v) = self.coerce(t, exec_state) { | ||||
|                 return Some(v); | ||||
|             if let Ok(v) = self.coerce(t, exec_state) { | ||||
|                 return Ok(v); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         None | ||||
|         Err(self.into()) | ||||
|     } | ||||
|  | ||||
|     fn coerce_to_object_type(&self, tys: &[(String, RuntimeType)], _exec_state: &mut ExecState) -> Option<KclValue> { | ||||
|     fn coerce_to_object_type( | ||||
|         &self, | ||||
|         tys: &[(String, RuntimeType)], | ||||
|         _exec_state: &mut ExecState, | ||||
|     ) -> Result<KclValue, CoercionError> { | ||||
|         match self { | ||||
|             KclValue::Object { value, .. } => { | ||||
|                 for (s, t) in tys { | ||||
|                     // TODO coerce fields | ||||
|                     if !value.get(s)?.has_type(t) { | ||||
|                         return None; | ||||
|                     if !value.get(s).ok_or(CoercionError::from(self))?.has_type(t) { | ||||
|                         return Err(self.into()); | ||||
|                     } | ||||
|                 } | ||||
|                 // TODO remove non-required fields | ||||
|                 Some(self.clone()) | ||||
|                 Ok(self.clone()) | ||||
|             } | ||||
|             KclValue::KclNone { meta, .. } if tys.is_empty() => Some(KclValue::Object { | ||||
|             KclValue::KclNone { meta, .. } if tys.is_empty() => Ok(KclValue::Object { | ||||
|                 value: HashMap::new(), | ||||
|                 meta: meta.clone(), | ||||
|             }), | ||||
|             _ => None, | ||||
|             _ => Err(self.into()), | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @ -859,6 +1084,8 @@ impl KclValue { | ||||
|  | ||||
| #[cfg(test)] | ||||
| mod test { | ||||
|     use crate::execution::{parse_execute, ExecTestResults}; | ||||
|  | ||||
|     use super::*; | ||||
|  | ||||
|     fn values(exec_state: &mut ExecState) -> Vec<KclValue> { | ||||
| @ -990,7 +1217,7 @@ mod test { | ||||
|             // Not a subtype | ||||
|             assert!(v | ||||
|                 .coerce(&RuntimeType::Primitive(PrimitiveType::Boolean), &mut exec_state) | ||||
|                 .is_none()); | ||||
|                 .is_err()); | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @ -1024,8 +1251,8 @@ mod test { | ||||
|             }, | ||||
|             &mut exec_state, | ||||
|         ); | ||||
|         assert!(none.coerce(&aty1, &mut exec_state).is_none()); | ||||
|         assert!(none.coerce(&aty1p, &mut exec_state).is_none()); | ||||
|         assert!(none.coerce(&aty1, &mut exec_state).is_err()); | ||||
|         assert!(none.coerce(&aty1p, &mut exec_state).is_err()); | ||||
|  | ||||
|         let tty = RuntimeType::Tuple(vec![]); | ||||
|         let tty1 = RuntimeType::Tuple(vec![RuntimeType::solid()]); | ||||
| @ -1038,7 +1265,7 @@ mod test { | ||||
|             }, | ||||
|             &mut exec_state, | ||||
|         ); | ||||
|         assert!(none.coerce(&tty1, &mut exec_state).is_none()); | ||||
|         assert!(none.coerce(&tty1, &mut exec_state).is_err()); | ||||
|  | ||||
|         let oty = RuntimeType::Object(vec![]); | ||||
|         assert_coerce_results( | ||||
| @ -1107,7 +1334,7 @@ mod test { | ||||
|         assert_coerce_results(&obj2, &ty0, &obj2, &mut exec_state); | ||||
|  | ||||
|         let ty1 = RuntimeType::Object(vec![("foo".to_owned(), RuntimeType::Primitive(PrimitiveType::Boolean))]); | ||||
|         assert!(&obj0.coerce(&ty1, &mut exec_state).is_none()); | ||||
|         assert!(&obj0.coerce(&ty1, &mut exec_state).is_err()); | ||||
|         assert_coerce_results(&obj1, &ty1, &obj1, &mut exec_state); | ||||
|         assert_coerce_results(&obj2, &ty1, &obj2, &mut exec_state); | ||||
|  | ||||
| @ -1119,19 +1346,19 @@ mod test { | ||||
|             ), | ||||
|             ("foo".to_owned(), RuntimeType::Primitive(PrimitiveType::Boolean)), | ||||
|         ]); | ||||
|         assert!(&obj0.coerce(&ty2, &mut exec_state).is_none()); | ||||
|         assert!(&obj1.coerce(&ty2, &mut exec_state).is_none()); | ||||
|         assert!(&obj0.coerce(&ty2, &mut exec_state).is_err()); | ||||
|         assert!(&obj1.coerce(&ty2, &mut exec_state).is_err()); | ||||
|         assert_coerce_results(&obj2, &ty2, &obj2, &mut exec_state); | ||||
|  | ||||
|         // field not present | ||||
|         let tyq = RuntimeType::Object(vec![("qux".to_owned(), RuntimeType::Primitive(PrimitiveType::Boolean))]); | ||||
|         assert!(&obj0.coerce(&tyq, &mut exec_state).is_none()); | ||||
|         assert!(&obj1.coerce(&tyq, &mut exec_state).is_none()); | ||||
|         assert!(&obj2.coerce(&tyq, &mut exec_state).is_none()); | ||||
|         assert!(&obj0.coerce(&tyq, &mut exec_state).is_err()); | ||||
|         assert!(&obj1.coerce(&tyq, &mut exec_state).is_err()); | ||||
|         assert!(&obj2.coerce(&tyq, &mut exec_state).is_err()); | ||||
|  | ||||
|         // field with different type | ||||
|         let ty1 = RuntimeType::Object(vec![("bar".to_owned(), RuntimeType::Primitive(PrimitiveType::Boolean))]); | ||||
|         assert!(&obj2.coerce(&ty1, &mut exec_state).is_none()); | ||||
|         assert!(&obj2.coerce(&ty1, &mut exec_state).is_err()); | ||||
|     } | ||||
|  | ||||
|     #[tokio::test(flavor = "multi_thread")] | ||||
| @ -1209,8 +1436,8 @@ mod test { | ||||
|         assert_coerce_results(&hom_arr, &tyh, &hom_arr, &mut exec_state); | ||||
|         assert_coerce_results(&mixed1, &tym1, &mixed1, &mut exec_state); | ||||
|         assert_coerce_results(&mixed2, &tym2, &mixed2, &mut exec_state); | ||||
|         assert!(&mixed1.coerce(&tym2, &mut exec_state).is_none()); | ||||
|         assert!(&mixed2.coerce(&tym1, &mut exec_state).is_none()); | ||||
|         assert!(&mixed1.coerce(&tym2, &mut exec_state).is_err()); | ||||
|         assert!(&mixed2.coerce(&tym1, &mut exec_state).is_err()); | ||||
|  | ||||
|         // Length subtyping | ||||
|         let tyhn = RuntimeType::Array( | ||||
| @ -1227,15 +1454,15 @@ mod test { | ||||
|         ); | ||||
|         assert_coerce_results(&hom_arr, &tyhn, &hom_arr, &mut exec_state); | ||||
|         assert_coerce_results(&hom_arr, &tyh1, &hom_arr, &mut exec_state); | ||||
|         assert!(&hom_arr.coerce(&tyh3, &mut exec_state).is_none()); | ||||
|         assert!(&hom_arr.coerce(&tyh3, &mut exec_state).is_err()); | ||||
|  | ||||
|         let hom_arr0 = KclValue::HomArray { | ||||
|             value: vec![], | ||||
|             ty: RuntimeType::Primitive(PrimitiveType::Number(NumericType::count())), | ||||
|         }; | ||||
|         assert_coerce_results(&hom_arr0, &tyhn, &hom_arr0, &mut exec_state); | ||||
|         assert!(&hom_arr0.coerce(&tyh1, &mut exec_state).is_none()); | ||||
|         assert!(&hom_arr0.coerce(&tyh3, &mut exec_state).is_none()); | ||||
|         assert!(&hom_arr0.coerce(&tyh1, &mut exec_state).is_err()); | ||||
|         assert!(&hom_arr0.coerce(&tyh3, &mut exec_state).is_err()); | ||||
|  | ||||
|         // Covariance | ||||
|         // let tyh = RuntimeType::Array(Box::new(RuntimeType::Primitive(PrimitiveType::Number(NumericType::Any))), ArrayLen::Known(4)); | ||||
| @ -1275,16 +1502,16 @@ mod test { | ||||
|         assert_coerce_results(&mixed1, &tyhn, &hom_arr_2, &mut exec_state); | ||||
|         assert_coerce_results(&mixed1, &tyh1, &hom_arr_2, &mut exec_state); | ||||
|         assert_coerce_results(&mixed0, &tyhn, &hom_arr0, &mut exec_state); | ||||
|         assert!(&mixed0.coerce(&tyh, &mut exec_state).is_none()); | ||||
|         assert!(&mixed0.coerce(&tyh1, &mut exec_state).is_none()); | ||||
|         assert!(&mixed0.coerce(&tyh, &mut exec_state).is_err()); | ||||
|         assert!(&mixed0.coerce(&tyh1, &mut exec_state).is_err()); | ||||
|  | ||||
|         // Homogehous to mixed | ||||
|         assert_coerce_results(&hom_arr_2, &tym1, &mixed1, &mut exec_state); | ||||
|         assert!(&hom_arr.coerce(&tym1, &mut exec_state).is_none()); | ||||
|         assert!(&hom_arr_2.coerce(&tym2, &mut exec_state).is_none()); | ||||
|         assert!(&hom_arr.coerce(&tym1, &mut exec_state).is_err()); | ||||
|         assert!(&hom_arr_2.coerce(&tym2, &mut exec_state).is_err()); | ||||
|  | ||||
|         assert!(&mixed0.coerce(&tym1, &mut exec_state).is_none()); | ||||
|         assert!(&mixed0.coerce(&tym2, &mut exec_state).is_none()); | ||||
|         assert!(&mixed0.coerce(&tym1, &mut exec_state).is_err()); | ||||
|         assert!(&mixed0.coerce(&tym2, &mut exec_state).is_err()); | ||||
|     } | ||||
|  | ||||
|     #[tokio::test(flavor = "multi_thread")] | ||||
| @ -1334,8 +1561,8 @@ mod test { | ||||
|             RuntimeType::Primitive(PrimitiveType::Boolean), | ||||
|             RuntimeType::Primitive(PrimitiveType::String), | ||||
|         ]); | ||||
|         assert!(count.coerce(&tyb, &mut exec_state).is_none()); | ||||
|         assert!(count.coerce(&tyb2, &mut exec_state).is_none()); | ||||
|         assert!(count.coerce(&tyb, &mut exec_state).is_err()); | ||||
|         assert!(count.coerce(&tyb2, &mut exec_state).is_err()); | ||||
|     } | ||||
|  | ||||
|     #[tokio::test(flavor = "multi_thread")] | ||||
| @ -1450,6 +1677,192 @@ mod test { | ||||
|         assert_coerce_results(&a2d, &ty2d, &a2d, &mut exec_state); | ||||
|         assert_coerce_results(&a3d, &ty3d, &a3d, &mut exec_state); | ||||
|         assert_coerce_results(&a3d, &ty2d, &a2d, &mut exec_state); | ||||
|         assert!(a2d.coerce(&ty3d, &mut exec_state).is_none()); | ||||
|         assert!(a2d.coerce(&ty3d, &mut exec_state).is_err()); | ||||
|     } | ||||
|  | ||||
|     #[tokio::test(flavor = "multi_thread")] | ||||
|     async fn coerce_numeric() { | ||||
|         let mut exec_state = ExecState::new(&crate::ExecutorContext::new_mock().await); | ||||
|  | ||||
|         let count = KclValue::Number { | ||||
|             value: 1.0, | ||||
|             ty: NumericType::count(), | ||||
|             meta: Vec::new(), | ||||
|         }; | ||||
|         let mm = KclValue::Number { | ||||
|             value: 1.0, | ||||
|             ty: NumericType::mm(), | ||||
|             meta: Vec::new(), | ||||
|         }; | ||||
|         let inches = KclValue::Number { | ||||
|             value: 1.0, | ||||
|             ty: NumericType::Known(UnitType::Length(UnitLen::Inches)), | ||||
|             meta: Vec::new(), | ||||
|         }; | ||||
|         let rads = KclValue::Number { | ||||
|             value: 1.0, | ||||
|             ty: NumericType::Known(UnitType::Angle(UnitAngle::Radians)), | ||||
|             meta: Vec::new(), | ||||
|         }; | ||||
|         let default = KclValue::Number { | ||||
|             value: 1.0, | ||||
|             ty: NumericType::default(), | ||||
|             meta: Vec::new(), | ||||
|         }; | ||||
|         let any = KclValue::Number { | ||||
|             value: 1.0, | ||||
|             ty: NumericType::Any, | ||||
|             meta: Vec::new(), | ||||
|         }; | ||||
|         let unknown = KclValue::Number { | ||||
|             value: 1.0, | ||||
|             ty: NumericType::Unknown, | ||||
|             meta: Vec::new(), | ||||
|         }; | ||||
|  | ||||
|         // Trivial coercions | ||||
|         assert_coerce_results(&count, &NumericType::count().into(), &count, &mut exec_state); | ||||
|         assert_coerce_results(&mm, &NumericType::mm().into(), &mm, &mut exec_state); | ||||
|         assert_coerce_results(&any, &NumericType::Any.into(), &any, &mut exec_state); | ||||
|         assert_coerce_results(&unknown, &NumericType::Unknown.into(), &unknown, &mut exec_state); | ||||
|         assert_coerce_results(&default, &NumericType::default().into(), &default, &mut exec_state); | ||||
|  | ||||
|         assert_coerce_results(&count, &NumericType::Any.into(), &count, &mut exec_state); | ||||
|         assert_coerce_results(&mm, &NumericType::Any.into(), &mm, &mut exec_state); | ||||
|         assert_coerce_results(&unknown, &NumericType::Any.into(), &unknown, &mut exec_state); | ||||
|         assert_coerce_results(&default, &NumericType::Any.into(), &default, &mut exec_state); | ||||
|  | ||||
|         if !*CHECK_NUMERIC_TYPES { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         assert_eq!( | ||||
|             default | ||||
|                 .coerce( | ||||
|                     &NumericType::Default { | ||||
|                         len: UnitLen::Yards, | ||||
|                         angle: UnitAngle::default() | ||||
|                     } | ||||
|                     .into(), | ||||
|                     &mut exec_state | ||||
|                 ) | ||||
|                 .unwrap(), | ||||
|             default | ||||
|         ); | ||||
|  | ||||
|         // No coercion | ||||
|         assert!(count.coerce(&NumericType::mm().into(), &mut exec_state).is_err()); | ||||
|         assert!(mm.coerce(&NumericType::count().into(), &mut exec_state).is_err()); | ||||
|         assert!(unknown.coerce(&NumericType::mm().into(), &mut exec_state).is_err()); | ||||
|         assert!(unknown.coerce(&NumericType::default().into(), &mut exec_state).is_err()); | ||||
|  | ||||
|         assert!(count.coerce(&NumericType::Unknown.into(), &mut exec_state).is_err()); | ||||
|         assert!(mm.coerce(&NumericType::Unknown.into(), &mut exec_state).is_err()); | ||||
|         assert!(default.coerce(&NumericType::Unknown.into(), &mut exec_state).is_err()); | ||||
|  | ||||
|         assert_eq!( | ||||
|             inches | ||||
|                 .coerce(&NumericType::mm().into(), &mut exec_state) | ||||
|                 .unwrap() | ||||
|                 .as_f64() | ||||
|                 .unwrap() | ||||
|                 .round(), | ||||
|             25.0 | ||||
|         ); | ||||
|         assert_eq!( | ||||
|             rads.coerce( | ||||
|                 &NumericType::Known(UnitType::Angle(UnitAngle::Degrees)).into(), | ||||
|                 &mut exec_state | ||||
|             ) | ||||
|             .unwrap() | ||||
|             .as_f64() | ||||
|             .unwrap() | ||||
|             .round(), | ||||
|             57.0 | ||||
|         ); | ||||
|         assert_eq!( | ||||
|             inches | ||||
|                 .coerce(&NumericType::default().into(), &mut exec_state) | ||||
|                 .unwrap() | ||||
|                 .as_f64() | ||||
|                 .unwrap() | ||||
|                 .round(), | ||||
|             25.0 | ||||
|         ); | ||||
|         assert_eq!( | ||||
|             rads.coerce(&NumericType::default().into(), &mut exec_state) | ||||
|                 .unwrap() | ||||
|                 .as_f64() | ||||
|                 .unwrap() | ||||
|                 .round(), | ||||
|             57.0 | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     #[track_caller] | ||||
|     fn assert_value_and_type(name: &str, result: &ExecTestResults, expected: f64, expected_ty: NumericType) { | ||||
|         let mem = result.exec_state.stack(); | ||||
|         match mem | ||||
|             .memory | ||||
|             .get_from(name, result.mem_env, SourceRange::default(), 0) | ||||
|             .unwrap() | ||||
|         { | ||||
|             KclValue::Number { value, ty, .. } => { | ||||
|                 assert_eq!(value.round(), expected); | ||||
|                 assert_eq!(*ty, expected_ty); | ||||
|             } | ||||
|             _ => unreachable!(), | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     #[tokio::test(flavor = "multi_thread")] | ||||
|     async fn combine_numeric() { | ||||
|         let program = r#"a = 5 + 4 | ||||
| b = 5 - 2 | ||||
| c = 5mm - 2mm + 10mm | ||||
| d = 5mm - 2 + 10 | ||||
| e = 5 - 2mm + 10 | ||||
| f = 30mm - 1inch | ||||
|  | ||||
| g = 2 * 10 | ||||
| h = 2 * 10mm | ||||
| i = 2mm * 10mm | ||||
| j = 2_ * 10 | ||||
| k = 2_ * 3mm * 3mm | ||||
|  | ||||
| l = 1 / 10 | ||||
| m = 2mm / 1mm | ||||
| n = 10inch / 2mm | ||||
| o = 3mm / 3 | ||||
| p = 3_ / 4 | ||||
| q = 4inch / 2_ | ||||
| "#; | ||||
|  | ||||
|         let result = parse_execute(program).await.unwrap(); | ||||
|         if *CHECK_NUMERIC_TYPES { | ||||
|             assert_eq!(result.exec_state.errors().len(), 2); | ||||
|         } else { | ||||
|             assert!(result.exec_state.errors().is_empty()); | ||||
|         } | ||||
|  | ||||
|         assert_value_and_type("a", &result, 9.0, NumericType::default()); | ||||
|         assert_value_and_type("b", &result, 3.0, NumericType::default()); | ||||
|         assert_value_and_type("c", &result, 13.0, NumericType::mm()); | ||||
|         assert_value_and_type("d", &result, 13.0, NumericType::mm()); | ||||
|         assert_value_and_type("e", &result, 13.0, NumericType::mm()); | ||||
|         assert_value_and_type("f", &result, 5.0, NumericType::mm()); | ||||
|  | ||||
|         assert_value_and_type("g", &result, 20.0, NumericType::default()); | ||||
|         assert_value_and_type("h", &result, 20.0, NumericType::mm()); | ||||
|         assert_value_and_type("i", &result, 20.0, NumericType::Unknown); | ||||
|         assert_value_and_type("j", &result, 20.0, NumericType::default()); | ||||
|         assert_value_and_type("k", &result, 18.0, NumericType::Unknown); | ||||
|  | ||||
|         assert_value_and_type("l", &result, 0.0, NumericType::count()); | ||||
|         assert_value_and_type("m", &result, 2.0, NumericType::count()); | ||||
|         assert_value_and_type("n", &result, 127.0, NumericType::count()); | ||||
|         assert_value_and_type("o", &result, 1.0, NumericType::mm()); | ||||
|         assert_value_and_type("p", &result, 1.0, NumericType::count()); | ||||
|         assert_value_and_type("q", &result, 2.0, NumericType::Known(UnitType::Length(UnitLen::Inches))); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -8,7 +8,7 @@ use kcmc::{ | ||||
| }; | ||||
| use kittycad_modeling_cmds as kcmc; | ||||
| use schemars::JsonSchema; | ||||
| use serde::{Deserialize, Serialize}; | ||||
| use serde::Serialize; | ||||
|  | ||||
| use crate::{ | ||||
|     errors::{KclError, KclErrorDetails}, | ||||
| @ -72,7 +72,7 @@ impl KwArgs { | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS)] | ||||
| #[derive(Debug, Clone, Serialize, PartialEq, ts_rs::TS)] | ||||
| #[ts(export)] | ||||
| #[serde(rename_all = "camelCase")] | ||||
| pub struct TyF64 { | ||||
| @ -92,7 +92,7 @@ impl TyF64 { | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     pub fn map(mut self, n: f64) -> Self { | ||||
|     pub fn map_value(mut self, n: f64) -> Self { | ||||
|         self.n = n; | ||||
|         self | ||||
|     } | ||||
| @ -209,7 +209,7 @@ impl Args { | ||||
|             })); | ||||
|         }; | ||||
|  | ||||
|         let arg = arg.value.coerce(ty, exec_state).ok_or_else(|| { | ||||
|         let arg = arg.value.coerce(ty, exec_state).map_err(|_| { | ||||
|             let actual_type_name = arg.value.human_friendly_type(); | ||||
|             let msg_base = format!( | ||||
|                 "This function expected the input argument to be {} but it's actually of type {actual_type_name}", | ||||
| @ -332,7 +332,7 @@ impl Args { | ||||
|                 message: format!("This function requires a value for the special unlabeled first parameter, '{label}'"), | ||||
|             }))?; | ||||
|  | ||||
|         let arg = arg.value.coerce(ty, exec_state).ok_or_else(|| { | ||||
|         let arg = arg.value.coerce(ty, exec_state).map_err(|_| { | ||||
|             let actual_type_name = arg.value.human_friendly_type(); | ||||
|             let msg_base = format!( | ||||
|                 "This function expected the input argument to be {} but it's actually of type {actual_type_name}", | ||||
| @ -523,7 +523,7 @@ impl Args { | ||||
|         }) | ||||
|     } | ||||
|  | ||||
|     pub(crate) fn make_user_val_from_f64(&self, f: f64) -> KclValue { | ||||
|     pub(super) fn make_user_val_from_f64(&self, f: f64) -> KclValue { | ||||
|         KclValue::from_number( | ||||
|             f, | ||||
|             vec![Metadata { | ||||
| @ -532,7 +532,7 @@ impl Args { | ||||
|         ) | ||||
|     } | ||||
|  | ||||
|     pub(crate) fn make_user_val_from_f64_with_type(&self, f: TyF64) -> KclValue { | ||||
|     pub(super) fn make_user_val_from_f64_with_type(&self, f: TyF64) -> KclValue { | ||||
|         KclValue::from_number_with_type( | ||||
|             f.n, | ||||
|             f.ty, | ||||
| @ -542,7 +542,7 @@ impl Args { | ||||
|         ) | ||||
|     } | ||||
|  | ||||
|     pub(crate) fn make_user_val_from_f64_array(&self, f: Vec<f64>, ty: &NumericType) -> Result<KclValue, KclError> { | ||||
|     pub(super) fn make_user_val_from_f64_array(&self, f: Vec<f64>, ty: &NumericType) -> Result<KclValue, KclError> { | ||||
|         let array = f | ||||
|             .into_iter() | ||||
|             .map(|n| KclValue::Number { | ||||
| @ -616,8 +616,7 @@ impl Args { | ||||
|         let mut numbers = numbers.into_iter(); | ||||
|         let a = numbers.next().unwrap(); | ||||
|         let b = numbers.next().unwrap(); | ||||
|         let ty = a.ty.combine_eq(&b.ty); | ||||
|         Ok((a.n, b.n, ty)) | ||||
|         Ok(NumericType::combine_eq(a, b)) | ||||
|     } | ||||
|  | ||||
|     pub(crate) fn get_sketches(&self, exec_state: &mut ExecState) -> Result<(Vec<Sketch>, Sketch), KclError> { | ||||
| @ -627,16 +626,15 @@ impl Args { | ||||
|                 source_ranges: vec![self.source_range], | ||||
|             })); | ||||
|         }; | ||||
|         let sarg = arg0 | ||||
|             .value | ||||
|             .coerce(&RuntimeType::sketches(), exec_state) | ||||
|             .ok_or(KclError::Type(KclErrorDetails { | ||||
|         let sarg = arg0.value.coerce(&RuntimeType::sketches(), exec_state).map_err(|_| { | ||||
|             KclError::Type(KclErrorDetails { | ||||
|                 message: format!( | ||||
|                     "Expected an array of sketches, found {}", | ||||
|                     arg0.value.human_friendly_type() | ||||
|                 ), | ||||
|                 source_ranges: vec![self.source_range], | ||||
|             }))?; | ||||
|             }) | ||||
|         })?; | ||||
|         let sketches = match sarg { | ||||
|             KclValue::HomArray { value, .. } => value.iter().map(|v| v.as_sketch().unwrap().clone()).collect(), | ||||
|             _ => unreachable!(), | ||||
| @ -651,10 +649,12 @@ impl Args { | ||||
|         let sarg = arg1 | ||||
|             .value | ||||
|             .coerce(&RuntimeType::Primitive(PrimitiveType::Sketch), exec_state) | ||||
|             .ok_or(KclError::Type(KclErrorDetails { | ||||
|                 message: format!("Expected a sketch, found {}", arg1.value.human_friendly_type()), | ||||
|                 source_ranges: vec![self.source_range], | ||||
|             }))?; | ||||
|             .map_err(|_| { | ||||
|                 KclError::Type(KclErrorDetails { | ||||
|                     message: format!("Expected a sketch, found {}", arg1.value.human_friendly_type()), | ||||
|                     source_ranges: vec![self.source_range], | ||||
|                 }) | ||||
|             })?; | ||||
|         let sketch = match sarg { | ||||
|             KclValue::Sketch { value } => *value, | ||||
|             _ => unreachable!(), | ||||
| @ -673,10 +673,12 @@ impl Args { | ||||
|         let sarg = arg0 | ||||
|             .value | ||||
|             .coerce(&RuntimeType::Primitive(PrimitiveType::Sketch), exec_state) | ||||
|             .ok_or(KclError::Type(KclErrorDetails { | ||||
|                 message: format!("Expected a sketch, found {}", arg0.value.human_friendly_type()), | ||||
|                 source_ranges: vec![self.source_range], | ||||
|             }))?; | ||||
|             .map_err(|_| { | ||||
|                 KclError::Type(KclErrorDetails { | ||||
|                     message: format!("Expected a sketch, found {}", arg0.value.human_friendly_type()), | ||||
|                     source_ranges: vec![self.source_range], | ||||
|                 }) | ||||
|             })?; | ||||
|         match sarg { | ||||
|             KclValue::Sketch { value } => Ok(*value), | ||||
|             _ => unreachable!(), | ||||
| @ -718,13 +720,15 @@ impl Args { | ||||
|         let sarg = arg1 | ||||
|             .value | ||||
|             .coerce(&RuntimeType::Primitive(PrimitiveType::Sketch), exec_state) | ||||
|             .ok_or(KclError::Type(KclErrorDetails { | ||||
|                 message: format!( | ||||
|                     "Expected a sketch for second argument, found {}", | ||||
|                     arg1.value.human_friendly_type() | ||||
|                 ), | ||||
|                 source_ranges: vec![self.source_range], | ||||
|             }))?; | ||||
|             .map_err(|_| { | ||||
|                 KclError::Type(KclErrorDetails { | ||||
|                     message: format!( | ||||
|                         "Expected a sketch for second argument, found {}", | ||||
|                         arg1.value.human_friendly_type() | ||||
|                     ), | ||||
|                     source_ranges: vec![self.source_range], | ||||
|                 }) | ||||
|             })?; | ||||
|         let sketch = match sarg { | ||||
|             KclValue::Sketch { value } => *value, | ||||
|             _ => unreachable!(), | ||||
| @ -754,13 +758,15 @@ impl Args { | ||||
|         let sarg = arg1 | ||||
|             .value | ||||
|             .coerce(&RuntimeType::Primitive(PrimitiveType::Solid), exec_state) | ||||
|             .ok_or(KclError::Type(KclErrorDetails { | ||||
|                 message: format!( | ||||
|                     "Expected a solid for second argument, found {}", | ||||
|                     arg1.value.human_friendly_type() | ||||
|                 ), | ||||
|                 source_ranges: vec![self.source_range], | ||||
|             }))?; | ||||
|             .map_err(|_| { | ||||
|                 KclError::Type(KclErrorDetails { | ||||
|                     message: format!( | ||||
|                         "Expected a solid for second argument, found {}", | ||||
|                         arg1.value.human_friendly_type() | ||||
|                     ), | ||||
|                     source_ranges: vec![self.source_range], | ||||
|                 }) | ||||
|             })?; | ||||
|         let solid = match sarg { | ||||
|             KclValue::Solid { value } => value, | ||||
|             _ => unreachable!(), | ||||
|  | ||||
| @ -13,7 +13,7 @@ pub async fn int(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, Kc | ||||
|     let num = args.get_number_with_type()?; | ||||
|     let converted = inner_int(num.n)?; | ||||
|  | ||||
|     Ok(args.make_user_val_from_f64_with_type(num.map(converted))) | ||||
|     Ok(args.make_user_val_from_f64_with_type(num.map_value(converted))) | ||||
| } | ||||
|  | ||||
| /// Convert a number to an integer. | ||||
|  | ||||
| @ -8,7 +8,7 @@ use serde::{Deserialize, Serialize}; | ||||
| use crate::{ | ||||
|     errors::KclError, | ||||
|     execution::{ExecState, KclValue}, | ||||
|     std::args::{Args, TyF64}, | ||||
|     std::args::Args, | ||||
| }; | ||||
|  | ||||
| /// Data for polar coordinates. | ||||
| @ -19,7 +19,7 @@ pub struct PolarCoordsData { | ||||
|     /// The angle of the line (in degrees). | ||||
|     pub angle: f64, | ||||
|     /// The length of the line. | ||||
|     pub length: TyF64, | ||||
|     pub length: f64, | ||||
| } | ||||
|  | ||||
| /// Convert from polar/sphere coordinates to cartesian coordinates. | ||||
| @ -27,7 +27,7 @@ pub async fn polar(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, | ||||
|     let data: PolarCoordsData = args.get_data()?; | ||||
|     let result = inner_polar(&data)?; | ||||
|  | ||||
|     args.make_user_val_from_f64_array(result.to_vec(), &data.length.ty) | ||||
|     args.make_user_val_from_f64_array(result.to_vec(), &crate::execution::types::NumericType::Unknown) | ||||
| } | ||||
|  | ||||
| /// Convert polar/sphere (azimuth, elevation, distance) coordinates to | ||||
| @ -49,7 +49,7 @@ pub async fn polar(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, | ||||
| }] | ||||
| fn inner_polar(data: &PolarCoordsData) -> Result<[f64; 2], KclError> { | ||||
|     let angle = data.angle.to_radians(); | ||||
|     let x = data.length.n * angle.cos(); | ||||
|     let y = data.length.n * angle.sin(); | ||||
|     let x = data.length * angle.cos(); | ||||
|     let y = data.length * angle.sin(); | ||||
|     Ok([x, y]) | ||||
| } | ||||
|  | ||||
| @ -7,7 +7,7 @@ | ||||
| /// circumference = 70 | ||||
| /// | ||||
| /// exampleSketch = startSketchOn(XZ) | ||||
| ///  |> circle(center = [0, 0], radius = circumference/ (2 * PI)) | ||||
| ///  |> circle(center = [0, 0], radius = circumference / (2 * PI)) | ||||
| /// | ||||
| /// example = extrude(exampleSketch, length = 5) | ||||
| /// ``` | ||||
|  | ||||
| @ -1,4 +1,5 @@ | ||||
| @no_std | ||||
| @settings(defaultLengthUnit = mm) | ||||
|  | ||||
| /// Construct a 2-dimensional circle, of the specified radius, centered at | ||||
| /// the provided (x, y) origin point. | ||||
|  | ||||
| @ -42,21 +42,24 @@ description: Variables in memory after executing double_map_fn.kcl | ||||
|         "type": "Number", | ||||
|         "value": 2.0, | ||||
|         "ty": { | ||||
|           "type": "Unknown" | ||||
|           "type": "Known", | ||||
|           "type": "Count" | ||||
|         } | ||||
|       }, | ||||
|       { | ||||
|         "type": "Number", | ||||
|         "value": 3.0, | ||||
|         "ty": { | ||||
|           "type": "Unknown" | ||||
|           "type": "Known", | ||||
|           "type": "Count" | ||||
|         } | ||||
|       }, | ||||
|       { | ||||
|         "type": "Number", | ||||
|         "value": 4.0, | ||||
|         "ty": { | ||||
|           "type": "Unknown" | ||||
|           "type": "Known", | ||||
|           "type": "Count" | ||||
|         } | ||||
|       } | ||||
|     ] | ||||
|  | ||||
| @ -307,7 +307,13 @@ description: Variables in memory after executing fillet-and-shell.kcl | ||||
|     "type": "Number", | ||||
|     "value": 73.0, | ||||
|     "ty": { | ||||
|       "type": "Unknown" | ||||
|       "type": "Default", | ||||
|       "len": { | ||||
|         "type": "Mm" | ||||
|       }, | ||||
|       "angle": { | ||||
|         "type": "Degrees" | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   "caseThickness": { | ||||
| @ -327,7 +333,13 @@ description: Variables in memory after executing fillet-and-shell.kcl | ||||
|     "type": "Number", | ||||
|     "value": 38.0, | ||||
|     "ty": { | ||||
|       "type": "Unknown" | ||||
|       "type": "Default", | ||||
|       "len": { | ||||
|         "type": "Mm" | ||||
|       }, | ||||
|       "angle": { | ||||
|         "type": "Degrees" | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   "connectorPadding": { | ||||
| @ -367,7 +379,13 @@ description: Variables in memory after executing fillet-and-shell.kcl | ||||
|     "type": "Number", | ||||
|     "value": 58.0, | ||||
|     "ty": { | ||||
|       "type": "Unknown" | ||||
|       "type": "Default", | ||||
|       "len": { | ||||
|         "type": "Mm" | ||||
|       }, | ||||
|       "angle": { | ||||
|         "type": "Degrees" | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   "m25Screw": { | ||||
|  | ||||
| @ -51,7 +51,8 @@ description: Operations executed flush_batch_on_end.kcl | ||||
|           "type": "Number", | ||||
|           "value": 1.5, | ||||
|           "ty": { | ||||
|             "type": "Unknown" | ||||
|             "type": "Known", | ||||
|             "type": "Count" | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
|  | ||||
| @ -128,14 +128,16 @@ description: Variables in memory after executing flush_batch_on_end.kcl | ||||
|     "type": "Number", | ||||
|     "value": 1.5, | ||||
|     "ty": { | ||||
|       "type": "Unknown" | ||||
|       "type": "Known", | ||||
|       "type": "Count" | ||||
|     } | ||||
|   }, | ||||
|   "outerDiameter": { | ||||
|     "type": "Number", | ||||
|     "value": 0.5469, | ||||
|     "ty": { | ||||
|       "type": "Unknown" | ||||
|       "type": "Known", | ||||
|       "type": "Count" | ||||
|     } | ||||
|   }, | ||||
|   "outerProfile": { | ||||
|  | ||||
| @ -10,7 +10,8 @@ description: Operations executed ball-bearing.kcl | ||||
|           "type": "Number", | ||||
|           "value": -0.1565, | ||||
|           "ty": { | ||||
|             "type": "Unknown" | ||||
|             "type": "Known", | ||||
|             "type": "Count" | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
| @ -666,7 +667,8 @@ description: Operations executed ball-bearing.kcl | ||||
|           "type": "Number", | ||||
|           "value": 36.0, | ||||
|           "ty": { | ||||
|             "type": "Unknown" | ||||
|             "type": "Known", | ||||
|             "type": "Count" | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
| @ -900,7 +902,8 @@ description: Operations executed ball-bearing.kcl | ||||
|           "type": "Number", | ||||
|           "value": -0.1565, | ||||
|           "ty": { | ||||
|             "type": "Unknown" | ||||
|             "type": "Known", | ||||
|             "type": "Count" | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
|  | ||||
| @ -3425,14 +3425,16 @@ description: Variables in memory after executing ball-bearing.kcl | ||||
|     "type": "Number", | ||||
|     "value": 0.0313, | ||||
|     "ty": { | ||||
|       "type": "Unknown" | ||||
|       "type": "Known", | ||||
|       "type": "Count" | ||||
|     } | ||||
|   }, | ||||
|   "chainWidth": { | ||||
|     "type": "Number", | ||||
|     "value": 0.125, | ||||
|     "ty": { | ||||
|       "type": "Unknown" | ||||
|       "type": "Known", | ||||
|       "type": "Count" | ||||
|     } | ||||
|   }, | ||||
|   "insideWall": { | ||||
| @ -3631,7 +3633,8 @@ description: Variables in memory after executing ball-bearing.kcl | ||||
|     "type": "Number", | ||||
|     "value": 0.0625, | ||||
|     "ty": { | ||||
|       "type": "Unknown" | ||||
|       "type": "Known", | ||||
|       "type": "Count" | ||||
|     } | ||||
|   }, | ||||
|   "linkRevolve": { | ||||
|  | ||||
| @ -58,7 +58,8 @@ description: Operations executed bench.kcl | ||||
|           "type": "Number", | ||||
|           "value": 2.0, | ||||
|           "ty": { | ||||
|             "type": "Unknown" | ||||
|             "type": "Known", | ||||
|             "type": "Count" | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
| @ -117,7 +118,8 @@ description: Operations executed bench.kcl | ||||
|           "type": "Number", | ||||
|           "value": -2.0, | ||||
|           "ty": { | ||||
|             "type": "Unknown" | ||||
|             "type": "Known", | ||||
|             "type": "Count" | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
| @ -234,7 +236,8 @@ description: Operations executed bench.kcl | ||||
|           "type": "Number", | ||||
|           "value": 28.0, | ||||
|           "ty": { | ||||
|             "type": "Unknown" | ||||
|             "type": "Known", | ||||
|             "type": "Count" | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
| @ -306,7 +309,8 @@ description: Operations executed bench.kcl | ||||
|           "type": "Number", | ||||
|           "value": 2.0, | ||||
|           "ty": { | ||||
|             "type": "Unknown" | ||||
|             "type": "Known", | ||||
|             "type": "Count" | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
| @ -365,7 +369,8 @@ description: Operations executed bench.kcl | ||||
|           "type": "Number", | ||||
|           "value": -2.0, | ||||
|           "ty": { | ||||
|             "type": "Unknown" | ||||
|             "type": "Known", | ||||
|             "type": "Count" | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
| @ -482,7 +487,8 @@ description: Operations executed bench.kcl | ||||
|           "type": "Number", | ||||
|           "value": 28.0, | ||||
|           "ty": { | ||||
|             "type": "Unknown" | ||||
|             "type": "Known", | ||||
|             "type": "Count" | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
| @ -554,7 +560,8 @@ description: Operations executed bench.kcl | ||||
|           "type": "Number", | ||||
|           "value": 2.0, | ||||
|           "ty": { | ||||
|             "type": "Unknown" | ||||
|             "type": "Known", | ||||
|             "type": "Count" | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
| @ -613,7 +620,8 @@ description: Operations executed bench.kcl | ||||
|           "type": "Number", | ||||
|           "value": -2.0, | ||||
|           "ty": { | ||||
|             "type": "Unknown" | ||||
|             "type": "Known", | ||||
|             "type": "Count" | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
| @ -730,7 +738,8 @@ description: Operations executed bench.kcl | ||||
|           "type": "Number", | ||||
|           "value": -28.0, | ||||
|           "ty": { | ||||
|             "type": "Unknown" | ||||
|             "type": "Known", | ||||
|             "type": "Count" | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
| @ -902,7 +911,8 @@ description: Operations executed bench.kcl | ||||
|           "type": "Number", | ||||
|           "value": -30.0, | ||||
|           "ty": { | ||||
|             "type": "Unknown" | ||||
|             "type": "Known", | ||||
|             "type": "Count" | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
| @ -1026,7 +1036,8 @@ description: Operations executed bench.kcl | ||||
|           "type": "Number", | ||||
|           "value": -30.0, | ||||
|           "ty": { | ||||
|             "type": "Unknown" | ||||
|             "type": "Known", | ||||
|             "type": "Count" | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
| @ -1159,7 +1170,8 @@ description: Operations executed bench.kcl | ||||
|           "type": "Number", | ||||
|           "value": 28.0, | ||||
|           "ty": { | ||||
|             "type": "Unknown" | ||||
|             "type": "Known", | ||||
|             "type": "Count" | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
| @ -1322,7 +1334,8 @@ description: Operations executed bench.kcl | ||||
|           "type": "Number", | ||||
|           "value": -28.0, | ||||
|           "ty": { | ||||
|             "type": "Unknown" | ||||
|             "type": "Known", | ||||
|             "type": "Count" | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
|  | ||||
| @ -40,7 +40,13 @@ description: Variables in memory after executing bracket.kcl | ||||
|     "type": "Number", | ||||
|     "value": 3600.0, | ||||
|     "ty": { | ||||
|       "type": "Unknown" | ||||
|       "type": "Default", | ||||
|       "len": { | ||||
|         "type": "Mm" | ||||
|       }, | ||||
|       "angle": { | ||||
|         "type": "Degrees" | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   "mountingHoleDiameter": { | ||||
|  | ||||
| @ -231,7 +231,13 @@ description: Operations executed car-wheel-assembly.kcl | ||||
|           "type": "Number", | ||||
|           "value": 0.5, | ||||
|           "ty": { | ||||
|             "type": "Unknown" | ||||
|             "type": "Default", | ||||
|             "len": { | ||||
|               "type": "Inches" | ||||
|             }, | ||||
|             "angle": { | ||||
|               "type": "Degrees" | ||||
|             } | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
| @ -422,7 +428,13 @@ description: Operations executed car-wheel-assembly.kcl | ||||
|           "type": "Number", | ||||
|           "value": 0.5, | ||||
|           "ty": { | ||||
|             "type": "Unknown" | ||||
|             "type": "Default", | ||||
|             "len": { | ||||
|               "type": "Inches" | ||||
|             }, | ||||
|             "angle": { | ||||
|               "type": "Degrees" | ||||
|             } | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
| @ -567,7 +579,8 @@ description: Operations executed car-wheel-assembly.kcl | ||||
|           "type": "Number", | ||||
|           "value": -0.125, | ||||
|           "ty": { | ||||
|             "type": "Unknown" | ||||
|             "type": "Known", | ||||
|             "type": "Count" | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
| @ -646,7 +659,8 @@ description: Operations executed car-wheel-assembly.kcl | ||||
|           "type": "Number", | ||||
|           "value": -0.125, | ||||
|           "ty": { | ||||
|             "type": "Unknown" | ||||
|             "type": "Known", | ||||
|             "type": "Count" | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
| @ -754,7 +768,8 @@ description: Operations executed car-wheel-assembly.kcl | ||||
|           "type": "Number", | ||||
|           "value": 0.475, | ||||
|           "ty": { | ||||
|             "type": "Unknown" | ||||
|             "type": "Known", | ||||
|             "type": "Count" | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
| @ -830,7 +845,8 @@ description: Operations executed car-wheel-assembly.kcl | ||||
|           "type": "Number", | ||||
|           "value": 0.95, | ||||
|           "ty": { | ||||
|             "type": "Unknown" | ||||
|             "type": "Known", | ||||
|             "type": "Count" | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
| @ -880,7 +896,8 @@ description: Operations executed car-wheel-assembly.kcl | ||||
|           "type": "Number", | ||||
|           "value": -0.95, | ||||
|           "ty": { | ||||
|             "type": "Unknown" | ||||
|             "type": "Known", | ||||
|             "type": "Count" | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
| @ -959,7 +976,8 @@ description: Operations executed car-wheel-assembly.kcl | ||||
|           "type": "Number", | ||||
|           "value": -0.475, | ||||
|           "ty": { | ||||
|             "type": "Unknown" | ||||
|             "type": "Known", | ||||
|             "type": "Count" | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
| @ -1266,7 +1284,8 @@ description: Operations executed car-wheel-assembly.kcl | ||||
|                       "type": "Number", | ||||
|                       "value": 0.1, | ||||
|                       "ty": { | ||||
|                         "type": "Unknown" | ||||
|                         "type": "Known", | ||||
|                         "type": "Count" | ||||
|                       } | ||||
|                     } | ||||
|                   ] | ||||
| @ -1656,7 +1675,8 @@ description: Operations executed car-wheel-assembly.kcl | ||||
|                       "type": "Number", | ||||
|                       "value": -0.1, | ||||
|                       "ty": { | ||||
|                         "type": "Unknown" | ||||
|                         "type": "Known", | ||||
|                         "type": "Count" | ||||
|                       } | ||||
|                     } | ||||
|                   ] | ||||
|  | ||||
| @ -302,7 +302,13 @@ description: Variables in memory after executing car-wheel-assembly.kcl | ||||
|     "type": "Number", | ||||
|     "value": 0.5, | ||||
|     "ty": { | ||||
|       "type": "Unknown" | ||||
|       "type": "Default", | ||||
|       "len": { | ||||
|         "type": "Inches" | ||||
|       }, | ||||
|       "angle": { | ||||
|         "type": "Degrees" | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   "spacerPatternDiameter": { | ||||
|  | ||||
| @ -10,7 +10,8 @@ description: Operations executed color-cube.kcl | ||||
|           "type": "Number", | ||||
|           "value": 50.0, | ||||
|           "ty": { | ||||
|             "type": "Unknown" | ||||
|             "type": "Known", | ||||
|             "type": "Count" | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
| @ -34,7 +35,8 @@ description: Operations executed color-cube.kcl | ||||
|           "type": "Number", | ||||
|           "value": -50.0, | ||||
|           "ty": { | ||||
|             "type": "Unknown" | ||||
|             "type": "Known", | ||||
|             "type": "Count" | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
| @ -58,7 +60,8 @@ description: Operations executed color-cube.kcl | ||||
|           "type": "Number", | ||||
|           "value": -50.0, | ||||
|           "ty": { | ||||
|             "type": "Unknown" | ||||
|             "type": "Known", | ||||
|             "type": "Count" | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
| @ -82,7 +85,8 @@ description: Operations executed color-cube.kcl | ||||
|           "type": "Number", | ||||
|           "value": -50.0, | ||||
|           "ty": { | ||||
|             "type": "Unknown" | ||||
|             "type": "Known", | ||||
|             "type": "Count" | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
| @ -106,7 +110,8 @@ description: Operations executed color-cube.kcl | ||||
|           "type": "Number", | ||||
|           "value": 49.0, | ||||
|           "ty": { | ||||
|             "type": "Unknown" | ||||
|             "type": "Known", | ||||
|             "type": "Count" | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
| @ -130,7 +135,8 @@ description: Operations executed color-cube.kcl | ||||
|           "type": "Number", | ||||
|           "value": -50.0, | ||||
|           "ty": { | ||||
|             "type": "Unknown" | ||||
|             "type": "Known", | ||||
|             "type": "Count" | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
|  | ||||
| @ -82,7 +82,8 @@ description: Variables in memory after executing color-cube.kcl | ||||
|     "type": "Number", | ||||
|     "value": 50.0, | ||||
|     "ty": { | ||||
|       "type": "Unknown" | ||||
|       "type": "Known", | ||||
|       "type": "Count" | ||||
|     } | ||||
|   }, | ||||
|   "metalConstant": { | ||||
|  | ||||
| @ -201,7 +201,8 @@ description: Operations executed cycloidal-gear.kcl | ||||
|           "type": "Number", | ||||
|           "value": 0.75, | ||||
|           "ty": { | ||||
|             "type": "Unknown" | ||||
|             "type": "Known", | ||||
|             "type": "Count" | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
|  | ||||
| @ -316,7 +316,13 @@ description: Operations executed dodecahedron.kcl | ||||
|           "type": "Number", | ||||
|           "value": 5.0, | ||||
|           "ty": { | ||||
|             "type": "Unknown" | ||||
|             "type": "Default", | ||||
|             "len": { | ||||
|               "type": "Inches" | ||||
|             }, | ||||
|             "angle": { | ||||
|               "type": "Degrees" | ||||
|             } | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
| @ -342,7 +348,13 @@ description: Operations executed dodecahedron.kcl | ||||
|           "type": "Number", | ||||
|           "value": 5.0, | ||||
|           "ty": { | ||||
|             "type": "Unknown" | ||||
|             "type": "Default", | ||||
|             "len": { | ||||
|               "type": "Inches" | ||||
|             }, | ||||
|             "angle": { | ||||
|               "type": "Degrees" | ||||
|             } | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
|  | ||||
| @ -1947,7 +1947,13 @@ description: Variables in memory after executing dodecahedron.kcl | ||||
|     "type": "Number", | ||||
|     "value": 5.0, | ||||
|     "ty": { | ||||
|       "type": "Unknown" | ||||
|       "type": "Default", | ||||
|       "len": { | ||||
|         "type": "Inches" | ||||
|       }, | ||||
|       "angle": { | ||||
|         "type": "Degrees" | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
| @ -1000,7 +1000,8 @@ description: Operations executed dual-basin-utility-sink.kcl | ||||
|           "type": "Number", | ||||
|           "value": 564.5, | ||||
|           "ty": { | ||||
|             "type": "Unknown" | ||||
|             "type": "Known", | ||||
|             "type": "Count" | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
| @ -1010,7 +1011,13 @@ description: Operations executed dual-basin-utility-sink.kcl | ||||
|           "type": "Number", | ||||
|           "value": 6.0, | ||||
|           "ty": { | ||||
|             "type": "Unknown" | ||||
|             "type": "Default", | ||||
|             "len": { | ||||
|               "type": "Mm" | ||||
|             }, | ||||
|             "angle": { | ||||
|               "type": "Degrees" | ||||
|             } | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
|  | ||||
| @ -59,14 +59,16 @@ description: Variables in memory after executing dual-basin-utility-sink.kcl | ||||
|     "type": "Number", | ||||
|     "value": 564.5, | ||||
|     "ty": { | ||||
|       "type": "Unknown" | ||||
|       "type": "Known", | ||||
|       "type": "Count" | ||||
|     } | ||||
|   }, | ||||
|   "blockWidth": { | ||||
|     "type": "Number", | ||||
|     "value": 1129.0, | ||||
|     "ty": { | ||||
|       "type": "Unknown" | ||||
|       "type": "Known", | ||||
|       "type": "Count" | ||||
|     } | ||||
|   }, | ||||
|   "doorBody": { | ||||
| @ -1115,7 +1117,13 @@ description: Variables in memory after executing dual-basin-utility-sink.kcl | ||||
|     "type": "Number", | ||||
|     "value": 6.0, | ||||
|     "ty": { | ||||
|       "type": "Unknown" | ||||
|       "type": "Default", | ||||
|       "len": { | ||||
|         "type": "Mm" | ||||
|       }, | ||||
|       "angle": { | ||||
|         "type": "Degrees" | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   "doorGap": { | ||||
| @ -1205,7 +1213,8 @@ description: Variables in memory after executing dual-basin-utility-sink.kcl | ||||
|     "type": "Number", | ||||
|     "value": 547.5, | ||||
|     "ty": { | ||||
|       "type": "Unknown" | ||||
|       "type": "Known", | ||||
|       "type": "Count" | ||||
|     } | ||||
|   }, | ||||
|   "floorPlane": { | ||||
| @ -1936,14 +1945,21 @@ description: Variables in memory after executing dual-basin-utility-sink.kcl | ||||
|     "type": "Number", | ||||
|     "value": 80.0, | ||||
|     "ty": { | ||||
|       "type": "Unknown" | ||||
|       "type": "Default", | ||||
|       "len": { | ||||
|         "type": "Mm" | ||||
|       }, | ||||
|       "angle": { | ||||
|         "type": "Degrees" | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   "handleOffset": { | ||||
|     "type": "Number", | ||||
|     "value": 228.75, | ||||
|     "ty": { | ||||
|       "type": "Unknown" | ||||
|       "type": "Known", | ||||
|       "type": "Count" | ||||
|     } | ||||
|   }, | ||||
|   "handlePlane": { | ||||
| @ -5106,7 +5122,8 @@ description: Variables in memory after executing dual-basin-utility-sink.kcl | ||||
|     "type": "Number", | ||||
|     "value": 1116.0, | ||||
|     "ty": { | ||||
|       "type": "Unknown" | ||||
|       "type": "Known", | ||||
|       "type": "Count" | ||||
|     } | ||||
|   }, | ||||
|   "lowerBeltLengthY": { | ||||
| @ -5540,7 +5557,13 @@ description: Variables in memory after executing dual-basin-utility-sink.kcl | ||||
|     "type": "Number", | ||||
|     "value": 7.0, | ||||
|     "ty": { | ||||
|       "type": "Unknown" | ||||
|       "type": "Default", | ||||
|       "len": { | ||||
|         "type": "Mm" | ||||
|       }, | ||||
|       "angle": { | ||||
|         "type": "Degrees" | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   "panelSpacing": { | ||||
| @ -5560,7 +5583,13 @@ description: Variables in memory after executing dual-basin-utility-sink.kcl | ||||
|     "type": "Number", | ||||
|     "value": 370.0, | ||||
|     "ty": { | ||||
|       "type": "Unknown" | ||||
|       "type": "Default", | ||||
|       "len": { | ||||
|         "type": "Mm" | ||||
|       }, | ||||
|       "angle": { | ||||
|         "type": "Degrees" | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   "pillarBody": { | ||||
| @ -8738,7 +8767,13 @@ description: Variables in memory after executing dual-basin-utility-sink.kcl | ||||
|     "type": "Number", | ||||
|     "value": 1700.0, | ||||
|     "ty": { | ||||
|       "type": "Unknown" | ||||
|       "type": "Default", | ||||
|       "len": { | ||||
|         "type": "Mm" | ||||
|       }, | ||||
|       "angle": { | ||||
|         "type": "Degrees" | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   "sinkWidth": { | ||||
|  | ||||
| @ -57,7 +57,13 @@ description: Operations executed enclosure.kcl | ||||
|           "type": "Number", | ||||
|           "value": 12.0, | ||||
|           "ty": { | ||||
|             "type": "Unknown" | ||||
|             "type": "Default", | ||||
|             "len": { | ||||
|               "type": "Mm" | ||||
|             }, | ||||
|             "angle": { | ||||
|               "type": "Degrees" | ||||
|             } | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
| @ -1394,7 +1400,13 @@ description: Operations executed enclosure.kcl | ||||
|           "type": "Number", | ||||
|           "value": 12.0, | ||||
|           "ty": { | ||||
|             "type": "Unknown" | ||||
|             "type": "Default", | ||||
|             "len": { | ||||
|               "type": "Mm" | ||||
|             }, | ||||
|             "angle": { | ||||
|               "type": "Degrees" | ||||
|             } | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
| @ -1604,7 +1616,13 @@ description: Operations executed enclosure.kcl | ||||
|           "type": "Number", | ||||
|           "value": 9.0, | ||||
|           "ty": { | ||||
|             "type": "Unknown" | ||||
|             "type": "Default", | ||||
|             "len": { | ||||
|               "type": "Mm" | ||||
|             }, | ||||
|             "angle": { | ||||
|               "type": "Degrees" | ||||
|             } | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
|  | ||||
| @ -70,7 +70,13 @@ description: Operations executed exhaust-manifold.kcl | ||||
|                       "type": "Number", | ||||
|                       "value": 0.0, | ||||
|                       "ty": { | ||||
|                         "type": "Unknown" | ||||
|                         "type": "Default", | ||||
|                         "len": { | ||||
|                           "type": "Inches" | ||||
|                         }, | ||||
|                         "angle": { | ||||
|                           "type": "Degrees" | ||||
|                         } | ||||
|                       } | ||||
|                     }, | ||||
|                     { | ||||
| @ -371,7 +377,13 @@ description: Operations executed exhaust-manifold.kcl | ||||
|                       "type": "Number", | ||||
|                       "value": 2.0, | ||||
|                       "ty": { | ||||
|                         "type": "Unknown" | ||||
|                         "type": "Default", | ||||
|                         "len": { | ||||
|                           "type": "Inches" | ||||
|                         }, | ||||
|                         "angle": { | ||||
|                           "type": "Degrees" | ||||
|                         } | ||||
|                       } | ||||
|                     }, | ||||
|                     { | ||||
| @ -672,7 +684,13 @@ description: Operations executed exhaust-manifold.kcl | ||||
|                       "type": "Number", | ||||
|                       "value": 4.0, | ||||
|                       "ty": { | ||||
|                         "type": "Unknown" | ||||
|                         "type": "Default", | ||||
|                         "len": { | ||||
|                           "type": "Inches" | ||||
|                         }, | ||||
|                         "angle": { | ||||
|                           "type": "Degrees" | ||||
|                         } | ||||
|                       } | ||||
|                     }, | ||||
|                     { | ||||
| @ -973,7 +991,13 @@ description: Operations executed exhaust-manifold.kcl | ||||
|                       "type": "Number", | ||||
|                       "value": 6.0, | ||||
|                       "ty": { | ||||
|                         "type": "Unknown" | ||||
|                         "type": "Default", | ||||
|                         "len": { | ||||
|                           "type": "Inches" | ||||
|                         }, | ||||
|                         "angle": { | ||||
|                           "type": "Degrees" | ||||
|                         } | ||||
|                       } | ||||
|                     }, | ||||
|                     { | ||||
|  | ||||
| @ -47,7 +47,8 @@ description: Operations executed focusrite-scarlett-mounting-bracket.kcl | ||||
|                       "type": "Number", | ||||
|                       "value": 44.0, | ||||
|                       "ty": { | ||||
|                         "type": "Unknown" | ||||
|                         "type": "Known", | ||||
|                         "type": "Count" | ||||
|                       } | ||||
|                     }, | ||||
|                     "z": { | ||||
| @ -219,7 +220,13 @@ description: Operations executed focusrite-scarlett-mounting-bracket.kcl | ||||
|           "type": "Number", | ||||
|           "value": 88.0, | ||||
|           "ty": { | ||||
|             "type": "Unknown" | ||||
|             "type": "Default", | ||||
|             "len": { | ||||
|               "type": "Mm" | ||||
|             }, | ||||
|             "angle": { | ||||
|               "type": "Degrees" | ||||
|             } | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
| @ -556,7 +563,8 @@ description: Operations executed focusrite-scarlett-mounting-bracket.kcl | ||||
|           "type": "Number", | ||||
|           "value": 2.5, | ||||
|           "ty": { | ||||
|             "type": "Unknown" | ||||
|             "type": "Known", | ||||
|             "type": "Count" | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
| @ -645,7 +653,8 @@ description: Operations executed focusrite-scarlett-mounting-bracket.kcl | ||||
|           "type": "Number", | ||||
|           "value": 54.666666666666664, | ||||
|           "ty": { | ||||
|             "type": "Unknown" | ||||
|             "type": "Known", | ||||
|             "type": "Count" | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
| @ -942,7 +951,8 @@ description: Operations executed focusrite-scarlett-mounting-bracket.kcl | ||||
|           "type": "Number", | ||||
|           "value": 2.5, | ||||
|           "ty": { | ||||
|             "type": "Unknown" | ||||
|             "type": "Known", | ||||
|             "type": "Count" | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
| @ -1031,7 +1041,8 @@ description: Operations executed focusrite-scarlett-mounting-bracket.kcl | ||||
|           "type": "Number", | ||||
|           "value": 54.666666666666664, | ||||
|           "ty": { | ||||
|             "type": "Unknown" | ||||
|             "type": "Known", | ||||
|             "type": "Count" | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
| @ -1082,7 +1093,8 @@ description: Operations executed focusrite-scarlett-mounting-bracket.kcl | ||||
|                       "type": "Number", | ||||
|                       "value": -52.0, | ||||
|                       "ty": { | ||||
|                         "type": "Unknown" | ||||
|                         "type": "Known", | ||||
|                         "type": "Count" | ||||
|                       } | ||||
|                     }, | ||||
|                     "y": { | ||||
| @ -1305,7 +1317,8 @@ description: Operations executed focusrite-scarlett-mounting-bracket.kcl | ||||
|                       "type": "Number", | ||||
|                       "value": -52.0, | ||||
|                       "ty": { | ||||
|                         "type": "Unknown" | ||||
|                         "type": "Known", | ||||
|                         "type": "Count" | ||||
|                       } | ||||
|                     }, | ||||
|                     "y": { | ||||
|  | ||||
| @ -471,7 +471,8 @@ description: Variables in memory after executing focusrite-scarlett-mounting-bra | ||||
|                 "type": "Number", | ||||
|                 "value": 44.0, | ||||
|                 "ty": { | ||||
|                   "type": "Unknown" | ||||
|                   "type": "Known", | ||||
|                   "type": "Count" | ||||
|                 } | ||||
|               }, | ||||
|               "z": { | ||||
| @ -1401,7 +1402,8 @@ description: Variables in memory after executing focusrite-scarlett-mounting-bra | ||||
|                 "type": "Number", | ||||
|                 "value": -52.0, | ||||
|                 "ty": { | ||||
|                   "type": "Unknown" | ||||
|                   "type": "Known", | ||||
|                   "type": "Count" | ||||
|                 } | ||||
|               }, | ||||
|               "y": { | ||||
|  | ||||
| @ -345,7 +345,8 @@ description: Operations executed food-service-spatula.kcl | ||||
|           "type": "Number", | ||||
|           "value": -7.5, | ||||
|           "ty": { | ||||
|             "type": "Unknown" | ||||
|             "type": "Known", | ||||
|             "type": "Count" | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
|  | ||||
| @ -1334,7 +1334,8 @@ description: Operations executed french-press.kcl | ||||
|           "type": "Number", | ||||
|           "value": 0.325, | ||||
|           "ty": { | ||||
|             "type": "Unknown" | ||||
|             "type": "Known", | ||||
|             "type": "Count" | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
|  | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -73,7 +73,13 @@ description: Operations executed gridfinity-baseplate-magnets.kcl | ||||
|           "type": "Number", | ||||
|           "value": 34.0, | ||||
|           "ty": { | ||||
|             "type": "Unknown" | ||||
|             "type": "Default", | ||||
|             "len": { | ||||
|               "type": "Mm" | ||||
|             }, | ||||
|             "angle": { | ||||
|               "type": "Degrees" | ||||
|             } | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
| @ -165,14 +171,16 @@ description: Operations executed gridfinity-baseplate-magnets.kcl | ||||
|               "type": "Number", | ||||
|               "value": 21.0, | ||||
|               "ty": { | ||||
|                 "type": "Unknown" | ||||
|                 "type": "Known", | ||||
|                 "type": "Count" | ||||
|               } | ||||
|             }, | ||||
|             { | ||||
|               "type": "Number", | ||||
|               "value": 21.0, | ||||
|               "ty": { | ||||
|                 "type": "Unknown" | ||||
|                 "type": "Known", | ||||
|                 "type": "Count" | ||||
|               } | ||||
|             }, | ||||
|             { | ||||
| @ -472,14 +480,16 @@ description: Operations executed gridfinity-baseplate-magnets.kcl | ||||
|               "type": "Number", | ||||
|               "value": 21.0, | ||||
|               "ty": { | ||||
|                 "type": "Unknown" | ||||
|                 "type": "Known", | ||||
|                 "type": "Count" | ||||
|               } | ||||
|             }, | ||||
|             { | ||||
|               "type": "Number", | ||||
|               "value": 21.0, | ||||
|               "ty": { | ||||
|                 "type": "Unknown" | ||||
|                 "type": "Known", | ||||
|                 "type": "Count" | ||||
|               } | ||||
|             }, | ||||
|             { | ||||
|  | ||||
| @ -73,7 +73,13 @@ description: Operations executed gridfinity-baseplate.kcl | ||||
|           "type": "Number", | ||||
|           "value": 34.0, | ||||
|           "ty": { | ||||
|             "type": "Unknown" | ||||
|             "type": "Default", | ||||
|             "len": { | ||||
|               "type": "Mm" | ||||
|             }, | ||||
|             "angle": { | ||||
|               "type": "Degrees" | ||||
|             } | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
| @ -165,14 +171,16 @@ description: Operations executed gridfinity-baseplate.kcl | ||||
|               "type": "Number", | ||||
|               "value": 21.0, | ||||
|               "ty": { | ||||
|                 "type": "Unknown" | ||||
|                 "type": "Known", | ||||
|                 "type": "Count" | ||||
|               } | ||||
|             }, | ||||
|             { | ||||
|               "type": "Number", | ||||
|               "value": 21.0, | ||||
|               "ty": { | ||||
|                 "type": "Unknown" | ||||
|                 "type": "Known", | ||||
|                 "type": "Count" | ||||
|               } | ||||
|             }, | ||||
|             { | ||||
| @ -472,14 +480,16 @@ description: Operations executed gridfinity-baseplate.kcl | ||||
|               "type": "Number", | ||||
|               "value": 21.0, | ||||
|               "ty": { | ||||
|                 "type": "Unknown" | ||||
|                 "type": "Known", | ||||
|                 "type": "Count" | ||||
|               } | ||||
|             }, | ||||
|             { | ||||
|               "type": "Number", | ||||
|               "value": 21.0, | ||||
|               "ty": { | ||||
|                 "type": "Unknown" | ||||
|                 "type": "Known", | ||||
|                 "type": "Count" | ||||
|               } | ||||
|             }, | ||||
|             { | ||||
|  | ||||
| @ -73,7 +73,13 @@ description: Operations executed gridfinity-bins-stacking-lip.kcl | ||||
|           "type": "Number", | ||||
|           "value": 34.0, | ||||
|           "ty": { | ||||
|             "type": "Unknown" | ||||
|             "type": "Default", | ||||
|             "len": { | ||||
|               "type": "Mm" | ||||
|             }, | ||||
|             "angle": { | ||||
|               "type": "Degrees" | ||||
|             } | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
| @ -165,14 +171,16 @@ description: Operations executed gridfinity-bins-stacking-lip.kcl | ||||
|               "type": "Number", | ||||
|               "value": 21.0, | ||||
|               "ty": { | ||||
|                 "type": "Unknown" | ||||
|                 "type": "Known", | ||||
|                 "type": "Count" | ||||
|               } | ||||
|             }, | ||||
|             { | ||||
|               "type": "Number", | ||||
|               "value": 21.0, | ||||
|               "ty": { | ||||
|                 "type": "Unknown" | ||||
|                 "type": "Known", | ||||
|                 "type": "Count" | ||||
|               } | ||||
|             }, | ||||
|             { | ||||
| @ -472,14 +480,16 @@ description: Operations executed gridfinity-bins-stacking-lip.kcl | ||||
|               "type": "Number", | ||||
|               "value": 21.0, | ||||
|               "ty": { | ||||
|                 "type": "Unknown" | ||||
|                 "type": "Known", | ||||
|                 "type": "Count" | ||||
|               } | ||||
|             }, | ||||
|             { | ||||
|               "type": "Number", | ||||
|               "value": 21.0, | ||||
|               "ty": { | ||||
|                 "type": "Unknown" | ||||
|                 "type": "Known", | ||||
|                 "type": "Count" | ||||
|               } | ||||
|             }, | ||||
|             { | ||||
| @ -772,7 +782,13 @@ description: Operations executed gridfinity-bins-stacking-lip.kcl | ||||
|           "type": "Number", | ||||
|           "value": 42.0, | ||||
|           "ty": { | ||||
|             "type": "Unknown" | ||||
|             "type": "Default", | ||||
|             "len": { | ||||
|               "type": "Mm" | ||||
|             }, | ||||
|             "angle": { | ||||
|               "type": "Degrees" | ||||
|             } | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
| @ -884,7 +900,13 @@ description: Operations executed gridfinity-bins-stacking-lip.kcl | ||||
|           "type": "Number", | ||||
|           "value": 42.0, | ||||
|           "ty": { | ||||
|             "type": "Unknown" | ||||
|             "type": "Default", | ||||
|             "len": { | ||||
|               "type": "Mm" | ||||
|             }, | ||||
|             "angle": { | ||||
|               "type": "Degrees" | ||||
|             } | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
| @ -1020,7 +1042,13 @@ description: Operations executed gridfinity-bins-stacking-lip.kcl | ||||
|           "type": "Number", | ||||
|           "value": 42.0, | ||||
|           "ty": { | ||||
|             "type": "Unknown" | ||||
|             "type": "Default", | ||||
|             "len": { | ||||
|               "type": "Mm" | ||||
|             }, | ||||
|             "angle": { | ||||
|               "type": "Degrees" | ||||
|             } | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
| @ -1132,7 +1160,13 @@ description: Operations executed gridfinity-bins-stacking-lip.kcl | ||||
|           "type": "Number", | ||||
|           "value": 42.0, | ||||
|           "ty": { | ||||
|             "type": "Unknown" | ||||
|             "type": "Default", | ||||
|             "len": { | ||||
|               "type": "Mm" | ||||
|             }, | ||||
|             "angle": { | ||||
|               "type": "Degrees" | ||||
|             } | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
| @ -1268,7 +1302,13 @@ description: Operations executed gridfinity-bins-stacking-lip.kcl | ||||
|           "type": "Number", | ||||
|           "value": 42.0, | ||||
|           "ty": { | ||||
|             "type": "Unknown" | ||||
|             "type": "Default", | ||||
|             "len": { | ||||
|               "type": "Mm" | ||||
|             }, | ||||
|             "angle": { | ||||
|               "type": "Degrees" | ||||
|             } | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
| @ -1357,7 +1397,13 @@ description: Operations executed gridfinity-bins-stacking-lip.kcl | ||||
|           "type": "Number", | ||||
|           "value": 42.0, | ||||
|           "ty": { | ||||
|             "type": "Unknown" | ||||
|             "type": "Default", | ||||
|             "len": { | ||||
|               "type": "Mm" | ||||
|             }, | ||||
|             "angle": { | ||||
|               "type": "Degrees" | ||||
|             } | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
| @ -1455,7 +1501,13 @@ description: Operations executed gridfinity-bins-stacking-lip.kcl | ||||
|           "type": "Number", | ||||
|           "value": 7.0, | ||||
|           "ty": { | ||||
|             "type": "Unknown" | ||||
|             "type": "Default", | ||||
|             "len": { | ||||
|               "type": "Mm" | ||||
|             }, | ||||
|             "angle": { | ||||
|               "type": "Degrees" | ||||
|             } | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
| @ -1631,7 +1683,13 @@ description: Operations executed gridfinity-bins-stacking-lip.kcl | ||||
|                       "type": "Number", | ||||
|                       "value": 11.75, | ||||
|                       "ty": { | ||||
|                         "type": "Unknown" | ||||
|                         "type": "Default", | ||||
|                         "len": { | ||||
|                           "type": "Mm" | ||||
|                         }, | ||||
|                         "angle": { | ||||
|                           "type": "Degrees" | ||||
|                         } | ||||
|                       } | ||||
|                     } | ||||
|                   ] | ||||
| @ -1790,7 +1848,13 @@ description: Operations executed gridfinity-bins-stacking-lip.kcl | ||||
|           "type": "Number", | ||||
|           "value": 76.5, | ||||
|           "ty": { | ||||
|             "type": "Unknown" | ||||
|             "type": "Default", | ||||
|             "len": { | ||||
|               "type": "Mm" | ||||
|             }, | ||||
|             "angle": { | ||||
|               "type": "Degrees" | ||||
|             } | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
| @ -1866,7 +1930,13 @@ description: Operations executed gridfinity-bins-stacking-lip.kcl | ||||
|                       "type": "Number", | ||||
|                       "value": 11.75, | ||||
|                       "ty": { | ||||
|                         "type": "Unknown" | ||||
|                         "type": "Default", | ||||
|                         "len": { | ||||
|                           "type": "Mm" | ||||
|                         }, | ||||
|                         "angle": { | ||||
|                           "type": "Degrees" | ||||
|                         } | ||||
|                       } | ||||
|                     } | ||||
|                   ] | ||||
| @ -2025,7 +2095,13 @@ description: Operations executed gridfinity-bins-stacking-lip.kcl | ||||
|           "type": "Number", | ||||
|           "value": 118.5, | ||||
|           "ty": { | ||||
|             "type": "Unknown" | ||||
|             "type": "Default", | ||||
|             "len": { | ||||
|               "type": "Mm" | ||||
|             }, | ||||
|             "angle": { | ||||
|               "type": "Degrees" | ||||
|             } | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
| @ -2117,14 +2193,26 @@ description: Operations executed gridfinity-bins-stacking-lip.kcl | ||||
|               "type": "Number", | ||||
|               "value": 42.0, | ||||
|               "ty": { | ||||
|                 "type": "Unknown" | ||||
|                 "type": "Default", | ||||
|                 "len": { | ||||
|                   "type": "Mm" | ||||
|                 }, | ||||
|                 "angle": { | ||||
|                   "type": "Degrees" | ||||
|                 } | ||||
|               } | ||||
|             }, | ||||
|             { | ||||
|               "type": "Number", | ||||
|               "value": 63.0, | ||||
|               "ty": { | ||||
|                 "type": "Unknown" | ||||
|                 "type": "Default", | ||||
|                 "len": { | ||||
|                   "type": "Mm" | ||||
|                 }, | ||||
|                 "angle": { | ||||
|                   "type": "Degrees" | ||||
|                 } | ||||
|               } | ||||
|             }, | ||||
|             { | ||||
| @ -2254,14 +2342,26 @@ description: Operations executed gridfinity-bins-stacking-lip.kcl | ||||
|               "type": "Number", | ||||
|               "value": 42.0, | ||||
|               "ty": { | ||||
|                 "type": "Unknown" | ||||
|                 "type": "Default", | ||||
|                 "len": { | ||||
|                   "type": "Mm" | ||||
|                 }, | ||||
|                 "angle": { | ||||
|                   "type": "Degrees" | ||||
|                 } | ||||
|               } | ||||
|             }, | ||||
|             { | ||||
|               "type": "Number", | ||||
|               "value": 63.0, | ||||
|               "ty": { | ||||
|                 "type": "Unknown" | ||||
|                 "type": "Default", | ||||
|                 "len": { | ||||
|                   "type": "Mm" | ||||
|                 }, | ||||
|                 "angle": { | ||||
|                   "type": "Degrees" | ||||
|                 } | ||||
|               } | ||||
|             }, | ||||
|             { | ||||
| @ -2375,7 +2475,13 @@ description: Operations executed gridfinity-bins-stacking-lip.kcl | ||||
|                       "type": "Number", | ||||
|                       "value": 11.75, | ||||
|                       "ty": { | ||||
|                         "type": "Unknown" | ||||
|                         "type": "Default", | ||||
|                         "len": { | ||||
|                           "type": "Mm" | ||||
|                         }, | ||||
|                         "angle": { | ||||
|                           "type": "Degrees" | ||||
|                         } | ||||
|                       } | ||||
|                     } | ||||
|                   ] | ||||
| @ -2665,7 +2771,13 @@ description: Operations executed gridfinity-bins-stacking-lip.kcl | ||||
|                       "type": "Number", | ||||
|                       "value": 80.25, | ||||
|                       "ty": { | ||||
|                         "type": "Unknown" | ||||
|                         "type": "Default", | ||||
|                         "len": { | ||||
|                           "type": "Mm" | ||||
|                         }, | ||||
|                         "angle": { | ||||
|                           "type": "Degrees" | ||||
|                         } | ||||
|                       } | ||||
|                     }, | ||||
|                     { | ||||
| @ -2685,7 +2797,13 @@ description: Operations executed gridfinity-bins-stacking-lip.kcl | ||||
|                       "type": "Number", | ||||
|                       "value": 11.75, | ||||
|                       "ty": { | ||||
|                         "type": "Unknown" | ||||
|                         "type": "Default", | ||||
|                         "len": { | ||||
|                           "type": "Mm" | ||||
|                         }, | ||||
|                         "angle": { | ||||
|                           "type": "Degrees" | ||||
|                         } | ||||
|                       } | ||||
|                     } | ||||
|                   ] | ||||
| @ -3017,14 +3135,26 @@ description: Operations executed gridfinity-bins-stacking-lip.kcl | ||||
|               "type": "Number", | ||||
|               "value": 42.0, | ||||
|               "ty": { | ||||
|                 "type": "Unknown" | ||||
|                 "type": "Default", | ||||
|                 "len": { | ||||
|                   "type": "Mm" | ||||
|                 }, | ||||
|                 "angle": { | ||||
|                   "type": "Degrees" | ||||
|                 } | ||||
|               } | ||||
|             }, | ||||
|             { | ||||
|               "type": "Number", | ||||
|               "value": 63.0, | ||||
|               "ty": { | ||||
|                 "type": "Unknown" | ||||
|                 "type": "Default", | ||||
|                 "len": { | ||||
|                   "type": "Mm" | ||||
|                 }, | ||||
|                 "angle": { | ||||
|                   "type": "Degrees" | ||||
|                 } | ||||
|               } | ||||
|             }, | ||||
|             { | ||||
| @ -3154,14 +3284,26 @@ description: Operations executed gridfinity-bins-stacking-lip.kcl | ||||
|               "type": "Number", | ||||
|               "value": 42.0, | ||||
|               "ty": { | ||||
|                 "type": "Unknown" | ||||
|                 "type": "Default", | ||||
|                 "len": { | ||||
|                   "type": "Mm" | ||||
|                 }, | ||||
|                 "angle": { | ||||
|                   "type": "Degrees" | ||||
|                 } | ||||
|               } | ||||
|             }, | ||||
|             { | ||||
|               "type": "Number", | ||||
|               "value": 63.0, | ||||
|               "ty": { | ||||
|                 "type": "Unknown" | ||||
|                 "type": "Default", | ||||
|                 "len": { | ||||
|                   "type": "Mm" | ||||
|                 }, | ||||
|                 "angle": { | ||||
|                   "type": "Degrees" | ||||
|                 } | ||||
|               } | ||||
|             }, | ||||
|             { | ||||
|  | ||||
| @ -19603,7 +19603,13 @@ description: Variables in memory after executing gridfinity-bins-stacking-lip.kc | ||||
|                 "type": "Number", | ||||
|                 "value": 11.75, | ||||
|                 "ty": { | ||||
|                   "type": "Unknown" | ||||
|                   "type": "Default", | ||||
|                   "len": { | ||||
|                     "type": "Mm" | ||||
|                   }, | ||||
|                   "angle": { | ||||
|                     "type": "Degrees" | ||||
|                   } | ||||
|                 } | ||||
|               } | ||||
|             ] | ||||
| @ -19783,7 +19789,13 @@ description: Variables in memory after executing gridfinity-bins-stacking-lip.kc | ||||
|                 "type": "Number", | ||||
|                 "value": 11.75, | ||||
|                 "ty": { | ||||
|                   "type": "Unknown" | ||||
|                   "type": "Default", | ||||
|                   "len": { | ||||
|                     "type": "Mm" | ||||
|                   }, | ||||
|                   "angle": { | ||||
|                     "type": "Degrees" | ||||
|                   } | ||||
|                 } | ||||
|               } | ||||
|             ] | ||||
| @ -19937,7 +19949,13 @@ description: Variables in memory after executing gridfinity-bins-stacking-lip.kc | ||||
|                 "type": "Number", | ||||
|                 "value": 80.25, | ||||
|                 "ty": { | ||||
|                   "type": "Unknown" | ||||
|                   "type": "Default", | ||||
|                   "len": { | ||||
|                     "type": "Mm" | ||||
|                   }, | ||||
|                   "angle": { | ||||
|                     "type": "Degrees" | ||||
|                   } | ||||
|                 } | ||||
|               }, | ||||
|               { | ||||
| @ -19957,7 +19975,13 @@ description: Variables in memory after executing gridfinity-bins-stacking-lip.kc | ||||
|                 "type": "Number", | ||||
|                 "value": 11.75, | ||||
|                 "ty": { | ||||
|                   "type": "Unknown" | ||||
|                   "type": "Default", | ||||
|                   "len": { | ||||
|                     "type": "Mm" | ||||
|                   }, | ||||
|                   "angle": { | ||||
|                     "type": "Degrees" | ||||
|                   } | ||||
|                 } | ||||
|               } | ||||
|             ] | ||||
|  | ||||
| @ -73,7 +73,13 @@ description: Operations executed gridfinity-bins.kcl | ||||
|           "type": "Number", | ||||
|           "value": 34.0, | ||||
|           "ty": { | ||||
|             "type": "Unknown" | ||||
|             "type": "Default", | ||||
|             "len": { | ||||
|               "type": "Mm" | ||||
|             }, | ||||
|             "angle": { | ||||
|               "type": "Degrees" | ||||
|             } | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
| @ -165,14 +171,16 @@ description: Operations executed gridfinity-bins.kcl | ||||
|               "type": "Number", | ||||
|               "value": 21.0, | ||||
|               "ty": { | ||||
|                 "type": "Unknown" | ||||
|                 "type": "Known", | ||||
|                 "type": "Count" | ||||
|               } | ||||
|             }, | ||||
|             { | ||||
|               "type": "Number", | ||||
|               "value": 21.0, | ||||
|               "ty": { | ||||
|                 "type": "Unknown" | ||||
|                 "type": "Known", | ||||
|                 "type": "Count" | ||||
|               } | ||||
|             }, | ||||
|             { | ||||
| @ -472,14 +480,16 @@ description: Operations executed gridfinity-bins.kcl | ||||
|               "type": "Number", | ||||
|               "value": 21.0, | ||||
|               "ty": { | ||||
|                 "type": "Unknown" | ||||
|                 "type": "Known", | ||||
|                 "type": "Count" | ||||
|               } | ||||
|             }, | ||||
|             { | ||||
|               "type": "Number", | ||||
|               "value": 21.0, | ||||
|               "ty": { | ||||
|                 "type": "Unknown" | ||||
|                 "type": "Known", | ||||
|                 "type": "Count" | ||||
|               } | ||||
|             }, | ||||
|             { | ||||
| @ -772,7 +782,13 @@ description: Operations executed gridfinity-bins.kcl | ||||
|           "type": "Number", | ||||
|           "value": 42.0, | ||||
|           "ty": { | ||||
|             "type": "Unknown" | ||||
|             "type": "Default", | ||||
|             "len": { | ||||
|               "type": "Mm" | ||||
|             }, | ||||
|             "angle": { | ||||
|               "type": "Degrees" | ||||
|             } | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
| @ -884,7 +900,13 @@ description: Operations executed gridfinity-bins.kcl | ||||
|           "type": "Number", | ||||
|           "value": 42.0, | ||||
|           "ty": { | ||||
|             "type": "Unknown" | ||||
|             "type": "Default", | ||||
|             "len": { | ||||
|               "type": "Mm" | ||||
|             }, | ||||
|             "angle": { | ||||
|               "type": "Degrees" | ||||
|             } | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
| @ -1020,7 +1042,13 @@ description: Operations executed gridfinity-bins.kcl | ||||
|           "type": "Number", | ||||
|           "value": 42.0, | ||||
|           "ty": { | ||||
|             "type": "Unknown" | ||||
|             "type": "Default", | ||||
|             "len": { | ||||
|               "type": "Mm" | ||||
|             }, | ||||
|             "angle": { | ||||
|               "type": "Degrees" | ||||
|             } | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
| @ -1132,7 +1160,13 @@ description: Operations executed gridfinity-bins.kcl | ||||
|           "type": "Number", | ||||
|           "value": 42.0, | ||||
|           "ty": { | ||||
|             "type": "Unknown" | ||||
|             "type": "Default", | ||||
|             "len": { | ||||
|               "type": "Mm" | ||||
|             }, | ||||
|             "angle": { | ||||
|               "type": "Degrees" | ||||
|             } | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
| @ -1268,7 +1302,13 @@ description: Operations executed gridfinity-bins.kcl | ||||
|           "type": "Number", | ||||
|           "value": 42.0, | ||||
|           "ty": { | ||||
|             "type": "Unknown" | ||||
|             "type": "Default", | ||||
|             "len": { | ||||
|               "type": "Mm" | ||||
|             }, | ||||
|             "angle": { | ||||
|               "type": "Degrees" | ||||
|             } | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
| @ -1357,7 +1397,13 @@ description: Operations executed gridfinity-bins.kcl | ||||
|           "type": "Number", | ||||
|           "value": 42.0, | ||||
|           "ty": { | ||||
|             "type": "Unknown" | ||||
|             "type": "Default", | ||||
|             "len": { | ||||
|               "type": "Mm" | ||||
|             }, | ||||
|             "angle": { | ||||
|               "type": "Degrees" | ||||
|             } | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
| @ -1455,7 +1501,13 @@ description: Operations executed gridfinity-bins.kcl | ||||
|           "type": "Number", | ||||
|           "value": 14.0, | ||||
|           "ty": { | ||||
|             "type": "Unknown" | ||||
|             "type": "Default", | ||||
|             "len": { | ||||
|               "type": "Mm" | ||||
|             }, | ||||
|             "angle": { | ||||
|               "type": "Degrees" | ||||
|             } | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
|  | ||||
| @ -1897,42 +1897,78 @@ description: Variables in memory after executing keyboard.kcl | ||||
|     "type": "Number", | ||||
|     "value": 0.3, | ||||
|     "ty": { | ||||
|       "type": "Unknown" | ||||
|       "type": "Default", | ||||
|       "len": { | ||||
|         "type": "Inches" | ||||
|       }, | ||||
|       "angle": { | ||||
|         "type": "Degrees" | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   "row2": { | ||||
|     "type": "Number", | ||||
|     "value": 1.2, | ||||
|     "ty": { | ||||
|       "type": "Unknown" | ||||
|       "type": "Default", | ||||
|       "len": { | ||||
|         "type": "Inches" | ||||
|       }, | ||||
|       "angle": { | ||||
|         "type": "Degrees" | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   "row3": { | ||||
|     "type": "Number", | ||||
|     "value": 2.1, | ||||
|     "ty": { | ||||
|       "type": "Unknown" | ||||
|       "type": "Default", | ||||
|       "len": { | ||||
|         "type": "Inches" | ||||
|       }, | ||||
|       "angle": { | ||||
|         "type": "Degrees" | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   "row4": { | ||||
|     "type": "Number", | ||||
|     "value": 3.0, | ||||
|     "ty": { | ||||
|       "type": "Unknown" | ||||
|       "type": "Default", | ||||
|       "len": { | ||||
|         "type": "Inches" | ||||
|       }, | ||||
|       "angle": { | ||||
|         "type": "Degrees" | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   "row5": { | ||||
|     "type": "Number", | ||||
|     "value": 3.9, | ||||
|     "ty": { | ||||
|       "type": "Unknown" | ||||
|       "type": "Default", | ||||
|       "len": { | ||||
|         "type": "Inches" | ||||
|       }, | ||||
|       "angle": { | ||||
|         "type": "Degrees" | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   "row6": { | ||||
|     "type": "Number", | ||||
|     "value": 4.8, | ||||
|     "ty": { | ||||
|       "type": "Unknown" | ||||
|       "type": "Default", | ||||
|       "len": { | ||||
|         "type": "Inches" | ||||
|       }, | ||||
|       "angle": { | ||||
|         "type": "Degrees" | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   "seg01": { | ||||
|  | ||||
| @ -3969,7 +3969,8 @@ description: Variables in memory after executing kitt.kcl | ||||
|     "type": "Number", | ||||
|     "value": 9.0, | ||||
|     "ty": { | ||||
|       "type": "Unknown" | ||||
|       "type": "Known", | ||||
|       "type": "Count" | ||||
|     } | ||||
|   }, | ||||
|   "kitBellyButtonWidth": { | ||||
| @ -4028,7 +4029,13 @@ description: Variables in memory after executing kitt.kcl | ||||
|     "type": "Number", | ||||
|     "value": 24.0, | ||||
|     "ty": { | ||||
|       "type": "Unknown" | ||||
|       "type": "Default", | ||||
|       "len": { | ||||
|         "type": "Mm" | ||||
|       }, | ||||
|       "angle": { | ||||
|         "type": "Degrees" | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   "kitBody": { | ||||
| @ -7160,7 +7167,13 @@ description: Variables in memory after executing kitt.kcl | ||||
|     "type": "Number", | ||||
|     "value": 20.0, | ||||
|     "ty": { | ||||
|       "type": "Unknown" | ||||
|       "type": "Default", | ||||
|       "len": { | ||||
|         "type": "Mm" | ||||
|       }, | ||||
|       "angle": { | ||||
|         "type": "Degrees" | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   "kitFloppy1": { | ||||
| @ -9033,7 +9046,8 @@ description: Variables in memory after executing kitt.kcl | ||||
|     "type": "Number", | ||||
|     "value": 11.0, | ||||
|     "ty": { | ||||
|       "type": "Unknown" | ||||
|       "type": "Known", | ||||
|       "type": "Count" | ||||
|     } | ||||
|   }, | ||||
|   "kitFloppyWidth": { | ||||
| @ -9525,7 +9539,13 @@ description: Variables in memory after executing kitt.kcl | ||||
|     "type": "Number", | ||||
|     "value": 24.0, | ||||
|     "ty": { | ||||
|       "type": "Unknown" | ||||
|       "type": "Default", | ||||
|       "len": { | ||||
|         "type": "Mm" | ||||
|       }, | ||||
|       "angle": { | ||||
|         "type": "Degrees" | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   "kitLeftEar": { | ||||
|  | ||||
| @ -81,7 +81,8 @@ description: Operations executed lego.kcl | ||||
|           "type": "Number", | ||||
|           "value": -1.7000000000000002, | ||||
|           "ty": { | ||||
|             "type": "Unknown" | ||||
|             "type": "Known", | ||||
|             "type": "Count" | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
|  | ||||
| @ -237,7 +237,8 @@ description: Variables in memory after executing lego.kcl | ||||
|     "type": "Number", | ||||
|     "value": 7.9333, | ||||
|     "ty": { | ||||
|       "type": "Unknown" | ||||
|       "type": "Known", | ||||
|       "type": "Count" | ||||
|     } | ||||
|   }, | ||||
|   "lbumps": { | ||||
| @ -1931,7 +1932,8 @@ description: Variables in memory after executing lego.kcl | ||||
|     "type": "Number", | ||||
|     "value": 6.5, | ||||
|     "ty": { | ||||
|       "type": "Unknown" | ||||
|       "type": "Known", | ||||
|       "type": "Count" | ||||
|     } | ||||
|   }, | ||||
|   "shellExtrude": { | ||||
| @ -2286,21 +2288,34 @@ description: Variables in memory after executing lego.kcl | ||||
|     "type": "Number", | ||||
|     "value": 1.5, | ||||
|     "ty": { | ||||
|       "type": "Unknown" | ||||
|       "type": "Known", | ||||
|       "type": "Count" | ||||
|     } | ||||
|   }, | ||||
|   "totalLength": { | ||||
|     "type": "Number", | ||||
|     "value": 23.8, | ||||
|     "ty": { | ||||
|       "type": "Unknown" | ||||
|       "type": "Default", | ||||
|       "len": { | ||||
|         "type": "Inches" | ||||
|       }, | ||||
|       "angle": { | ||||
|         "type": "Degrees" | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   "totalWidth": { | ||||
|     "type": "Number", | ||||
|     "value": 15.8, | ||||
|     "ty": { | ||||
|       "type": "Unknown" | ||||
|       "type": "Default", | ||||
|       "len": { | ||||
|         "type": "Inches" | ||||
|       }, | ||||
|       "angle": { | ||||
|         "type": "Degrees" | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   "tubePattern": { | ||||
| @ -3204,7 +3219,8 @@ description: Variables in memory after executing lego.kcl | ||||
|     "type": "Number", | ||||
|     "value": 7.9, | ||||
|     "ty": { | ||||
|       "type": "Unknown" | ||||
|       "type": "Known", | ||||
|       "type": "Count" | ||||
|     } | ||||
|   }, | ||||
|   "wbumps": { | ||||
|  | ||||
| @ -70,7 +70,13 @@ description: Operations executed makeup-mirror.kcl | ||||
|           "type": "Number", | ||||
|           "value": 24.0, | ||||
|           "ty": { | ||||
|             "type": "Unknown" | ||||
|             "type": "Default", | ||||
|             "len": { | ||||
|               "type": "Mm" | ||||
|             }, | ||||
|             "angle": { | ||||
|               "type": "Degrees" | ||||
|             } | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
| @ -114,7 +120,13 @@ description: Operations executed makeup-mirror.kcl | ||||
|           "type": "Number", | ||||
|           "value": 24.5, | ||||
|           "ty": { | ||||
|             "type": "Unknown" | ||||
|             "type": "Default", | ||||
|             "len": { | ||||
|               "type": "Mm" | ||||
|             }, | ||||
|             "angle": { | ||||
|               "type": "Degrees" | ||||
|             } | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
| @ -153,7 +165,13 @@ description: Operations executed makeup-mirror.kcl | ||||
|           "type": "Number", | ||||
|           "value": 24.0, | ||||
|           "ty": { | ||||
|             "type": "Unknown" | ||||
|             "type": "Default", | ||||
|             "len": { | ||||
|               "type": "Mm" | ||||
|             }, | ||||
|             "angle": { | ||||
|               "type": "Degrees" | ||||
|             } | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
| @ -197,7 +215,13 @@ description: Operations executed makeup-mirror.kcl | ||||
|           "type": "Number", | ||||
|           "value": 49.0, | ||||
|           "ty": { | ||||
|             "type": "Unknown" | ||||
|             "type": "Default", | ||||
|             "len": { | ||||
|               "type": "Mm" | ||||
|             }, | ||||
|             "angle": { | ||||
|               "type": "Degrees" | ||||
|             } | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
| @ -236,7 +260,13 @@ description: Operations executed makeup-mirror.kcl | ||||
|           "type": "Number", | ||||
|           "value": 24.0, | ||||
|           "ty": { | ||||
|             "type": "Unknown" | ||||
|             "type": "Default", | ||||
|             "len": { | ||||
|               "type": "Mm" | ||||
|             }, | ||||
|             "angle": { | ||||
|               "type": "Degrees" | ||||
|             } | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
| @ -280,7 +310,13 @@ description: Operations executed makeup-mirror.kcl | ||||
|           "type": "Number", | ||||
|           "value": 24.5, | ||||
|           "ty": { | ||||
|             "type": "Unknown" | ||||
|             "type": "Default", | ||||
|             "len": { | ||||
|               "type": "Mm" | ||||
|             }, | ||||
|             "angle": { | ||||
|               "type": "Degrees" | ||||
|             } | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
| @ -319,7 +355,13 @@ description: Operations executed makeup-mirror.kcl | ||||
|           "type": "Number", | ||||
|           "value": 24.0, | ||||
|           "ty": { | ||||
|             "type": "Unknown" | ||||
|             "type": "Default", | ||||
|             "len": { | ||||
|               "type": "Mm" | ||||
|             }, | ||||
|             "angle": { | ||||
|               "type": "Degrees" | ||||
|             } | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
| @ -363,7 +405,13 @@ description: Operations executed makeup-mirror.kcl | ||||
|           "type": "Number", | ||||
|           "value": 49.0, | ||||
|           "ty": { | ||||
|             "type": "Unknown" | ||||
|             "type": "Default", | ||||
|             "len": { | ||||
|               "type": "Mm" | ||||
|             }, | ||||
|             "angle": { | ||||
|               "type": "Degrees" | ||||
|             } | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
| @ -402,7 +450,13 @@ description: Operations executed makeup-mirror.kcl | ||||
|           "type": "Number", | ||||
|           "value": 24.0, | ||||
|           "ty": { | ||||
|             "type": "Unknown" | ||||
|             "type": "Default", | ||||
|             "len": { | ||||
|               "type": "Mm" | ||||
|             }, | ||||
|             "angle": { | ||||
|               "type": "Degrees" | ||||
|             } | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
| @ -446,7 +500,13 @@ description: Operations executed makeup-mirror.kcl | ||||
|           "type": "Number", | ||||
|           "value": 49.0, | ||||
|           "ty": { | ||||
|             "type": "Unknown" | ||||
|             "type": "Default", | ||||
|             "len": { | ||||
|               "type": "Mm" | ||||
|             }, | ||||
|             "angle": { | ||||
|               "type": "Degrees" | ||||
|             } | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
| @ -485,7 +545,13 @@ description: Operations executed makeup-mirror.kcl | ||||
|           "type": "Number", | ||||
|           "value": 24.0, | ||||
|           "ty": { | ||||
|             "type": "Unknown" | ||||
|             "type": "Default", | ||||
|             "len": { | ||||
|               "type": "Mm" | ||||
|             }, | ||||
|             "angle": { | ||||
|               "type": "Degrees" | ||||
|             } | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
| @ -529,7 +595,13 @@ description: Operations executed makeup-mirror.kcl | ||||
|           "type": "Number", | ||||
|           "value": 73.5, | ||||
|           "ty": { | ||||
|             "type": "Unknown" | ||||
|             "type": "Default", | ||||
|             "len": { | ||||
|               "type": "Mm" | ||||
|             }, | ||||
|             "angle": { | ||||
|               "type": "Degrees" | ||||
|             } | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
| @ -568,7 +640,13 @@ description: Operations executed makeup-mirror.kcl | ||||
|           "type": "Number", | ||||
|           "value": 24.0, | ||||
|           "ty": { | ||||
|             "type": "Unknown" | ||||
|             "type": "Default", | ||||
|             "len": { | ||||
|               "type": "Mm" | ||||
|             }, | ||||
|             "angle": { | ||||
|               "type": "Degrees" | ||||
|             } | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
| @ -742,7 +820,8 @@ description: Operations executed makeup-mirror.kcl | ||||
|           "type": "Number", | ||||
|           "value": 165.0, | ||||
|           "ty": { | ||||
|             "type": "Unknown" | ||||
|             "type": "Known", | ||||
|             "type": "Count" | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
|  | ||||
| @ -7,7 +7,8 @@ description: Variables in memory after executing makeup-mirror.kcl | ||||
|     "type": "Number", | ||||
|     "value": 90.0, | ||||
|     "ty": { | ||||
|       "type": "Unknown" | ||||
|       "type": "Known", | ||||
|       "type": "Count" | ||||
|     } | ||||
|   }, | ||||
|   "archThickness": { | ||||
| @ -297,7 +298,13 @@ description: Variables in memory after executing makeup-mirror.kcl | ||||
|     "type": "Number", | ||||
|     "value": 24.0, | ||||
|     "ty": { | ||||
|       "type": "Unknown" | ||||
|       "type": "Default", | ||||
|       "len": { | ||||
|         "type": "Mm" | ||||
|       }, | ||||
|       "angle": { | ||||
|         "type": "Degrees" | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   "hingePartA1": { | ||||
| @ -1168,7 +1175,8 @@ description: Variables in memory after executing makeup-mirror.kcl | ||||
|     "type": "Number", | ||||
|     "value": 85.0, | ||||
|     "ty": { | ||||
|       "type": "Unknown" | ||||
|       "type": "Known", | ||||
|       "type": "Count" | ||||
|     } | ||||
|   }, | ||||
|   "mirrorThickness": { | ||||
|  | ||||
| @ -1036,7 +1036,13 @@ description: Operations executed pipe-flange-assembly.kcl | ||||
|           "type": "Number", | ||||
|           "value": -1.563, | ||||
|           "ty": { | ||||
|             "type": "Unknown" | ||||
|             "type": "Default", | ||||
|             "len": { | ||||
|               "type": "Inches" | ||||
|             }, | ||||
|             "angle": { | ||||
|               "type": "Degrees" | ||||
|             } | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
| @ -1236,7 +1242,13 @@ description: Operations executed pipe-flange-assembly.kcl | ||||
|           "type": "Number", | ||||
|           "value": -0.46875, | ||||
|           "ty": { | ||||
|             "type": "Unknown" | ||||
|             "type": "Default", | ||||
|             "len": { | ||||
|               "type": "Inches" | ||||
|             }, | ||||
|             "angle": { | ||||
|               "type": "Degrees" | ||||
|             } | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
| @ -1500,7 +1512,8 @@ description: Operations executed pipe-flange-assembly.kcl | ||||
|           "type": "Number", | ||||
|           "value": 0.546875, | ||||
|           "ty": { | ||||
|             "type": "Unknown" | ||||
|             "type": "Known", | ||||
|             "type": "Count" | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
| @ -1550,7 +1563,8 @@ description: Operations executed pipe-flange-assembly.kcl | ||||
|           "type": "Number", | ||||
|           "value": -0.546875, | ||||
|           "ty": { | ||||
|             "type": "Unknown" | ||||
|             "type": "Known", | ||||
|             "type": "Count" | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
|  | ||||
| @ -49,14 +49,16 @@ description: Variables in memory after executing pipe-flange-assembly.kcl | ||||
|     "type": "Number", | ||||
|     "value": 0.5, | ||||
|     "ty": { | ||||
|       "type": "Unknown" | ||||
|       "type": "Known", | ||||
|       "type": "Count" | ||||
|     } | ||||
|   }, | ||||
|   "boltHexFlatLength": { | ||||
|     "type": "Number", | ||||
|     "value": 0.2887, | ||||
|     "ty": { | ||||
|       "type": "Unknown" | ||||
|       "type": "Known", | ||||
|       "type": "Count" | ||||
|     } | ||||
|   }, | ||||
|   "boltLength": { | ||||
| @ -234,28 +236,32 @@ description: Variables in memory after executing pipe-flange-assembly.kcl | ||||
|     "type": "Number", | ||||
|     "value": 0.625, | ||||
|     "ty": { | ||||
|       "type": "Unknown" | ||||
|       "type": "Known", | ||||
|       "type": "Count" | ||||
|     } | ||||
|   }, | ||||
|   "hexNutFlatLength": { | ||||
|     "type": "Number", | ||||
|     "value": 0.5413, | ||||
|     "ty": { | ||||
|       "type": "Unknown" | ||||
|       "type": "Known", | ||||
|       "type": "Count" | ||||
|     } | ||||
|   }, | ||||
|   "hexNutFlatToFlat": { | ||||
|     "type": "Number", | ||||
|     "value": 0.9375, | ||||
|     "ty": { | ||||
|       "type": "Unknown" | ||||
|       "type": "Known", | ||||
|       "type": "Count" | ||||
|     } | ||||
|   }, | ||||
|   "hexNutThickness": { | ||||
|     "type": "Number", | ||||
|     "value": 0.5469, | ||||
|     "ty": { | ||||
|       "type": "Unknown" | ||||
|       "type": "Known", | ||||
|       "type": "Count" | ||||
|     } | ||||
|   }, | ||||
|   "mountingHoleDiameter": { | ||||
|  | ||||
| @ -201,7 +201,8 @@ description: Operations executed poopy-shoe.kcl | ||||
|                       "type": "Number", | ||||
|                       "value": -1.4375, | ||||
|                       "ty": { | ||||
|                         "type": "Unknown" | ||||
|                         "type": "Known", | ||||
|                         "type": "Count" | ||||
|                       } | ||||
|                     }, | ||||
|                     "z": { | ||||
| @ -467,7 +468,13 @@ description: Operations executed poopy-shoe.kcl | ||||
|                       "type": "Number", | ||||
|                       "value": -3.875, | ||||
|                       "ty": { | ||||
|                         "type": "Unknown" | ||||
|                         "type": "Default", | ||||
|                         "len": { | ||||
|                           "type": "Inches" | ||||
|                         }, | ||||
|                         "angle": { | ||||
|                           "type": "Degrees" | ||||
|                         } | ||||
|                       } | ||||
|                     }, | ||||
|                     "y": { | ||||
| @ -762,7 +769,13 @@ description: Operations executed poopy-shoe.kcl | ||||
|           "type": "Number", | ||||
|           "value": 2.75, | ||||
|           "ty": { | ||||
|             "type": "Unknown" | ||||
|             "type": "Default", | ||||
|             "len": { | ||||
|               "type": "Inches" | ||||
|             }, | ||||
|             "angle": { | ||||
|               "type": "Degrees" | ||||
|             } | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
| @ -797,7 +810,13 @@ description: Operations executed poopy-shoe.kcl | ||||
|                       "type": "Number", | ||||
|                       "value": -3.875, | ||||
|                       "ty": { | ||||
|                         "type": "Unknown" | ||||
|                         "type": "Default", | ||||
|                         "len": { | ||||
|                           "type": "Inches" | ||||
|                         }, | ||||
|                         "angle": { | ||||
|                           "type": "Degrees" | ||||
|                         } | ||||
|                       } | ||||
|                     }, | ||||
|                     "y": { | ||||
|  | ||||
| @ -42,7 +42,8 @@ description: Variables in memory after executing poopy-shoe.kcl | ||||
|                 "type": "Number", | ||||
|                 "value": -1.4375, | ||||
|                 "ty": { | ||||
|                   "type": "Unknown" | ||||
|                   "type": "Known", | ||||
|                   "type": "Count" | ||||
|                 } | ||||
|               }, | ||||
|               "z": { | ||||
| @ -209,7 +210,13 @@ description: Variables in memory after executing poopy-shoe.kcl | ||||
|                 "type": "Number", | ||||
|                 "value": -3.875, | ||||
|                 "ty": { | ||||
|                   "type": "Unknown" | ||||
|                   "type": "Default", | ||||
|                   "len": { | ||||
|                     "type": "Inches" | ||||
|                   }, | ||||
|                   "angle": { | ||||
|                     "type": "Degrees" | ||||
|                   } | ||||
|                 } | ||||
|               }, | ||||
|               "y": { | ||||
| @ -389,7 +396,13 @@ description: Variables in memory after executing poopy-shoe.kcl | ||||
|                 "type": "Number", | ||||
|                 "value": -3.875, | ||||
|                 "ty": { | ||||
|                   "type": "Unknown" | ||||
|                   "type": "Default", | ||||
|                   "len": { | ||||
|                     "type": "Inches" | ||||
|                   }, | ||||
|                   "angle": { | ||||
|                     "type": "Degrees" | ||||
|                   } | ||||
|                 } | ||||
|               }, | ||||
|               "y": { | ||||
|  | ||||
| @ -7930,7 +7930,8 @@ description: Variables in memory after executing router-template-cross-bar.kcl | ||||
|     "type": "Number", | ||||
|     "value": 20.75, | ||||
|     "ty": { | ||||
|       "type": "Unknown" | ||||
|       "type": "Known", | ||||
|       "type": "Count" | ||||
|     } | ||||
|   }, | ||||
|   "templateDiameter": { | ||||
|  | ||||
| @ -1924,7 +1924,8 @@ description: Variables in memory after executing router-template-slate.kcl | ||||
|     "type": "Number", | ||||
|     "value": 10.75, | ||||
|     "ty": { | ||||
|       "type": "Unknown" | ||||
|       "type": "Known", | ||||
|       "type": "Count" | ||||
|     } | ||||
|   }, | ||||
|   "length002": { | ||||
| @ -3712,7 +3713,8 @@ description: Variables in memory after executing router-template-slate.kcl | ||||
|     "type": "Number", | ||||
|     "value": 20.75, | ||||
|     "ty": { | ||||
|       "type": "Unknown" | ||||
|       "type": "Known", | ||||
|       "type": "Count" | ||||
|     } | ||||
|   }, | ||||
|   "templateDiameter": { | ||||
|  | ||||
| @ -25,7 +25,13 @@ description: Operations executed sheet-metal-bracket.kcl | ||||
|           "type": "Number", | ||||
|           "value": 5.5, | ||||
|           "ty": { | ||||
|             "type": "Unknown" | ||||
|             "type": "Default", | ||||
|             "len": { | ||||
|               "type": "Inches" | ||||
|             }, | ||||
|             "angle": { | ||||
|               "type": "Degrees" | ||||
|             } | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
| @ -51,7 +57,8 @@ description: Operations executed sheet-metal-bracket.kcl | ||||
|           "type": "Number", | ||||
|           "value": 0.5, | ||||
|           "ty": { | ||||
|             "type": "Unknown" | ||||
|             "type": "Known", | ||||
|             "type": "Count" | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
|  | ||||
| @ -1788,7 +1788,8 @@ description: Variables in memory after executing sheet-metal-bracket.kcl | ||||
|     "type": "Number", | ||||
|     "value": 0.1875, | ||||
|     "ty": { | ||||
|       "type": "Unknown" | ||||
|       "type": "Known", | ||||
|       "type": "Count" | ||||
|     } | ||||
|   }, | ||||
|   "componentBoltPatternX": { | ||||
| @ -1834,14 +1835,21 @@ description: Variables in memory after executing sheet-metal-bracket.kcl | ||||
|     "type": "Number", | ||||
|     "value": 5.5, | ||||
|     "ty": { | ||||
|       "type": "Unknown" | ||||
|       "type": "Default", | ||||
|       "len": { | ||||
|         "type": "Inches" | ||||
|       }, | ||||
|       "angle": { | ||||
|         "type": "Degrees" | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   "flangeLength": { | ||||
|     "type": "Number", | ||||
|     "value": 1.5, | ||||
|     "ty": { | ||||
|       "type": "Unknown" | ||||
|       "type": "Known", | ||||
|       "type": "Count" | ||||
|     } | ||||
|   }, | ||||
|   "hatHeight": { | ||||
| @ -3745,7 +3753,8 @@ description: Variables in memory after executing sheet-metal-bracket.kcl | ||||
|     "type": "Number", | ||||
|     "value": 0.25, | ||||
|     "ty": { | ||||
|       "type": "Unknown" | ||||
|       "type": "Known", | ||||
|       "type": "Count" | ||||
|     } | ||||
|   }, | ||||
|   "mountingBoltPatternX": { | ||||
| @ -3778,7 +3787,8 @@ description: Variables in memory after executing sheet-metal-bracket.kcl | ||||
|     "type": "Number", | ||||
|     "value": 0.75, | ||||
|     "ty": { | ||||
|       "type": "Unknown" | ||||
|       "type": "Known", | ||||
|       "type": "Count" | ||||
|     } | ||||
|   }, | ||||
|   "rightFlangeBoltPattern": { | ||||
|  | ||||
| @ -148,7 +148,13 @@ description: Operations executed socket-head-cap-screw.kcl | ||||
|           "type": "Number", | ||||
|           "value": -0.14250000000000002, | ||||
|           "ty": { | ||||
|             "type": "Unknown" | ||||
|             "type": "Default", | ||||
|             "len": { | ||||
|               "type": "Inches" | ||||
|             }, | ||||
|             "angle": { | ||||
|               "type": "Degrees" | ||||
|             } | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
|  | ||||
| @ -451,14 +451,16 @@ description: Variables in memory after executing socket-head-cap-screw.kcl | ||||
|     "type": "Number", | ||||
|     "value": 0.1563, | ||||
|     "ty": { | ||||
|       "type": "Unknown" | ||||
|       "type": "Known", | ||||
|       "type": "Count" | ||||
|     } | ||||
|   }, | ||||
|   "boltHexFlatLength": { | ||||
|     "type": "Number", | ||||
|     "value": 0.0902, | ||||
|     "ty": { | ||||
|       "type": "Unknown" | ||||
|       "type": "Known", | ||||
|       "type": "Count" | ||||
|     } | ||||
|   }, | ||||
|   "boltLength": { | ||||
|  | ||||
| @ -83,7 +83,8 @@ description: Variables in memory after executing walkie-talkie.kcl | ||||
|     "type": "Number", | ||||
|     "value": 0.48, | ||||
|     "ty": { | ||||
|       "type": "Unknown" | ||||
|       "type": "Known", | ||||
|       "type": "Count" | ||||
|     } | ||||
|   }, | ||||
|   "buttonThickness": { | ||||
| @ -254,7 +255,8 @@ description: Variables in memory after executing walkie-talkie.kcl | ||||
|     "type": "Number", | ||||
|     "value": 1.25, | ||||
|     "ty": { | ||||
|       "type": "Unknown" | ||||
|       "type": "Known", | ||||
|       "type": "Count" | ||||
|     } | ||||
|   }, | ||||
|   "speakerBoxHeight": { | ||||
|  | ||||
| @ -58,7 +58,13 @@ description: Operations executed pipe_as_arg.kcl | ||||
|           "type": "Number", | ||||
|           "value": 400.0, | ||||
|           "ty": { | ||||
|             "type": "Unknown" | ||||
|             "type": "Default", | ||||
|             "len": { | ||||
|               "type": "Mm" | ||||
|             }, | ||||
|             "angle": { | ||||
|               "type": "Degrees" | ||||
|             } | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
|  | ||||
| @ -20,14 +20,16 @@ description: Variables in memory after executing riddle_small.kcl | ||||
|     "type": "Number", | ||||
|     "value": -26.0, | ||||
|     "ty": { | ||||
|       "type": "Unknown" | ||||
|       "type": "Known", | ||||
|       "type": "Count" | ||||
|     } | ||||
|   }, | ||||
|   "oy": { | ||||
|     "type": "Number", | ||||
|     "value": 34.0, | ||||
|     "ty": { | ||||
|       "type": "Unknown" | ||||
|       "type": "Known", | ||||
|       "type": "Count" | ||||
|     } | ||||
|   }, | ||||
|   "r": { | ||||
|  | ||||
| @ -163,7 +163,13 @@ description: Operations executed rotate_after_fillet.kcl | ||||
|           "type": "Number", | ||||
|           "value": -0.46875, | ||||
|           "ty": { | ||||
|             "type": "Unknown" | ||||
|             "type": "Default", | ||||
|             "len": { | ||||
|               "type": "Mm" | ||||
|             }, | ||||
|             "angle": { | ||||
|               "type": "Degrees" | ||||
|             } | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
|  | ||||
| @ -49,14 +49,16 @@ description: Variables in memory after executing rotate_after_fillet.kcl | ||||
|     "type": "Number", | ||||
|     "value": 0.5, | ||||
|     "ty": { | ||||
|       "type": "Unknown" | ||||
|       "type": "Known", | ||||
|       "type": "Count" | ||||
|     } | ||||
|   }, | ||||
|   "boltHexFlatLength": { | ||||
|     "type": "Number", | ||||
|     "value": 0.2887, | ||||
|     "ty": { | ||||
|       "type": "Unknown" | ||||
|       "type": "Known", | ||||
|       "type": "Count" | ||||
|     } | ||||
|   }, | ||||
|   "boltLength": { | ||||
|  | ||||
| @ -163,7 +163,13 @@ description: Operations executed scale_after_fillet.kcl | ||||
|           "type": "Number", | ||||
|           "value": -0.46875, | ||||
|           "ty": { | ||||
|             "type": "Unknown" | ||||
|             "type": "Default", | ||||
|             "len": { | ||||
|               "type": "Mm" | ||||
|             }, | ||||
|             "angle": { | ||||
|               "type": "Degrees" | ||||
|             } | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
|  | ||||
| @ -49,14 +49,16 @@ description: Variables in memory after executing scale_after_fillet.kcl | ||||
|     "type": "Number", | ||||
|     "value": 0.5, | ||||
|     "ty": { | ||||
|       "type": "Unknown" | ||||
|       "type": "Known", | ||||
|       "type": "Count" | ||||
|     } | ||||
|   }, | ||||
|   "boltHexFlatLength": { | ||||
|     "type": "Number", | ||||
|     "value": 0.2887, | ||||
|     "ty": { | ||||
|       "type": "Unknown" | ||||
|       "type": "Known", | ||||
|       "type": "Count" | ||||
|     } | ||||
|   }, | ||||
|   "boltLength": { | ||||
|  | ||||
| @ -33,7 +33,8 @@ description: Variables in memory after executing sketch_on_face_after_fillets_re | ||||
|     "type": "Number", | ||||
|     "value": 1800.0, | ||||
|     "ty": { | ||||
|       "type": "Unknown" | ||||
|       "type": "Known", | ||||
|       "type": "Count" | ||||
|     } | ||||
|   }, | ||||
|   "bracket": { | ||||
|  | ||||
| @ -163,7 +163,13 @@ description: Operations executed translate_after_fillet.kcl | ||||
|           "type": "Number", | ||||
|           "value": -0.46875, | ||||
|           "ty": { | ||||
|             "type": "Unknown" | ||||
|             "type": "Default", | ||||
|             "len": { | ||||
|               "type": "Mm" | ||||
|             }, | ||||
|             "angle": { | ||||
|               "type": "Degrees" | ||||
|             } | ||||
|           } | ||||
|         }, | ||||
|         "sourceRange": [] | ||||
|  | ||||
| @ -49,14 +49,16 @@ description: Variables in memory after executing translate_after_fillet.kcl | ||||
|     "type": "Number", | ||||
|     "value": 0.5, | ||||
|     "ty": { | ||||
|       "type": "Unknown" | ||||
|       "type": "Known", | ||||
|       "type": "Count" | ||||
|     } | ||||
|   }, | ||||
|   "boltHexFlatLength": { | ||||
|     "type": "Number", | ||||
|     "value": 0.2887, | ||||
|     "ty": { | ||||
|       "type": "Unknown" | ||||
|       "type": "Known", | ||||
|       "type": "Count" | ||||
|     } | ||||
|   }, | ||||
|   "boltLength": { | ||||
|  | ||||
		Reference in New Issue
	
	Block a user