diff --git a/rust/kcl-lib/src/docs/gen_std_tests.rs b/rust/kcl-lib/src/docs/gen_std_tests.rs index 267e9da8f..086df8389 100644 --- a/rust/kcl-lib/src/docs/gen_std_tests.rs +++ b/rust/kcl-lib/src/docs/gen_std_tests.rs @@ -23,7 +23,9 @@ use crate::{ const TYPES_DIR: &str = "../../docs/kcl/types"; const LANG_TOPICS: [&str; 5] = ["Types", "Modules", "Settings", "Known Issues", "Constants"]; // These types are declared in std. -const DECLARED_TYPES: [&str; 9] = ["number", "string", "tag", "bool", "Sketch", "Solid", "Plane", "Helix", "Face"]; +const DECLARED_TYPES: [&str; 9] = [ + "number", "string", "tag", "bool", "Sketch", "Solid", "Plane", "Helix", "Face", +]; fn init_handlebars() -> Result> { let mut hbs = handlebars::Handlebars::new(); diff --git a/rust/kcl-lib/src/docs/mod.rs b/rust/kcl-lib/src/docs/mod.rs index e2f224276..44d339ff2 100644 --- a/rust/kcl-lib/src/docs/mod.rs +++ b/rust/kcl-lib/src/docs/mod.rs @@ -18,7 +18,7 @@ use tower_lsp::lsp_types::{ }; use crate::{ - execution::{kcl_value::NumericType, Sketch}, + execution::{types::NumericType, Sketch}, std::Primitive, }; diff --git a/rust/kcl-lib/src/execution/annotations.rs b/rust/kcl-lib/src/execution/annotations.rs index 5dd2ff844..b2622b4ae 100644 --- a/rust/kcl-lib/src/execution/annotations.rs +++ b/rust/kcl-lib/src/execution/annotations.rs @@ -6,7 +6,7 @@ use kittycad_modeling_cmds::coord::{System, KITTYCAD, OPENGL, VULKAN}; use crate::{ errors::KclErrorDetails, - execution::kcl_value::{UnitAngle, UnitLen}, + execution::types::{UnitAngle, UnitLen}, parsing::ast::types::{Annotation, Expr, Node, ObjectProperty}, KclError, SourceRange, }; diff --git a/rust/kcl-lib/src/execution/cad_op.rs b/rust/kcl-lib/src/execution/cad_op.rs index a77f13560..ec7c9783b 100644 --- a/rust/kcl-lib/src/execution/cad_op.rs +++ b/rust/kcl-lib/src/execution/cad_op.rs @@ -2,7 +2,7 @@ use indexmap::IndexMap; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -use super::{kcl_value::NumericType, ArtifactId, KclValue}; +use super::{types::NumericType, ArtifactId, KclValue}; use crate::{docs::StdLibFn, std::get_stdlib_fn, SourceRange}; /// A CAD modeling operation for display in the feature tree, AKA operations diff --git a/rust/kcl-lib/src/execution/exec_ast.rs b/rust/kcl-lib/src/execution/exec_ast.rs index 5ac16e04f..e49173abd 100644 --- a/rust/kcl-lib/src/execution/exec_ast.rs +++ b/rust/kcl-lib/src/execution/exec_ast.rs @@ -8,9 +8,10 @@ use crate::{ execution::{ annotations, cad_op::{OpArg, OpKclValue, Operation}, - kcl_value::{FunctionSource, NumericType, RuntimeType}, + kcl_value::FunctionSource, memory, state::ModuleState, + types::{NumericType, RuntimeType}, BodyType, EnvironmentRef, ExecState, ExecutorContext, KclValue, Metadata, PlaneType, TagEngineInfo, TagIdentifier, }, diff --git a/rust/kcl-lib/src/execution/geometry.rs b/rust/kcl-lib/src/execution/geometry.rs index d7d7c679d..a9efcb45f 100644 --- a/rust/kcl-lib/src/execution/geometry.rs +++ b/rust/kcl-lib/src/execution/geometry.rs @@ -104,7 +104,7 @@ impl From for crate::execution::KclValue { .into_iter() .map(|s| crate::execution::KclValue::Solid { value: Box::new(s) }) .collect(), - ty: crate::execution::kcl_value::RuntimeType::solid(), + ty: crate::execution::types::RuntimeType::solid(), } } } diff --git a/rust/kcl-lib/src/execution/import.rs b/rust/kcl-lib/src/execution/import.rs index b54d720e0..98ae36570 100644 --- a/rust/kcl-lib/src/execution/import.rs +++ b/rust/kcl-lib/src/execution/import.rs @@ -17,7 +17,7 @@ use uuid::Uuid; use crate::{ errors::{KclError, KclErrorDetails}, - execution::{annotations, kcl_value::UnitLen, ExecState, ExecutorContext, ImportedGeometry}, + execution::{annotations, types::UnitLen, ExecState, ExecutorContext, ImportedGeometry}, fs::FileSystem, parsing::ast::types::{Annotation, Node}, source_range::SourceRange, diff --git a/rust/kcl-lib/src/execution/kcl_value.rs b/rust/kcl-lib/src/execution/kcl_value.rs index 66d5187d9..82b1c3b7b 100644 --- a/rust/kcl-lib/src/execution/kcl_value.rs +++ b/rust/kcl-lib/src/execution/kcl_value.rs @@ -1,29 +1,20 @@ -use std::{collections::HashMap, fmt}; +use std::collections::HashMap; use anyhow::Result; use schemars::JsonSchema; -use serde::{Deserialize, Serialize}; +use serde::Serialize; -use super::{ - memory::{self, EnvironmentRef}, - MetaSettings, Point3d, -}; +use super::{memory::EnvironmentRef, MetaSettings}; use crate::{ errors::KclErrorDetails, execution::{ + types::{NumericType, PrimitiveType, RuntimeType}, ExecState, ExecutorContext, Face, Helix, ImportedGeometry, Metadata, Plane, Sketch, Solid, TagIdentifier, }, - parsing::{ - ast::types::{ - DefaultParamVal, FunctionExpression, KclNone, Literal, LiteralValue, Node, - PrimitiveType as AstPrimitiveType, TagDeclarator, TagNode, Type, - }, - token::NumericSuffix, - }, - std::{ - args::{Arg, FromKclValue}, - StdFnProps, + parsing::ast::types::{ + DefaultParamVal, FunctionExpression, KclNone, Literal, LiteralValue, Node, TagDeclarator, TagNode, }, + std::{args::Arg, StdFnProps}, CompilationError, KclError, ModuleId, SourceRange, }; @@ -559,269 +550,6 @@ impl KclValue { Ok(*b) } - /// True if `self` has a type which is a subtype of `ty` without coercion. - pub fn has_type(&self, ty: &RuntimeType) -> bool { - let Some(self_ty) = self.principal_type() else { - return false; - }; - - self_ty.subtype(ty) - } - - /// Coerce `self` to a new value which has `ty` as it's closest supertype. - /// - /// If the result is Some, then: - /// - 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 { - 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), - RuntimeType::Tuple(tys) => self.coerce_to_tuple_type(tys, exec_state), - RuntimeType::Union(tys) => self.coerce_to_union_type(tys, exec_state), - RuntimeType::Object(tys) => self.coerce_to_object_type(tys, exec_state), - } - } - - fn coerce_to_primitive_type(&self, ty: &PrimitiveType, exec_state: &mut ExecState) -> Option { - 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::String => match value { - KclValue::String { .. } => Some(value.clone()), - _ => None, - }, - PrimitiveType::Boolean => match value { - KclValue::Bool { .. } => Some(value.clone()), - _ => None, - }, - PrimitiveType::Sketch => match value { - KclValue::Sketch { .. } => Some(value.clone()), - _ => None, - }, - PrimitiveType::Solid => match value { - KclValue::Solid { .. } => Some(value.clone()), - _ => None, - }, - PrimitiveType::Plane => match value { - KclValue::Plane { .. } => Some(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 id = exec_state.mod_local.id_generator.next_uuid(); - let plane = Plane { - id, - artifact_id: id.into(), - origin, - x_axis, - y_axis, - z_axis, - value: super::PlaneType::Uninit, - // TODO use length unit from origin - units: exec_state.length_unit(), - meta: meta.clone(), - }; - - Some(KclValue::Plane { value: Box::new(plane) }) - } - _ => None, - }, - PrimitiveType::Face => match value { - KclValue::Face { .. } => Some(value.clone()), - _ => None, - }, - PrimitiveType::Helix => match value { - KclValue::Helix { .. } => Some(value.clone()), - _ => None, - }, - PrimitiveType::ImportedGeometry => match value { - KclValue::ImportedGeometry { .. } => Some(value.clone()), - _ => None, - }, - PrimitiveType::Tag => match value { - KclValue::TagDeclarator { .. } => Some(value.clone()), - KclValue::TagIdentifier { .. } => Some(value.clone()), - _ => None, - }, - } - } - - fn coerce_to_array_type(&self, ty: &RuntimeType, len: ArrayLen, exec_state: &mut ExecState) -> Option { - match self { - KclValue::HomArray { value, ty: aty } => { - // TODO could check types of values individually - if aty != ty { - return None; - } - - let value = match len { - ArrayLen::None => value.clone(), - ArrayLen::NonEmpty => { - if value.is_empty() { - return None; - } - - value.clone() - } - ArrayLen::Known(n) => { - if n != value.len() { - return None; - } - - value[..n].to_vec() - } - }; - - Some(KclValue::HomArray { value, ty: ty.clone() }) - } - KclValue::MixedArray { value, .. } => { - let value = match len { - ArrayLen::None => value.clone(), - ArrayLen::NonEmpty => { - if value.is_empty() { - return None; - } - - value.clone() - } - ArrayLen::Known(n) => { - if n != value.len() { - return None; - } - - value[..n].to_vec() - } - }; - - let value = value - .iter() - .map(|v| v.coerce(ty, exec_state)) - .collect::>>()?; - - Some(KclValue::HomArray { value, ty: ty.clone() }) - } - KclValue::KclNone { .. } if len.satisfied(0) => Some(KclValue::HomArray { - value: Vec::new(), - ty: ty.clone(), - }), - value if len.satisfied(1) => { - if value.has_type(ty) { - Some(KclValue::HomArray { - value: vec![value.clone()], - ty: ty.clone(), - }) - } else { - None - } - } - _ => None, - } - } - - fn coerce_to_tuple_type(&self, tys: &[RuntimeType], exec_state: &mut ExecState) -> Option { - match self { - KclValue::MixedArray { value, .. } | KclValue::HomArray { value, .. } => { - if value.len() < tys.len() { - return None; - } - let mut result = Vec::new(); - for (i, t) in tys.iter().enumerate() { - result.push(value[i].coerce(t, exec_state)?); - } - - Some(KclValue::MixedArray { - value: result, - meta: Vec::new(), - }) - } - KclValue::KclNone { meta, .. } if tys.is_empty() => Some(KclValue::MixedArray { - value: Vec::new(), - meta: meta.clone(), - }), - value if tys.len() == 1 => { - if value.has_type(&tys[0]) { - Some(KclValue::MixedArray { - value: vec![value.clone()], - meta: Vec::new(), - }) - } else { - None - } - } - _ => None, - } - } - - fn coerce_to_union_type(&self, tys: &[RuntimeType], exec_state: &mut ExecState) -> Option { - for t in tys { - if let Some(v) = self.coerce(t, exec_state) { - return Some(v); - } - } - - None - } - - fn coerce_to_object_type(&self, tys: &[(String, RuntimeType)], _exec_state: &mut ExecState) -> Option { - match self { - KclValue::Object { value, .. } => { - for (s, t) in tys { - // TODO coerce fields - if !value.get(s)?.has_type(t) { - return None; - } - } - // TODO remove non-required fields - Some(self.clone()) - } - _ => None, - } - } - - pub fn principal_type(&self) -> Option { - match self { - KclValue::Bool { .. } => Some(RuntimeType::Primitive(PrimitiveType::Boolean)), - KclValue::Number { ty, .. } => Some(RuntimeType::Primitive(PrimitiveType::Number(ty.clone()))), - KclValue::String { .. } => Some(RuntimeType::Primitive(PrimitiveType::String)), - KclValue::Object { value, .. } => { - let properties = value - .iter() - .map(|(k, v)| v.principal_type().map(|t| (k.clone(), t))) - .collect::>>()?; - Some(RuntimeType::Object(properties)) - } - KclValue::Plane { .. } => Some(RuntimeType::Primitive(PrimitiveType::Plane)), - KclValue::Sketch { .. } => Some(RuntimeType::Primitive(PrimitiveType::Sketch)), - KclValue::Solid { .. } => Some(RuntimeType::Primitive(PrimitiveType::Solid)), - KclValue::Face { .. } => Some(RuntimeType::Primitive(PrimitiveType::Face)), - KclValue::Helix { .. } => Some(RuntimeType::Primitive(PrimitiveType::Helix)), - KclValue::ImportedGeometry(..) => Some(RuntimeType::Primitive(PrimitiveType::ImportedGeometry)), - KclValue::MixedArray { value, .. } => Some(RuntimeType::Tuple( - value.iter().map(|v| v.principal_type()).collect::>>()?, - )), - KclValue::HomArray { ty, value, .. } => { - Some(RuntimeType::Array(Box::new(ty.clone()), ArrayLen::Known(value.len()))) - } - KclValue::TagIdentifier(_) | KclValue::TagDeclarator(_) => Some(RuntimeType::Primitive(PrimitiveType::Tag)), - KclValue::Function { .. } - | KclValue::Module { .. } - | KclValue::KclNone { .. } - | KclValue::Type { .. } - | KclValue::Uuid { .. } => None, - } - } - /// If this memory item is a function, call it with the given arguments, return its val as Ok. /// If it's not a function, return Err. pub async fn call_fn( @@ -935,486 +663,3 @@ impl KclValue { } } } - -#[derive(Debug, Clone, PartialEq)] -pub enum RuntimeType { - Primitive(PrimitiveType), - Array(Box, ArrayLen), - Union(Vec), - Tuple(Vec), - Object(Vec<(String, RuntimeType)>), -} - -impl RuntimeType { - /// `[Sketch; 1+]` - pub fn sketches() -> Self { - RuntimeType::Array( - Box::new(RuntimeType::Primitive(PrimitiveType::Sketch)), - ArrayLen::NonEmpty, - ) - } - - /// `[Solid; 1+]` - pub fn solids() -> Self { - RuntimeType::Array( - Box::new(RuntimeType::Primitive(PrimitiveType::Solid)), - ArrayLen::NonEmpty, - ) - } - - pub fn solid() -> Self { - RuntimeType::Primitive(PrimitiveType::Solid) - } - - pub fn imported() -> Self { - RuntimeType::Primitive(PrimitiveType::ImportedGeometry) - } - - pub fn from_parsed( - value: Type, - exec_state: &mut ExecState, - source_range: SourceRange, - ) -> Result { - match value { - Type::Primitive(pt) => Self::from_parsed_primitive(pt, exec_state, source_range), - Type::Array { ty, len } => { - Self::from_parsed_primitive(ty, exec_state, source_range).map(|t| RuntimeType::Array(Box::new(t), len)) - } - Type::Union { tys } => tys - .into_iter() - .map(|t| Self::from_parsed_primitive(t.inner, exec_state, source_range)) - .collect::, CompilationError>>() - .map(RuntimeType::Union), - Type::Object { properties } => properties - .into_iter() - .map(|p| { - RuntimeType::from_parsed(p.type_.unwrap().inner, exec_state, source_range) - .map(|ty| (p.identifier.inner.name, ty)) - }) - .collect::, CompilationError>>() - .map(RuntimeType::Object), - } - } - - fn from_parsed_primitive( - value: AstPrimitiveType, - exec_state: &mut ExecState, - source_range: SourceRange, - ) -> Result { - Ok(match value { - AstPrimitiveType::String => RuntimeType::Primitive(PrimitiveType::String), - AstPrimitiveType::Boolean => RuntimeType::Primitive(PrimitiveType::Boolean), - AstPrimitiveType::Number(suffix) => RuntimeType::Primitive(PrimitiveType::Number( - NumericType::from_parsed(suffix, &exec_state.mod_local.settings), - )), - AstPrimitiveType::Named(name) => { - let ty_val = exec_state - .stack() - .get(&format!("{}{}", memory::TYPE_PREFIX, name.name), source_range) - .map_err(|_| CompilationError::err(source_range, format!("Unknown type: {}", name.name)))?; - - match ty_val { - KclValue::Type { value, .. } => match value { - TypeDef::RustRepr(ty, _) => RuntimeType::Primitive(ty.clone()), - TypeDef::Alias(ty) => ty.clone(), - }, - _ => unreachable!(), - } - } - AstPrimitiveType::Tag => RuntimeType::Primitive(PrimitiveType::Tag), - }) - } - - pub fn human_friendly_type(&self) -> String { - match self { - RuntimeType::Primitive(ty) => ty.to_string(), - RuntimeType::Array(ty, ArrayLen::None) => format!("an array of {}", ty.display_multiple()), - RuntimeType::Array(ty, ArrayLen::NonEmpty) => format!("one or more {}", ty.display_multiple()), - RuntimeType::Array(ty, ArrayLen::Known(n)) => format!("an array of {n} {}", ty.display_multiple()), - RuntimeType::Union(tys) => tys - .iter() - .map(Self::human_friendly_type) - .collect::>() - .join(" or "), - RuntimeType::Tuple(tys) => format!( - "an array with values of types ({})", - tys.iter().map(Self::human_friendly_type).collect::>().join(", ") - ), - RuntimeType::Object(_) => format!("an object with fields {}", self), - } - } - - // Subtype with no coercion, including refining numeric types. - fn subtype(&self, sup: &RuntimeType) -> bool { - use RuntimeType::*; - - match (self, sup) { - (Primitive(t1), Primitive(t2)) => t1 == t2, - // TODO arrays could be covariant - (Array(t1, l1), Array(t2, l2)) => t1 == t2 && l1.subtype(*l2), - (Tuple(t1), Tuple(t2)) => t1 == t2, - (Tuple(t1), Array(t2, l2)) => (l2.satisfied(t1.len())) && t1.iter().all(|t| t == &**t2), - (Union(ts1), Union(ts2)) => ts1.iter().all(|t| ts2.contains(t)), - (t1, Union(ts2)) => ts2.contains(t1), - // TODO record subtyping - subtype can be larger, fields can be covariant. - (Object(t1), Object(t2)) => t1 == t2, - _ => false, - } - } - - fn display_multiple(&self) -> String { - match self { - RuntimeType::Primitive(ty) => ty.display_multiple(), - RuntimeType::Array(..) => "arrays".to_owned(), - RuntimeType::Union(tys) => tys - .iter() - .map(|t| t.display_multiple()) - .collect::>() - .join(" or "), - RuntimeType::Tuple(_) => "arrays".to_owned(), - RuntimeType::Object(_) => format!("objects with fields {self}"), - } - } -} - -impl fmt::Display for RuntimeType { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - RuntimeType::Primitive(t) => t.fmt(f), - RuntimeType::Array(t, l) => match l { - ArrayLen::None => write!(f, "[{t}]"), - ArrayLen::NonEmpty => write!(f, "[{t}; 1+]"), - ArrayLen::Known(n) => write!(f, "[{t}; {n}]"), - }, - RuntimeType::Tuple(ts) => write!( - f, - "[{}]", - ts.iter().map(|t| t.to_string()).collect::>().join(", ") - ), - RuntimeType::Union(ts) => write!( - f, - "{}", - ts.iter().map(|t| t.to_string()).collect::>().join(" | ") - ), - RuntimeType::Object(items) => write!( - f, - "{{ {} }}", - items - .iter() - .map(|(n, t)| format!("{n}: {t}")) - .collect::>() - .join(", ") - ), - } - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize, ts_rs::TS, JsonSchema)] -pub enum ArrayLen { - None, - NonEmpty, - Known(usize), -} - -impl ArrayLen { - pub fn subtype(self, other: ArrayLen) -> bool { - match (self, other) { - (_, ArrayLen::None) => true, - (ArrayLen::NonEmpty, ArrayLen::NonEmpty) => true, - (ArrayLen::Known(size), ArrayLen::NonEmpty) if size > 0 => true, - (ArrayLen::Known(s1), ArrayLen::Known(s2)) if s1 == s2 => true, - _ => false, - } - } - - /// True if the length constraint is satisfied by the supplied length. - fn satisfied(self, len: usize) -> bool { - match self { - ArrayLen::None => true, - ArrayLen::NonEmpty => len > 0, - ArrayLen::Known(s) => len == s, - } - } -} - -#[derive(Debug, Clone, PartialEq)] -pub enum PrimitiveType { - Number(NumericType), - String, - Boolean, - Tag, - Sketch, - Solid, - Plane, - Helix, - Face, - ImportedGeometry, -} - -impl PrimitiveType { - fn display_multiple(&self) -> String { - match self { - PrimitiveType::Number(NumericType::Known(unit)) => format!("numbers({unit})"), - PrimitiveType::Number(_) => "numbers".to_owned(), - PrimitiveType::String => "strings".to_owned(), - PrimitiveType::Boolean => "bools".to_owned(), - PrimitiveType::Sketch => "Sketches".to_owned(), - PrimitiveType::Solid => "Solids".to_owned(), - PrimitiveType::Plane => "Planes".to_owned(), - PrimitiveType::Helix => "Helices".to_owned(), - PrimitiveType::Face => "Faces".to_owned(), - PrimitiveType::ImportedGeometry => "imported geometries".to_owned(), - PrimitiveType::Tag => "tags".to_owned(), - } - } -} - -impl fmt::Display for PrimitiveType { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - PrimitiveType::Number(NumericType::Known(unit)) => write!(f, "number({unit})"), - PrimitiveType::Number(_) => write!(f, "number"), - PrimitiveType::String => write!(f, "string"), - PrimitiveType::Boolean => write!(f, "bool"), - PrimitiveType::Tag => write!(f, "tag"), - PrimitiveType::Sketch => write!(f, "Sketch"), - PrimitiveType::Solid => write!(f, "Solid"), - PrimitiveType::Plane => write!(f, "Plane"), - PrimitiveType::Face => write!(f, "Face"), - PrimitiveType::Helix => write!(f, "Helix"), - PrimitiveType::ImportedGeometry => write!(f, "imported geometry"), - } - } -} - -#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)] -#[ts(export)] -#[serde(tag = "type")] -pub enum NumericType { - // Specified by the user (directly or indirectly) - Known(UnitType), - // Unspecified, using defaults - Default { len: UnitLen, angle: UnitAngle }, - // Exceeded the ability of the type system to track. - Unknown, - // Type info has been explicitly cast away. - Any, -} - -impl NumericType { - pub fn count() -> Self { - NumericType::Known(UnitType::Count) - } - - /// 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 - } - } - - /// 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; - } - } - ty0 - } - - /// Combine two types in addition-like operations. - pub fn combine_add(a: NumericType, b: NumericType) -> NumericType { - if a == b { - return a; - } - NumericType::Unknown - } - - /// Combine two types in multiplication-like operations. - pub fn combine_mul(a: NumericType, b: NumericType) -> NumericType { - if a == NumericType::count() { - return b; - } - 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 { - match suffix { - NumericSuffix::None => NumericType::Default { - len: settings.default_length_units, - angle: settings.default_angle_units, - }, - NumericSuffix::Count => NumericType::Known(UnitType::Count), - NumericSuffix::Mm => NumericType::Known(UnitType::Length(UnitLen::Mm)), - NumericSuffix::Cm => NumericType::Known(UnitType::Length(UnitLen::Cm)), - NumericSuffix::M => NumericType::Known(UnitType::Length(UnitLen::M)), - NumericSuffix::Inch => NumericType::Known(UnitType::Length(UnitLen::Inches)), - NumericSuffix::Ft => NumericType::Known(UnitType::Length(UnitLen::Feet)), - NumericSuffix::Yd => NumericType::Known(UnitType::Length(UnitLen::Yards)), - NumericSuffix::Deg => NumericType::Known(UnitType::Angle(UnitAngle::Degrees)), - NumericSuffix::Rad => NumericType::Known(UnitType::Angle(UnitAngle::Radians)), - } - } -} - -impl From for NumericType { - fn from(value: UnitLen) -> Self { - NumericType::Known(UnitType::Length(value)) - } -} - -impl From for NumericType { - fn from(value: UnitAngle) -> Self { - NumericType::Known(UnitType::Angle(value)) - } -} - -#[derive(Debug, Clone, Copy, Deserialize, Serialize, PartialEq, Eq, ts_rs::TS, JsonSchema)] -#[ts(export)] -#[serde(tag = "type")] -pub enum UnitType { - Count, - Length(UnitLen), - Angle(UnitAngle), -} - -impl std::fmt::Display for UnitType { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - UnitType::Count => write!(f, "_"), - UnitType::Length(l) => l.fmt(f), - UnitType::Angle(a) => a.fmt(f), - } - } -} - -// TODO called UnitLen so as not to clash with UnitLength in settings) -/// A unit of length. -#[derive(Debug, Default, Clone, Copy, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema, Eq)] -#[ts(export)] -#[serde(tag = "type")] -pub enum UnitLen { - #[default] - Mm, - Cm, - M, - Inches, - Feet, - Yards, -} - -impl std::fmt::Display for UnitLen { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - UnitLen::Mm => write!(f, "mm"), - UnitLen::Cm => write!(f, "cm"), - UnitLen::M => write!(f, "m"), - UnitLen::Inches => write!(f, "in"), - UnitLen::Feet => write!(f, "ft"), - UnitLen::Yards => write!(f, "yd"), - } - } -} - -impl TryFrom for UnitLen { - type Error = (); - - fn try_from(suffix: NumericSuffix) -> std::result::Result { - match suffix { - NumericSuffix::Mm => Ok(Self::Mm), - NumericSuffix::Cm => Ok(Self::Cm), - NumericSuffix::M => Ok(Self::M), - NumericSuffix::Inch => Ok(Self::Inches), - NumericSuffix::Ft => Ok(Self::Feet), - NumericSuffix::Yd => Ok(Self::Yards), - _ => Err(()), - } - } -} - -impl From for UnitLen { - fn from(unit: crate::UnitLength) -> Self { - match unit { - crate::UnitLength::Cm => UnitLen::Cm, - crate::UnitLength::Ft => UnitLen::Feet, - crate::UnitLength::In => UnitLen::Inches, - crate::UnitLength::M => UnitLen::M, - crate::UnitLength::Mm => UnitLen::Mm, - crate::UnitLength::Yd => UnitLen::Yards, - } - } -} - -impl From for crate::UnitLength { - fn from(unit: UnitLen) -> Self { - match unit { - UnitLen::Cm => crate::UnitLength::Cm, - UnitLen::Feet => crate::UnitLength::Ft, - UnitLen::Inches => crate::UnitLength::In, - UnitLen::M => crate::UnitLength::M, - UnitLen::Mm => crate::UnitLength::Mm, - UnitLen::Yards => crate::UnitLength::Yd, - } - } -} - -impl From for kittycad_modeling_cmds::units::UnitLength { - fn from(unit: UnitLen) -> Self { - match unit { - UnitLen::Cm => kittycad_modeling_cmds::units::UnitLength::Centimeters, - UnitLen::Feet => kittycad_modeling_cmds::units::UnitLength::Feet, - UnitLen::Inches => kittycad_modeling_cmds::units::UnitLength::Inches, - UnitLen::M => kittycad_modeling_cmds::units::UnitLength::Meters, - UnitLen::Mm => kittycad_modeling_cmds::units::UnitLength::Millimeters, - UnitLen::Yards => kittycad_modeling_cmds::units::UnitLength::Yards, - } - } -} - -/// A unit of angle. -#[derive(Debug, Default, Clone, Copy, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema, Eq)] -#[ts(export)] -#[serde(tag = "type")] -pub enum UnitAngle { - #[default] - Degrees, - Radians, -} - -impl std::fmt::Display for UnitAngle { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - UnitAngle::Degrees => write!(f, "deg"), - UnitAngle::Radians => write!(f, "rad"), - } - } -} - -impl TryFrom for UnitAngle { - type Error = (); - - fn try_from(suffix: NumericSuffix) -> std::result::Result { - match suffix { - NumericSuffix::Deg => Ok(Self::Degrees), - NumericSuffix::Rad => Ok(Self::Radians), - _ => Err(()), - } - } -} diff --git a/rust/kcl-lib/src/execution/memory.rs b/rust/kcl-lib/src/execution/memory.rs index b558943d1..a1d7c330a 100644 --- a/rust/kcl-lib/src/execution/memory.rs +++ b/rust/kcl-lib/src/execution/memory.rs @@ -1055,7 +1055,7 @@ mod env { #[cfg(test)] mod test { use super::*; - use crate::execution::kcl_value::{FunctionSource, NumericType}; + use crate::execution::{kcl_value::FunctionSource, types::NumericType}; fn sr() -> SourceRange { SourceRange::default() diff --git a/rust/kcl-lib/src/execution/mod.rs b/rust/kcl-lib/src/execution/mod.rs index 891ebe005..51d8aed22 100644 --- a/rust/kcl-lib/src/execution/mod.rs +++ b/rust/kcl-lib/src/execution/mod.rs @@ -15,7 +15,7 @@ pub(crate) use import::{ import_foreign, send_to_engine as send_import_to_engine, PreImportedGeometry, ZOO_COORD_SYSTEM, }; use indexmap::IndexMap; -pub use kcl_value::{KclObjectFields, KclValue, PrimitiveType, UnitAngle, UnitLen}; +pub use kcl_value::{KclObjectFields, KclValue}; use kcmc::{ each_cmd as mcmd, ok_response::{output::TakeSnapshot, OkModelingCmdResponse}, @@ -34,6 +34,7 @@ use crate::{ execution::{ artifact::build_artifact_graph, cache::{CacheInformation, CacheResult}, + types::{UnitAngle, UnitLen}, }, fs::FileManager, modules::{ModuleId, ModulePath}, @@ -55,6 +56,7 @@ mod import; pub(crate) mod kcl_value; mod memory; mod state; +pub(crate) mod types; /// Outcome of executing a program. This is used in TS. #[derive(Debug, Clone, Serialize, ts_rs::TS)] diff --git a/rust/kcl-lib/src/execution/state.rs b/rust/kcl-lib/src/execution/state.rs index fa6242968..2f6014e71 100644 --- a/rust/kcl-lib/src/execution/state.rs +++ b/rust/kcl-lib/src/execution/state.rs @@ -12,10 +12,9 @@ use crate::{ execution::{ annotations, id_generator::IdGenerator, - kcl_value, memory::{ProgramMemory, Stack}, - Artifact, ArtifactCommand, ArtifactGraph, ArtifactId, EnvironmentRef, ExecOutcome, ExecutorSettings, KclValue, - Operation, UnitAngle, UnitLen, + types, Artifact, ArtifactCommand, ArtifactGraph, ArtifactId, EnvironmentRef, ExecOutcome, ExecutorSettings, + KclValue, Operation, UnitAngle, UnitLen, }, modules::{ModuleId, ModuleInfo, ModuleLoader, ModulePath, ModuleRepr, ModuleSource}, parsing::ast::types::Annotation, @@ -310,8 +309,8 @@ impl ModuleState { #[ts(export)] #[serde(rename_all = "camelCase")] pub struct MetaSettings { - pub default_length_units: kcl_value::UnitLen, - pub default_angle_units: kcl_value::UnitAngle, + pub default_length_units: types::UnitLen, + pub default_angle_units: types::UnitAngle, pub std_path: Option, } @@ -326,12 +325,12 @@ impl MetaSettings { match &*p.inner.key.name { annotations::SETTINGS_UNIT_LENGTH => { let value = annotations::expect_ident(&p.inner.value)?; - let value = kcl_value::UnitLen::from_str(value, annotation.as_source_range())?; + let value = types::UnitLen::from_str(value, annotation.as_source_range())?; self.default_length_units = value; } annotations::SETTINGS_UNIT_ANGLE => { let value = annotations::expect_ident(&p.inner.value)?; - let value = kcl_value::UnitAngle::from_str(value, annotation.as_source_range())?; + let value = types::UnitAngle::from_str(value, annotation.as_source_range())?; self.default_angle_units = value; } name => { diff --git a/rust/kcl-lib/src/execution/types.rs b/rust/kcl-lib/src/execution/types.rs new file mode 100644 index 000000000..8efd254ef --- /dev/null +++ b/rust/kcl-lib/src/execution/types.rs @@ -0,0 +1,770 @@ +use std::fmt; + +use anyhow::Result; +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; + +use super::{ + memory::{self}, + Point3d, +}; +use crate::{ + execution::{ + kcl_value::{KclValue, TypeDef}, + ExecState, Plane, + }, + parsing::{ + ast::types::{PrimitiveType as AstPrimitiveType, Type}, + token::NumericSuffix, + }, + std::args::FromKclValue, + CompilationError, SourceRange, +}; + +#[derive(Debug, Clone, PartialEq)] +pub enum RuntimeType { + Primitive(PrimitiveType), + Array(Box, ArrayLen), + Union(Vec), + Tuple(Vec), + Object(Vec<(String, RuntimeType)>), +} + +impl RuntimeType { + /// `[Sketch; 1+]` + pub fn sketches() -> Self { + RuntimeType::Array( + Box::new(RuntimeType::Primitive(PrimitiveType::Sketch)), + ArrayLen::NonEmpty, + ) + } + + /// `[Solid; 1+]` + pub fn solids() -> Self { + RuntimeType::Array( + Box::new(RuntimeType::Primitive(PrimitiveType::Solid)), + ArrayLen::NonEmpty, + ) + } + + pub fn solid() -> Self { + RuntimeType::Primitive(PrimitiveType::Solid) + } + + pub fn imported() -> Self { + RuntimeType::Primitive(PrimitiveType::ImportedGeometry) + } + + pub fn from_parsed( + value: Type, + exec_state: &mut ExecState, + source_range: SourceRange, + ) -> Result { + match value { + Type::Primitive(pt) => Self::from_parsed_primitive(pt, exec_state, source_range), + Type::Array { ty, len } => { + Self::from_parsed_primitive(ty, exec_state, source_range).map(|t| RuntimeType::Array(Box::new(t), len)) + } + Type::Union { tys } => tys + .into_iter() + .map(|t| Self::from_parsed_primitive(t.inner, exec_state, source_range)) + .collect::, CompilationError>>() + .map(RuntimeType::Union), + Type::Object { properties } => properties + .into_iter() + .map(|p| { + RuntimeType::from_parsed(p.type_.unwrap().inner, exec_state, source_range) + .map(|ty| (p.identifier.inner.name, ty)) + }) + .collect::, CompilationError>>() + .map(RuntimeType::Object), + } + } + + fn from_parsed_primitive( + value: AstPrimitiveType, + exec_state: &mut ExecState, + source_range: SourceRange, + ) -> Result { + Ok(match value { + AstPrimitiveType::String => RuntimeType::Primitive(PrimitiveType::String), + AstPrimitiveType::Boolean => RuntimeType::Primitive(PrimitiveType::Boolean), + AstPrimitiveType::Number(suffix) => RuntimeType::Primitive(PrimitiveType::Number( + NumericType::from_parsed(suffix, &exec_state.mod_local.settings), + )), + AstPrimitiveType::Named(name) => { + let ty_val = exec_state + .stack() + .get(&format!("{}{}", memory::TYPE_PREFIX, name.name), source_range) + .map_err(|_| CompilationError::err(source_range, format!("Unknown type: {}", name.name)))?; + + match ty_val { + KclValue::Type { value, .. } => match value { + TypeDef::RustRepr(ty, _) => RuntimeType::Primitive(ty.clone()), + TypeDef::Alias(ty) => ty.clone(), + }, + _ => unreachable!(), + } + } + AstPrimitiveType::Tag => RuntimeType::Primitive(PrimitiveType::Tag), + }) + } + + pub fn human_friendly_type(&self) -> String { + match self { + RuntimeType::Primitive(ty) => ty.to_string(), + RuntimeType::Array(ty, ArrayLen::None) => format!("an array of {}", ty.display_multiple()), + RuntimeType::Array(ty, ArrayLen::NonEmpty) => format!("one or more {}", ty.display_multiple()), + RuntimeType::Array(ty, ArrayLen::Known(n)) => format!("an array of {n} {}", ty.display_multiple()), + RuntimeType::Union(tys) => tys + .iter() + .map(Self::human_friendly_type) + .collect::>() + .join(" or "), + RuntimeType::Tuple(tys) => format!( + "an array with values of types ({})", + tys.iter().map(Self::human_friendly_type).collect::>().join(", ") + ), + RuntimeType::Object(_) => format!("an object with fields {}", self), + } + } + + // Subtype with no coercion, including refining numeric types. + fn subtype(&self, sup: &RuntimeType) -> bool { + use RuntimeType::*; + + match (self, sup) { + (Primitive(t1), Primitive(t2)) => t1 == t2, + // TODO arrays could be covariant + (Array(t1, l1), Array(t2, l2)) => t1 == t2 && l1.subtype(*l2), + (Tuple(t1), Tuple(t2)) => t1 == t2, + (Tuple(t1), Array(t2, l2)) => (l2.satisfied(t1.len())) && t1.iter().all(|t| t == &**t2), + (Union(ts1), Union(ts2)) => ts1.iter().all(|t| ts2.contains(t)), + (t1, Union(ts2)) => ts2.contains(t1), + // TODO record subtyping - subtype can be larger, fields can be covariant. + (Object(t1), Object(t2)) => t1 == t2, + _ => false, + } + } + + fn display_multiple(&self) -> String { + match self { + RuntimeType::Primitive(ty) => ty.display_multiple(), + RuntimeType::Array(..) => "arrays".to_owned(), + RuntimeType::Union(tys) => tys + .iter() + .map(|t| t.display_multiple()) + .collect::>() + .join(" or "), + RuntimeType::Tuple(_) => "arrays".to_owned(), + RuntimeType::Object(_) => format!("objects with fields {self}"), + } + } +} + +impl fmt::Display for RuntimeType { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + RuntimeType::Primitive(t) => t.fmt(f), + RuntimeType::Array(t, l) => match l { + ArrayLen::None => write!(f, "[{t}]"), + ArrayLen::NonEmpty => write!(f, "[{t}; 1+]"), + ArrayLen::Known(n) => write!(f, "[{t}; {n}]"), + }, + RuntimeType::Tuple(ts) => write!( + f, + "[{}]", + ts.iter().map(|t| t.to_string()).collect::>().join(", ") + ), + RuntimeType::Union(ts) => write!( + f, + "{}", + ts.iter().map(|t| t.to_string()).collect::>().join(" | ") + ), + RuntimeType::Object(items) => write!( + f, + "{{ {} }}", + items + .iter() + .map(|(n, t)| format!("{n}: {t}")) + .collect::>() + .join(", ") + ), + } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize, ts_rs::TS, JsonSchema)] +pub enum ArrayLen { + None, + NonEmpty, + Known(usize), +} + +impl ArrayLen { + pub fn subtype(self, other: ArrayLen) -> bool { + match (self, other) { + (_, ArrayLen::None) => true, + (ArrayLen::NonEmpty, ArrayLen::NonEmpty) => true, + (ArrayLen::Known(size), ArrayLen::NonEmpty) if size > 0 => true, + (ArrayLen::Known(s1), ArrayLen::Known(s2)) if s1 == s2 => true, + _ => false, + } + } + + /// True if the length constraint is satisfied by the supplied length. + fn satisfied(self, len: usize) -> bool { + match self { + ArrayLen::None => true, + ArrayLen::NonEmpty => len > 0, + ArrayLen::Known(s) => len == s, + } + } +} + +#[derive(Debug, Clone, PartialEq)] +pub enum PrimitiveType { + Number(NumericType), + String, + Boolean, + Tag, + Sketch, + Solid, + Plane, + Helix, + Face, + ImportedGeometry, +} + +impl PrimitiveType { + fn display_multiple(&self) -> String { + match self { + PrimitiveType::Number(NumericType::Known(unit)) => format!("numbers({unit})"), + PrimitiveType::Number(_) => "numbers".to_owned(), + PrimitiveType::String => "strings".to_owned(), + PrimitiveType::Boolean => "bools".to_owned(), + PrimitiveType::Sketch => "Sketches".to_owned(), + PrimitiveType::Solid => "Solids".to_owned(), + PrimitiveType::Plane => "Planes".to_owned(), + PrimitiveType::Helix => "Helices".to_owned(), + PrimitiveType::Face => "Faces".to_owned(), + PrimitiveType::ImportedGeometry => "imported geometries".to_owned(), + PrimitiveType::Tag => "tags".to_owned(), + } + } +} + +impl fmt::Display for PrimitiveType { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + PrimitiveType::Number(NumericType::Known(unit)) => write!(f, "number({unit})"), + PrimitiveType::Number(_) => write!(f, "number"), + PrimitiveType::String => write!(f, "string"), + PrimitiveType::Boolean => write!(f, "bool"), + PrimitiveType::Tag => write!(f, "tag"), + PrimitiveType::Sketch => write!(f, "Sketch"), + PrimitiveType::Solid => write!(f, "Solid"), + PrimitiveType::Plane => write!(f, "Plane"), + PrimitiveType::Face => write!(f, "Face"), + PrimitiveType::Helix => write!(f, "Helix"), + PrimitiveType::ImportedGeometry => write!(f, "imported geometry"), + } + } +} + +#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)] +#[ts(export)] +#[serde(tag = "type")] +pub enum NumericType { + // Specified by the user (directly or indirectly) + Known(UnitType), + // Unspecified, using defaults + Default { len: UnitLen, angle: UnitAngle }, + // Exceeded the ability of the type system to track. + Unknown, + // Type info has been explicitly cast away. + Any, +} + +impl NumericType { + pub fn count() -> Self { + NumericType::Known(UnitType::Count) + } + + /// 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 + } + } + + /// 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; + } + } + ty0 + } + + /// Combine two types in addition-like operations. + pub fn combine_add(a: NumericType, b: NumericType) -> NumericType { + if a == b { + return a; + } + NumericType::Unknown + } + + /// Combine two types in multiplication-like operations. + pub fn combine_mul(a: NumericType, b: NumericType) -> NumericType { + if a == NumericType::count() { + return b; + } + 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 { + match suffix { + NumericSuffix::None => NumericType::Default { + len: settings.default_length_units, + angle: settings.default_angle_units, + }, + NumericSuffix::Count => NumericType::Known(UnitType::Count), + NumericSuffix::Mm => NumericType::Known(UnitType::Length(UnitLen::Mm)), + NumericSuffix::Cm => NumericType::Known(UnitType::Length(UnitLen::Cm)), + NumericSuffix::M => NumericType::Known(UnitType::Length(UnitLen::M)), + NumericSuffix::Inch => NumericType::Known(UnitType::Length(UnitLen::Inches)), + NumericSuffix::Ft => NumericType::Known(UnitType::Length(UnitLen::Feet)), + NumericSuffix::Yd => NumericType::Known(UnitType::Length(UnitLen::Yards)), + NumericSuffix::Deg => NumericType::Known(UnitType::Angle(UnitAngle::Degrees)), + NumericSuffix::Rad => NumericType::Known(UnitType::Angle(UnitAngle::Radians)), + } + } +} + +impl From for NumericType { + fn from(value: UnitLen) -> Self { + NumericType::Known(UnitType::Length(value)) + } +} + +impl From for NumericType { + fn from(value: UnitAngle) -> Self { + NumericType::Known(UnitType::Angle(value)) + } +} + +#[derive(Debug, Clone, Copy, Deserialize, Serialize, PartialEq, Eq, ts_rs::TS, JsonSchema)] +#[ts(export)] +#[serde(tag = "type")] +pub enum UnitType { + Count, + Length(UnitLen), + Angle(UnitAngle), +} + +impl std::fmt::Display for UnitType { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + UnitType::Count => write!(f, "_"), + UnitType::Length(l) => l.fmt(f), + UnitType::Angle(a) => a.fmt(f), + } + } +} + +// TODO called UnitLen so as not to clash with UnitLength in settings) +/// A unit of length. +#[derive(Debug, Default, Clone, Copy, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema, Eq)] +#[ts(export)] +#[serde(tag = "type")] +pub enum UnitLen { + #[default] + Mm, + Cm, + M, + Inches, + Feet, + Yards, +} + +impl std::fmt::Display for UnitLen { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + UnitLen::Mm => write!(f, "mm"), + UnitLen::Cm => write!(f, "cm"), + UnitLen::M => write!(f, "m"), + UnitLen::Inches => write!(f, "in"), + UnitLen::Feet => write!(f, "ft"), + UnitLen::Yards => write!(f, "yd"), + } + } +} + +impl TryFrom for UnitLen { + type Error = (); + + fn try_from(suffix: NumericSuffix) -> std::result::Result { + match suffix { + NumericSuffix::Mm => Ok(Self::Mm), + NumericSuffix::Cm => Ok(Self::Cm), + NumericSuffix::M => Ok(Self::M), + NumericSuffix::Inch => Ok(Self::Inches), + NumericSuffix::Ft => Ok(Self::Feet), + NumericSuffix::Yd => Ok(Self::Yards), + _ => Err(()), + } + } +} + +impl From for UnitLen { + fn from(unit: crate::UnitLength) -> Self { + match unit { + crate::UnitLength::Cm => UnitLen::Cm, + crate::UnitLength::Ft => UnitLen::Feet, + crate::UnitLength::In => UnitLen::Inches, + crate::UnitLength::M => UnitLen::M, + crate::UnitLength::Mm => UnitLen::Mm, + crate::UnitLength::Yd => UnitLen::Yards, + } + } +} + +impl From for crate::UnitLength { + fn from(unit: UnitLen) -> Self { + match unit { + UnitLen::Cm => crate::UnitLength::Cm, + UnitLen::Feet => crate::UnitLength::Ft, + UnitLen::Inches => crate::UnitLength::In, + UnitLen::M => crate::UnitLength::M, + UnitLen::Mm => crate::UnitLength::Mm, + UnitLen::Yards => crate::UnitLength::Yd, + } + } +} + +impl From for kittycad_modeling_cmds::units::UnitLength { + fn from(unit: UnitLen) -> Self { + match unit { + UnitLen::Cm => kittycad_modeling_cmds::units::UnitLength::Centimeters, + UnitLen::Feet => kittycad_modeling_cmds::units::UnitLength::Feet, + UnitLen::Inches => kittycad_modeling_cmds::units::UnitLength::Inches, + UnitLen::M => kittycad_modeling_cmds::units::UnitLength::Meters, + UnitLen::Mm => kittycad_modeling_cmds::units::UnitLength::Millimeters, + UnitLen::Yards => kittycad_modeling_cmds::units::UnitLength::Yards, + } + } +} + +/// A unit of angle. +#[derive(Debug, Default, Clone, Copy, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema, Eq)] +#[ts(export)] +#[serde(tag = "type")] +pub enum UnitAngle { + #[default] + Degrees, + Radians, +} + +impl std::fmt::Display for UnitAngle { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + UnitAngle::Degrees => write!(f, "deg"), + UnitAngle::Radians => write!(f, "rad"), + } + } +} + +impl TryFrom for UnitAngle { + type Error = (); + + fn try_from(suffix: NumericSuffix) -> std::result::Result { + match suffix { + NumericSuffix::Deg => Ok(Self::Degrees), + NumericSuffix::Rad => Ok(Self::Radians), + _ => Err(()), + } + } +} + +impl KclValue { + /// True if `self` has a type which is a subtype of `ty` without coercion. + pub fn has_type(&self, ty: &RuntimeType) -> bool { + let Some(self_ty) = self.principal_type() else { + return false; + }; + + self_ty.subtype(ty) + } + + /// Coerce `self` to a new value which has `ty` as it's closest supertype. + /// + /// If the result is Some, then: + /// - 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 { + 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), + RuntimeType::Tuple(tys) => self.coerce_to_tuple_type(tys, exec_state), + RuntimeType::Union(tys) => self.coerce_to_union_type(tys, exec_state), + RuntimeType::Object(tys) => self.coerce_to_object_type(tys, exec_state), + } + } + + fn coerce_to_primitive_type(&self, ty: &PrimitiveType, exec_state: &mut ExecState) -> Option { + 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::String => match value { + KclValue::String { .. } => Some(value.clone()), + _ => None, + }, + PrimitiveType::Boolean => match value { + KclValue::Bool { .. } => Some(value.clone()), + _ => None, + }, + PrimitiveType::Sketch => match value { + KclValue::Sketch { .. } => Some(value.clone()), + _ => None, + }, + PrimitiveType::Solid => match value { + KclValue::Solid { .. } => Some(value.clone()), + _ => None, + }, + PrimitiveType::Plane => match value { + KclValue::Plane { .. } => Some(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 id = exec_state.mod_local.id_generator.next_uuid(); + let plane = Plane { + id, + artifact_id: id.into(), + origin, + x_axis, + y_axis, + z_axis, + value: super::PlaneType::Uninit, + // TODO use length unit from origin + units: exec_state.length_unit(), + meta: meta.clone(), + }; + + Some(KclValue::Plane { value: Box::new(plane) }) + } + _ => None, + }, + PrimitiveType::Face => match value { + KclValue::Face { .. } => Some(value.clone()), + _ => None, + }, + PrimitiveType::Helix => match value { + KclValue::Helix { .. } => Some(value.clone()), + _ => None, + }, + PrimitiveType::ImportedGeometry => match value { + KclValue::ImportedGeometry { .. } => Some(value.clone()), + _ => None, + }, + PrimitiveType::Tag => match value { + KclValue::TagDeclarator { .. } => Some(value.clone()), + KclValue::TagIdentifier { .. } => Some(value.clone()), + _ => None, + }, + } + } + + fn coerce_to_array_type(&self, ty: &RuntimeType, len: ArrayLen, exec_state: &mut ExecState) -> Option { + match self { + KclValue::HomArray { value, ty: aty } => { + // TODO could check types of values individually + if aty != ty { + return None; + } + + let value = match len { + ArrayLen::None => value.clone(), + ArrayLen::NonEmpty => { + if value.is_empty() { + return None; + } + + value.clone() + } + ArrayLen::Known(n) => { + if n != value.len() { + return None; + } + + value[..n].to_vec() + } + }; + + Some(KclValue::HomArray { value, ty: ty.clone() }) + } + KclValue::MixedArray { value, .. } => { + let value = match len { + ArrayLen::None => value.clone(), + ArrayLen::NonEmpty => { + if value.is_empty() { + return None; + } + + value.clone() + } + ArrayLen::Known(n) => { + if n != value.len() { + return None; + } + + value[..n].to_vec() + } + }; + + let value = value + .iter() + .map(|v| v.coerce(ty, exec_state)) + .collect::>>()?; + + Some(KclValue::HomArray { value, ty: ty.clone() }) + } + KclValue::KclNone { .. } if len.satisfied(0) => Some(KclValue::HomArray { + value: Vec::new(), + ty: ty.clone(), + }), + value if len.satisfied(1) => { + if value.has_type(ty) { + Some(KclValue::HomArray { + value: vec![value.clone()], + ty: ty.clone(), + }) + } else { + None + } + } + _ => None, + } + } + + fn coerce_to_tuple_type(&self, tys: &[RuntimeType], exec_state: &mut ExecState) -> Option { + match self { + KclValue::MixedArray { value, .. } | KclValue::HomArray { value, .. } => { + if value.len() < tys.len() { + return None; + } + let mut result = Vec::new(); + for (i, t) in tys.iter().enumerate() { + result.push(value[i].coerce(t, exec_state)?); + } + + Some(KclValue::MixedArray { + value: result, + meta: Vec::new(), + }) + } + KclValue::KclNone { meta, .. } if tys.is_empty() => Some(KclValue::MixedArray { + value: Vec::new(), + meta: meta.clone(), + }), + value if tys.len() == 1 => { + if value.has_type(&tys[0]) { + Some(KclValue::MixedArray { + value: vec![value.clone()], + meta: Vec::new(), + }) + } else { + None + } + } + _ => None, + } + } + + fn coerce_to_union_type(&self, tys: &[RuntimeType], exec_state: &mut ExecState) -> Option { + for t in tys { + if let Some(v) = self.coerce(t, exec_state) { + return Some(v); + } + } + + None + } + + fn coerce_to_object_type(&self, tys: &[(String, RuntimeType)], _exec_state: &mut ExecState) -> Option { + match self { + KclValue::Object { value, .. } => { + for (s, t) in tys { + // TODO coerce fields + if !value.get(s)?.has_type(t) { + return None; + } + } + // TODO remove non-required fields + Some(self.clone()) + } + _ => None, + } + } + + pub fn principal_type(&self) -> Option { + match self { + KclValue::Bool { .. } => Some(RuntimeType::Primitive(PrimitiveType::Boolean)), + KclValue::Number { ty, .. } => Some(RuntimeType::Primitive(PrimitiveType::Number(ty.clone()))), + KclValue::String { .. } => Some(RuntimeType::Primitive(PrimitiveType::String)), + KclValue::Object { value, .. } => { + let properties = value + .iter() + .map(|(k, v)| v.principal_type().map(|t| (k.clone(), t))) + .collect::>>()?; + Some(RuntimeType::Object(properties)) + } + KclValue::Plane { .. } => Some(RuntimeType::Primitive(PrimitiveType::Plane)), + KclValue::Sketch { .. } => Some(RuntimeType::Primitive(PrimitiveType::Sketch)), + KclValue::Solid { .. } => Some(RuntimeType::Primitive(PrimitiveType::Solid)), + KclValue::Face { .. } => Some(RuntimeType::Primitive(PrimitiveType::Face)), + KclValue::Helix { .. } => Some(RuntimeType::Primitive(PrimitiveType::Helix)), + KclValue::ImportedGeometry(..) => Some(RuntimeType::Primitive(PrimitiveType::ImportedGeometry)), + KclValue::MixedArray { value, .. } => Some(RuntimeType::Tuple( + value.iter().map(|v| v.principal_type()).collect::>>()?, + )), + KclValue::HomArray { ty, value, .. } => { + Some(RuntimeType::Array(Box::new(ty.clone()), ArrayLen::Known(value.len()))) + } + KclValue::TagIdentifier(_) | KclValue::TagDeclarator(_) => Some(RuntimeType::Primitive(PrimitiveType::Tag)), + KclValue::Function { .. } + | KclValue::Module { .. } + | KclValue::KclNone { .. } + | KclValue::Type { .. } + | KclValue::Uuid { .. } => None, + } + } +} diff --git a/rust/kcl-lib/src/parsing/ast/digest.rs b/rust/kcl-lib/src/parsing/ast/digest.rs index 2b519ddd8..1c46e5617 100644 --- a/rust/kcl-lib/src/parsing/ast/digest.rs +++ b/rust/kcl-lib/src/parsing/ast/digest.rs @@ -198,9 +198,9 @@ impl Type { hasher.update(b"FnArgType::Array"); hasher.update(ty.compute_digest()); match len { - crate::execution::kcl_value::ArrayLen::None => {} - crate::execution::kcl_value::ArrayLen::NonEmpty => hasher.update(usize::MAX.to_ne_bytes()), - crate::execution::kcl_value::ArrayLen::Known(n) => hasher.update(n.to_ne_bytes()), + crate::execution::types::ArrayLen::None => {} + crate::execution::types::ArrayLen::NonEmpty => hasher.update(usize::MAX.to_ne_bytes()), + crate::execution::types::ArrayLen::Known(n) => hasher.update(n.to_ne_bytes()), } } Type::Union { tys } => { diff --git a/rust/kcl-lib/src/parsing/ast/types/mod.rs b/rust/kcl-lib/src/parsing/ast/types/mod.rs index 799f4c23f..1fab38613 100644 --- a/rust/kcl-lib/src/parsing/ast/types/mod.rs +++ b/rust/kcl-lib/src/parsing/ast/types/mod.rs @@ -25,7 +25,7 @@ pub use crate::parsing::ast::types::{ use crate::{ docs::StdLibFn, errors::KclError, - execution::{annotations, kcl_value::ArrayLen, KclValue, Metadata, TagIdentifier}, + execution::{annotations, types::ArrayLen, KclValue, Metadata, TagIdentifier}, parsing::{ast::digest::Digest, token::NumericSuffix, PIPE_OPERATOR}, source_range::SourceRange, ModuleId, @@ -3994,7 +3994,7 @@ startSketchOn('XY')"#; assert_eq!( meta_settings.default_length_units, - crate::execution::kcl_value::UnitLen::Inches + crate::execution::types::UnitLen::Inches ); } @@ -4010,13 +4010,13 @@ startSketchOn('XY')"#; assert_eq!( meta_settings.default_length_units, - crate::execution::kcl_value::UnitLen::Inches + crate::execution::types::UnitLen::Inches ); // Edit the ast. let new_program = program .change_meta_settings(crate::execution::MetaSettings { - default_length_units: crate::execution::kcl_value::UnitLen::Mm, + default_length_units: crate::execution::types::UnitLen::Mm, ..Default::default() }) .unwrap(); @@ -4025,10 +4025,7 @@ startSketchOn('XY')"#; assert!(result.is_some()); let meta_settings = result.unwrap(); - assert_eq!( - meta_settings.default_length_units, - crate::execution::kcl_value::UnitLen::Mm - ); + assert_eq!(meta_settings.default_length_units, crate::execution::types::UnitLen::Mm); let formatted = new_program.recast(&Default::default(), 0); @@ -4051,7 +4048,7 @@ startSketchOn('XY') // Edit the ast. let new_program = program .change_meta_settings(crate::execution::MetaSettings { - default_length_units: crate::execution::kcl_value::UnitLen::Mm, + default_length_units: crate::execution::types::UnitLen::Mm, ..Default::default() }) .unwrap(); @@ -4060,10 +4057,7 @@ startSketchOn('XY') assert!(result.is_some()); let meta_settings = result.unwrap(); - assert_eq!( - meta_settings.default_length_units, - crate::execution::kcl_value::UnitLen::Mm - ); + assert_eq!(meta_settings.default_length_units, crate::execution::types::UnitLen::Mm); let formatted = new_program.recast(&Default::default(), 0); diff --git a/rust/kcl-lib/src/parsing/parser.rs b/rust/kcl-lib/src/parsing/parser.rs index 09e465b59..2a9098f4a 100644 --- a/rust/kcl-lib/src/parsing/parser.rs +++ b/rust/kcl-lib/src/parsing/parser.rs @@ -19,7 +19,7 @@ use super::{ use crate::{ docs::StdLibFn, errors::{CompilationError, Severity, Tag}, - execution::kcl_value::ArrayLen, + execution::types::ArrayLen, parsing::{ ast::types::{ Annotation, ArrayExpression, ArrayRangeExpression, BinaryExpression, BinaryOperator, BinaryPart, BodyItem, diff --git a/rust/kcl-lib/src/std/appearance.rs b/rust/kcl-lib/src/std/appearance.rs index 3d3dfdcab..c19620bf9 100644 --- a/rust/kcl-lib/src/std/appearance.rs +++ b/rust/kcl-lib/src/std/appearance.rs @@ -12,7 +12,7 @@ use validator::Validate; use crate::{ errors::{KclError, KclErrorDetails}, - execution::{kcl_value::RuntimeType, ExecState, KclValue, Solid}, + execution::{types::RuntimeType, ExecState, KclValue, Solid}, std::Args, }; diff --git a/rust/kcl-lib/src/std/args.rs b/rust/kcl-lib/src/std/args.rs index 26785262f..453543220 100644 --- a/rust/kcl-lib/src/std/args.rs +++ b/rust/kcl-lib/src/std/args.rs @@ -12,9 +12,10 @@ use serde::{Deserialize, Serialize}; use crate::{ errors::{KclError, KclErrorDetails}, execution::{ - kcl_value::{FunctionSource, NumericType, RuntimeType}, - ExecState, ExecutorContext, ExtrudeSurface, Helix, KclObjectFields, KclValue, Metadata, PrimitiveType, Sketch, - SketchSurface, Solid, TagIdentifier, + kcl_value::FunctionSource, + types::{NumericType, PrimitiveType, RuntimeType}, + ExecState, ExecutorContext, ExtrudeSurface, Helix, KclObjectFields, KclValue, Metadata, Sketch, SketchSurface, + Solid, TagIdentifier, }, parsing::ast::types::TagNode, source_range::SourceRange, diff --git a/rust/kcl-lib/src/std/chamfer.rs b/rust/kcl-lib/src/std/chamfer.rs index 083a00bce..7d4cdf1bb 100644 --- a/rust/kcl-lib/src/std/chamfer.rs +++ b/rust/kcl-lib/src/std/chamfer.rs @@ -8,8 +8,8 @@ use kittycad_modeling_cmds as kcmc; use crate::{ errors::{KclError, KclErrorDetails}, execution::{ - kcl_value::RuntimeType, ChamferSurface, EdgeCut, ExecState, ExtrudeSurface, GeoMeta, KclValue, PrimitiveType, - Solid, + types::{PrimitiveType, RuntimeType}, + ChamferSurface, EdgeCut, ExecState, ExtrudeSurface, GeoMeta, KclValue, Solid, }, parsing::ast::types::TagNode, std::{fillet::EdgeReference, Args}, diff --git a/rust/kcl-lib/src/std/extrude.rs b/rust/kcl-lib/src/std/extrude.rs index b973bd464..03a10e6bb 100644 --- a/rust/kcl-lib/src/std/extrude.rs +++ b/rust/kcl-lib/src/std/extrude.rs @@ -19,7 +19,7 @@ use uuid::Uuid; use crate::{ errors::{KclError, KclErrorDetails}, execution::{ - kcl_value::RuntimeType, ArtifactId, ExecState, ExtrudeSurface, GeoMeta, KclValue, Path, Sketch, SketchSurface, + types::RuntimeType, ArtifactId, ExecState, ExtrudeSurface, GeoMeta, KclValue, Path, Sketch, SketchSurface, Solid, }, parsing::ast::types::TagNode, diff --git a/rust/kcl-lib/src/std/fillet.rs b/rust/kcl-lib/src/std/fillet.rs index 6f9afee10..0aa08dfcc 100644 --- a/rust/kcl-lib/src/std/fillet.rs +++ b/rust/kcl-lib/src/std/fillet.rs @@ -11,8 +11,8 @@ use serde::{Deserialize, Serialize}; use crate::{ errors::{KclError, KclErrorDetails}, execution::{ - kcl_value::RuntimeType, EdgeCut, ExecState, ExtrudeSurface, FilletSurface, GeoMeta, KclValue, PrimitiveType, - Solid, TagIdentifier, + types::{PrimitiveType, RuntimeType}, + EdgeCut, ExecState, ExtrudeSurface, FilletSurface, GeoMeta, KclValue, Solid, TagIdentifier, }, parsing::ast::types::TagNode, settings::types::UnitLength, diff --git a/rust/kcl-lib/src/std/loft.rs b/rust/kcl-lib/src/std/loft.rs index ab7c4a5c2..1cc0ee659 100644 --- a/rust/kcl-lib/src/std/loft.rs +++ b/rust/kcl-lib/src/std/loft.rs @@ -9,7 +9,7 @@ use kittycad_modeling_cmds as kcmc; use crate::{ errors::{KclError, KclErrorDetails}, - execution::{kcl_value::RuntimeType, ExecState, KclValue, Sketch, Solid}, + execution::{types::RuntimeType, ExecState, KclValue, Sketch, Solid}, std::{extrude::do_post_extrude, fillet::default_tolerance, Args}, }; diff --git a/rust/kcl-lib/src/std/mod.rs b/rust/kcl-lib/src/std/mod.rs index b7977a82f..e2af54d5e 100644 --- a/rust/kcl-lib/src/std/mod.rs +++ b/rust/kcl-lib/src/std/mod.rs @@ -42,7 +42,7 @@ use serde::{Deserialize, Serialize}; use crate::{ docs::StdLibFn, errors::KclError, - execution::{ExecState, KclValue}, + execution::{types::PrimitiveType, ExecState, KclValue}, }; pub type StdFn = fn( @@ -207,25 +207,13 @@ pub(crate) fn std_fn(path: &str, fn_name: &str) -> (crate::std::StdFn, StdFnProp } } -pub(crate) fn std_ty(path: &str, fn_name: &str) -> (crate::execution::PrimitiveType, StdFnProps) { +pub(crate) fn std_ty(path: &str, fn_name: &str) -> (PrimitiveType, StdFnProps) { match (path, fn_name) { - ("prelude", "Sketch") => ( - crate::execution::PrimitiveType::Sketch, - StdFnProps::default("std::Sketch"), - ), - ("prelude", "Solid") => ( - crate::execution::PrimitiveType::Solid, - StdFnProps::default("std::Solid"), - ), - ("prelude", "Plane") => ( - crate::execution::PrimitiveType::Plane, - StdFnProps::default("std::Plane"), - ), - ("prelude", "Face") => (crate::execution::PrimitiveType::Face, StdFnProps::default("std::Face")), - ("prelude", "Helix") => ( - crate::execution::PrimitiveType::Helix, - StdFnProps::default("std::Helix"), - ), + ("prelude", "Sketch") => (PrimitiveType::Sketch, StdFnProps::default("std::Sketch")), + ("prelude", "Solid") => (PrimitiveType::Solid, StdFnProps::default("std::Solid")), + ("prelude", "Plane") => (PrimitiveType::Plane, StdFnProps::default("std::Plane")), + ("prelude", "Face") => (PrimitiveType::Face, StdFnProps::default("std::Face")), + ("prelude", "Helix") => (PrimitiveType::Helix, StdFnProps::default("std::Helix")), _ => unreachable!(), } } diff --git a/rust/kcl-lib/src/std/patterns.rs b/rust/kcl-lib/src/std/patterns.rs index eafaecb53..184bbc7a8 100644 --- a/rust/kcl-lib/src/std/patterns.rs +++ b/rust/kcl-lib/src/std/patterns.rs @@ -20,7 +20,8 @@ use super::args::Arg; use crate::{ errors::{KclError, KclErrorDetails}, execution::{ - kcl_value::{FunctionSource, NumericType, RuntimeType}, + kcl_value::FunctionSource, + types::{NumericType, RuntimeType}, ExecState, Geometries, Geometry, KclObjectFields, KclValue, Point2d, Point3d, Sketch, Solid, }, std::Args, @@ -656,7 +657,7 @@ impl GeometryTrait for Solid { #[cfg(test)] mod tests { use super::*; - use crate::execution::kcl_value::NumericType; + use crate::execution::types::NumericType; #[test] fn test_array_to_point3d() { diff --git a/rust/kcl-lib/src/std/segment.rs b/rust/kcl-lib/src/std/segment.rs index 1f5be0898..7f4a3f420 100644 --- a/rust/kcl-lib/src/std/segment.rs +++ b/rust/kcl-lib/src/std/segment.rs @@ -6,7 +6,10 @@ use kittycad_modeling_cmds::shared::Angle; use crate::{ errors::{KclError, KclErrorDetails}, - execution::{kcl_value::RuntimeType, ExecState, KclValue, Point2d, PrimitiveType, Sketch, TagIdentifier}, + execution::{ + types::{PrimitiveType, RuntimeType}, + ExecState, KclValue, Point2d, Sketch, TagIdentifier, + }, std::{utils::between, Args}, }; diff --git a/rust/kcl-lib/src/std/shell.rs b/rust/kcl-lib/src/std/shell.rs index 37c7c18d3..618696f7c 100644 --- a/rust/kcl-lib/src/std/shell.rs +++ b/rust/kcl-lib/src/std/shell.rs @@ -7,7 +7,7 @@ use kittycad_modeling_cmds as kcmc; use crate::{ errors::{KclError, KclErrorDetails}, - execution::{kcl_value::RuntimeType, ExecState, KclValue, Solid}, + execution::{types::RuntimeType, ExecState, KclValue, Solid}, std::{sketch::FaceTag, Args}, }; diff --git a/rust/kcl-lib/src/std/sketch.rs b/rust/kcl-lib/src/std/sketch.rs index 23fe6ae3d..5c06a4b1b 100644 --- a/rust/kcl-lib/src/std/sketch.rs +++ b/rust/kcl-lib/src/std/sketch.rs @@ -14,9 +14,9 @@ use serde::{Deserialize, Serialize}; use crate::{ errors::{KclError, KclErrorDetails}, execution::{ - kcl_value::RuntimeType, Artifact, ArtifactId, BasePath, CodeRef, ExecState, Face, GeoMeta, KclValue, Path, - Plane, Point2d, Point3d, PrimitiveType, Sketch, SketchSurface, Solid, StartSketchOnFace, StartSketchOnPlane, - TagEngineInfo, TagIdentifier, + types::{PrimitiveType, RuntimeType}, + Artifact, ArtifactId, BasePath, CodeRef, ExecState, Face, GeoMeta, KclValue, Path, Plane, Point2d, Point3d, + Sketch, SketchSurface, Solid, StartSketchOnFace, StartSketchOnPlane, TagEngineInfo, TagIdentifier, }, parsing::ast::types::TagNode, std::{ diff --git a/rust/kcl-lib/src/std/sweep.rs b/rust/kcl-lib/src/std/sweep.rs index 966fd8f66..c9d1cf339 100644 --- a/rust/kcl-lib/src/std/sweep.rs +++ b/rust/kcl-lib/src/std/sweep.rs @@ -9,8 +9,7 @@ use serde::{Deserialize, Serialize}; use crate::{ errors::KclError, - execution::{kcl_value::RuntimeType, ExecState, Helix, KclValue, Sketch, Solid}, - parsing::ast::types::TagNode, + execution::{types::RuntimeType, ExecState, Helix, KclValue, Sketch, Solid}, std::{extrude::do_post_extrude, fillet::default_tolerance, Args}, }; diff --git a/rust/kcl-lib/src/std/transform.rs b/rust/kcl-lib/src/std/transform.rs index 2a73c78f9..3d9f69774 100644 --- a/rust/kcl-lib/src/std/transform.rs +++ b/rust/kcl-lib/src/std/transform.rs @@ -13,7 +13,7 @@ use kittycad_modeling_cmds as kcmc; use crate::{ errors::{KclError, KclErrorDetails}, - execution::{kcl_value::RuntimeType, ExecState, KclValue, SolidOrSketchOrImportedGeometry}, + execution::{types::RuntimeType, ExecState, KclValue, SolidOrSketchOrImportedGeometry}, std::Args, }; diff --git a/rust/kcl-lib/src/std/units.rs b/rust/kcl-lib/src/std/units.rs index 03a830a6f..c096a6eb2 100644 --- a/rust/kcl-lib/src/std/units.rs +++ b/rust/kcl-lib/src/std/units.rs @@ -5,7 +5,7 @@ use kcl_derive_docs::stdlib; use crate::{ errors::KclError, - execution::{ExecState, KclValue, UnitLen}, + execution::{types::UnitLen, ExecState, KclValue}, std::Args, };