Files
modeling-app/rust/kcl-lib/src/execution/kcl_value.rs

754 lines
25 KiB
Rust
Raw Normal View History

use std::collections::HashMap;
use anyhow::Result;
use schemars::JsonSchema;
use serde::Serialize;
use crate::{
errors::KclErrorDetails,
Enhance helixes (#4973) * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> * allow a helix to go into a sweep Signed-off-by: Jess Frazelle <github@jessfraz.com> * fix clippy Signed-off-by: Jess Frazelle <github@jessfraz.com> * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> * udpates Signed-off-by: Jess Frazelle <github@jessfraz.com> * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> * snapshots Signed-off-by: Jess Frazelle <github@jessfraz.com> * docs Signed-off-by: Jess Frazelle <github@jessfraz.com> * docs Signed-off-by: Jess Frazelle <github@jessfraz.com> * fix Signed-off-by: Jess Frazelle <github@jessfraz.com> * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> * A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores) * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> * docs Signed-off-by: Jess Frazelle <github@jessfraz.com> * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> * A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores) * em,pty * A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores) * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> --------- Signed-off-by: Jess Frazelle <github@jessfraz.com> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-01-07 19:10:53 -08:00
execution::{
annotations::{SETTINGS, SETTINGS_UNIT_LENGTH},
parallelized modules from kcl (#6206) * wip * sketch a bit more; going to pull this out of tests next * wip * lock start things * this was a bad idea * Revert "this was a bad idea" This reverts commit a2092e7ed664f2be17eb553e82d39a16983f52ed. * prepare prelude before spawning * error * poop * yike * :( * ok * Reapply "this was a bad idea" This reverts commit fafdf410935abbddd41f312474322a79222a523f. * chip away more * man this is bad * fix rebase add feature flag Signed-off-by: Jess Frazelle <github@jessfraz.com> * get rid of execution kind Signed-off-by: Jess Frazelle <github@jessfraz.com> * clippy Signed-off-by: Jess Frazelle <github@jessfraz.com> * logs Signed-off-by: Jess Frazelle <github@jessfraz.com> * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> * no extra executes Signed-off-by: Jess Frazelle <github@jessfraz.com> * race w batch Signed-off-by: Jess Frazelle <github@jessfraz.com> * cluppy Signed-off-by: Jess Frazelle <github@jessfraz.com> * no printlns Signed-off-by: Jess Frazelle <github@jessfraz.com> * no printlns Signed-off-by: Jess Frazelle <github@jessfraz.com> * fix source ranges Signed-off-by: Jess Frazelle <github@jessfraz.com> * batch shit Signed-off-by: Jess Frazelle <github@jessfraz.com> * fixes Signed-off-by: Jess Frazelle <github@jessfraz.com> * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> * fix Signed-off-by: Jess Frazelle <github@jessfraz.com> * fix some bugs Signed-off-by: Jess Frazelle <github@jessfraz.com> * fix error Signed-off-by: Jess Frazelle <github@jessfraz.com> * cut 1 * preserve mem * re-ad deep_clone the helper we were calling was pushing a new call, which was hanging out. we can skip the middleman since we already have something properly prepared, just without a stdlib in some cases. * skip non-kcl * clean up source range bug * error message changed the uuids also changed because the error is hit before execute even starts. * typo * rensnapshot a few * order things * MAYBE REVERT LATER: attempt at an ordering * snapsnap * Revert "snapsnap" This reverts commit 7350b32c7d0c90c1dd0352aa4a5686370ea422fd. * Revert "MAYBE REVERT LATER:" This reverts commit ab49f3e85ff5c9dd2c625eb11573f82877239104. * ugh * poop * poop2 * lint * tranche 1 * more * more snaps * snap * more * update * MAYBE REVERT THIS * cache multi-file Signed-off-by: Jess Frazelle <github@jessfraz.com> * addd tests Signed-off-by: Jess Frazelle <github@jessfraz.com> * set to false Signed-off-by: Jess Frazelle <github@jessfraz.com> * add test outputs Signed-off-by: Jess Frazelle <github@jessfraz.com> * clippy Signed-off-by: Jess Frazelle <github@jessfraz.com> * kcl-py-bindings uses carwheel Signed-off-by: Jess Frazelle <github@jessfraz.com> * update snapshots Signed-off-by: Jess Frazelle <github@jessfraz.com> * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> --------- Signed-off-by: Jess Frazelle <github@jessfraz.com> Co-authored-by: Paul R. Tagliamonte <paul@zoo.dev> Co-authored-by: Paul Tagliamonte <paultag@gmail.com>
2025-04-16 11:52:14 -07:00
types::{NumericType, PrimitiveType, RuntimeType, UnitLen},
Add clone (#5462) * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> updates Signed-off-by: Jess Frazelle <github@jessfraz.com> updates Signed-off-by: Jess Frazelle <github@jessfraz.com> updates Signed-off-by: Jess Frazelle <github@jessfraz.com> update the extrude idds Signed-off-by: Jess Frazelle <github@jessfraz.com> updates Signed-off-by: Jess Frazelle <github@jessfraz.com> fix sample Signed-off-by: Jess Frazelle <github@jessfraz.com> better docs Signed-off-by: Jess Frazelle <github@jessfraz.com> fix the start and end tag Signed-off-by: Jess Frazelle <github@jessfraz.com> better docs Signed-off-by: Jess Frazelle <github@jessfraz.com> updates Signed-off-by: Jess Frazelle <github@jessfraz.com> new tests Signed-off-by: Jess Frazelle <github@jessfraz.com> codespell Signed-off-by: Jess Frazelle <github@jessfraz.com> updates Signed-off-by: Jess Frazelle <github@jessfraz.com> updates Signed-off-by: Jess Frazelle <github@jessfraz.com> updates Signed-off-by: Jess Frazelle <github@jessfraz.com> * fix examples Signed-off-by: Jess Frazelle <github@jessfraz.com> * fix some stuff Signed-off-by: Jess Frazelle <github@jessfraz.com> * fixes Signed-off-by: Jess Frazelle <github@jessfraz.com> * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> * add another test for fillet Signed-off-by: Jess Frazelle <github@jessfraz.com> * Update rust/kcl-lib/src/std/clone.rs Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com> * fixes Signed-off-by: Jess Frazelle <github@jessfraz.com> * add sweep test Signed-off-by: Jess Frazelle <github@jessfraz.com> * revolve test; Signed-off-by: Jess Frazelle <github@jessfraz.com> * Update rust/kcl-lib/src/std/clone.rs Co-authored-by: Jonathan Tran <jonnytran@gmail.com> * add another test for fillet Signed-off-by: Jess Frazelle <github@jessfraz.com> * allow cloning an imported geometry; Signed-off-by: Jess Frazelle <github@jessfraz.com> * allow for imported geometry Signed-off-by: Jess Frazelle <github@jessfraz.com> * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> * update docs Signed-off-by: Jess Frazelle <github@jessfraz.com> --------- Signed-off-by: Jess Frazelle <github@jessfraz.com> Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com> Co-authored-by: Jonathan Tran <jonnytran@gmail.com>
2025-04-23 21:26:09 -07:00
EnvironmentRef, ExecState, Face, Geometry, GeometryWithImportedGeometry, Helix, ImportedGeometry, MetaSettings,
Metadata, Plane, Sketch, Solid, TagIdentifier,
Enhance helixes (#4973) * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> * allow a helix to go into a sweep Signed-off-by: Jess Frazelle <github@jessfraz.com> * fix clippy Signed-off-by: Jess Frazelle <github@jessfraz.com> * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> * udpates Signed-off-by: Jess Frazelle <github@jessfraz.com> * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> * snapshots Signed-off-by: Jess Frazelle <github@jessfraz.com> * docs Signed-off-by: Jess Frazelle <github@jessfraz.com> * docs Signed-off-by: Jess Frazelle <github@jessfraz.com> * fix Signed-off-by: Jess Frazelle <github@jessfraz.com> * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> * A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores) * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> * docs Signed-off-by: Jess Frazelle <github@jessfraz.com> * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> * A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores) * em,pty * A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores) * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> --------- Signed-off-by: Jess Frazelle <github@jessfraz.com> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-01-07 19:10:53 -08:00
},
parsing::ast::types::{
DefaultParamVal, FunctionExpression, KclNone, Literal, LiteralValue, Node, TagDeclarator, TagNode,
},
std::{args::TyF64, StdFnProps},
CompilationError, KclError, ModuleId, SourceRange,
};
pub type KclObjectFields = HashMap<String, KclValue>;
/// Any KCL value.
#[derive(Debug, Clone, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[ts(export)]
#[serde(tag = "type")]
pub enum KclValue {
Uuid {
value: ::uuid::Uuid,
#[serde(skip)]
meta: Vec<Metadata>,
},
Bool {
value: bool,
#[serde(skip)]
meta: Vec<Metadata>,
},
Number {
value: f64,
ty: NumericType,
#[serde(skip)]
meta: Vec<Metadata>,
},
String {
value: String,
#[serde(skip)]
meta: Vec<Metadata>,
},
Tuple {
value: Vec<KclValue>,
#[serde(skip)]
meta: Vec<Metadata>,
},
// An array where all values have a shared type (not necessarily the same principal type).
HomArray {
value: Vec<KclValue>,
// The type of values, not the array type.
#[serde(skip)]
ty: RuntimeType,
},
Object {
value: KclObjectFields,
#[serde(skip)]
meta: Vec<Metadata>,
},
TagIdentifier(Box<TagIdentifier>),
TagDeclarator(crate::parsing::ast::types::BoxNode<TagDeclarator>),
Plane {
value: Box<Plane>,
},
Face {
value: Box<Face>,
},
Sketch {
value: Box<Sketch>,
},
Solid {
value: Box<Solid>,
},
Helix {
value: Box<Helix>,
},
ImportedGeometry(ImportedGeometry),
Function {
#[serde(serialize_with = "function_value_stub")]
#[ts(type = "null")]
value: FunctionSource,
#[serde(skip)]
meta: Vec<Metadata>,
},
Module {
value: ModuleId,
#[serde(skip)]
meta: Vec<Metadata>,
},
#[ts(skip)]
Type {
#[serde(skip)]
value: TypeDef,
#[serde(skip)]
meta: Vec<Metadata>,
},
KclNone {
value: KclNone,
#[serde(skip)]
meta: Vec<Metadata>,
},
}
fn function_value_stub<S>(_value: &FunctionSource, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serializer.serialize_unit()
}
#[derive(Debug, Clone, PartialEq, Default)]
pub enum FunctionSource {
#[default]
None,
Std {
func: crate::std::StdFn,
ast: crate::parsing::ast::types::BoxNode<FunctionExpression>,
props: StdFnProps,
},
User {
ast: crate::parsing::ast::types::BoxNode<FunctionExpression>,
settings: MetaSettings,
memory: EnvironmentRef,
},
}
impl JsonSchema for FunctionSource {
fn schema_name() -> String {
"FunctionSource".to_owned()
}
fn json_schema(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
// TODO: Actually generate a reasonable schema.
gen.subschema_for::<()>()
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum TypeDef {
RustRepr(PrimitiveType, StdFnProps),
Alias(RuntimeType),
}
impl From<Vec<Sketch>> for KclValue {
fn from(mut eg: Vec<Sketch>) -> Self {
if eg.len() == 1 {
KclValue::Sketch {
value: Box::new(eg.pop().unwrap()),
}
} else {
KclValue::HomArray {
value: eg
.into_iter()
.map(|s| KclValue::Sketch { value: Box::new(s) })
.collect(),
ty: RuntimeType::Primitive(PrimitiveType::Sketch),
}
}
}
}
impl From<Vec<Solid>> for KclValue {
fn from(mut eg: Vec<Solid>) -> Self {
if eg.len() == 1 {
KclValue::Solid {
value: Box::new(eg.pop().unwrap()),
}
} else {
KclValue::HomArray {
value: eg.into_iter().map(|s| KclValue::Solid { value: Box::new(s) }).collect(),
ty: RuntimeType::Primitive(PrimitiveType::Solid),
}
}
}
}
impl From<KclValue> for Vec<SourceRange> {
fn from(item: KclValue) -> Self {
match item {
KclValue::TagDeclarator(t) => vec![SourceRange::new(t.start, t.end, t.module_id)],
KclValue::TagIdentifier(t) => to_vec_sr(&t.meta),
KclValue::Solid { value } => to_vec_sr(&value.meta),
KclValue::Sketch { value } => to_vec_sr(&value.meta),
KclValue::Helix { value } => to_vec_sr(&value.meta),
KclValue::ImportedGeometry(i) => to_vec_sr(&i.meta),
KclValue::Function { meta, .. } => to_vec_sr(&meta),
KclValue::Plane { value } => to_vec_sr(&value.meta),
KclValue::Face { value } => to_vec_sr(&value.meta),
KclValue::Bool { meta, .. } => to_vec_sr(&meta),
KclValue::Number { meta, .. } => to_vec_sr(&meta),
KclValue::String { meta, .. } => to_vec_sr(&meta),
KclValue::Tuple { meta, .. } => to_vec_sr(&meta),
KclValue::HomArray { value, .. } => value.iter().flat_map(Into::<Vec<SourceRange>>::into).collect(),
KclValue::Object { meta, .. } => to_vec_sr(&meta),
KclValue::Module { meta, .. } => to_vec_sr(&meta),
KclValue::Uuid { meta, .. } => to_vec_sr(&meta),
KclValue::Type { meta, .. } => to_vec_sr(&meta),
KclValue::KclNone { meta, .. } => to_vec_sr(&meta),
}
}
}
fn to_vec_sr(meta: &[Metadata]) -> Vec<SourceRange> {
meta.iter().map(|m| m.source_range).collect()
}
impl From<&KclValue> for Vec<SourceRange> {
fn from(item: &KclValue) -> Self {
match item {
KclValue::TagDeclarator(t) => vec![SourceRange::new(t.start, t.end, t.module_id)],
KclValue::TagIdentifier(t) => to_vec_sr(&t.meta),
KclValue::Solid { value } => to_vec_sr(&value.meta),
KclValue::Sketch { value } => to_vec_sr(&value.meta),
KclValue::Helix { value } => to_vec_sr(&value.meta),
KclValue::ImportedGeometry(i) => to_vec_sr(&i.meta),
KclValue::Function { meta, .. } => to_vec_sr(meta),
KclValue::Plane { value } => to_vec_sr(&value.meta),
KclValue::Face { value } => to_vec_sr(&value.meta),
KclValue::Bool { meta, .. } => to_vec_sr(meta),
KclValue::Number { meta, .. } => to_vec_sr(meta),
KclValue::String { meta, .. } => to_vec_sr(meta),
KclValue::Uuid { meta, .. } => to_vec_sr(meta),
KclValue::Tuple { meta, .. } => to_vec_sr(meta),
KclValue::HomArray { value, .. } => value.iter().flat_map(Into::<Vec<SourceRange>>::into).collect(),
KclValue::Object { meta, .. } => to_vec_sr(meta),
KclValue::Module { meta, .. } => to_vec_sr(meta),
KclValue::KclNone { meta, .. } => to_vec_sr(meta),
KclValue::Type { meta, .. } => to_vec_sr(meta),
}
}
}
impl From<&KclValue> for SourceRange {
fn from(item: &KclValue) -> Self {
let v: Vec<_> = item.into();
v.into_iter().next().unwrap_or_default()
}
}
impl KclValue {
pub(crate) fn metadata(&self) -> Vec<Metadata> {
match self {
KclValue::Uuid { value: _, meta } => meta.clone(),
KclValue::Bool { value: _, meta } => meta.clone(),
KclValue::Number { meta, .. } => meta.clone(),
KclValue::String { value: _, meta } => meta.clone(),
KclValue::Tuple { value: _, meta } => meta.clone(),
KclValue::HomArray { value, .. } => value.iter().flat_map(|v| v.metadata()).collect(),
KclValue::Object { value: _, meta } => meta.clone(),
KclValue::TagIdentifier(x) => x.meta.clone(),
KclValue::TagDeclarator(x) => vec![x.metadata()],
KclValue::Plane { value } => value.meta.clone(),
KclValue::Face { value } => value.meta.clone(),
KclValue::Sketch { value } => value.meta.clone(),
KclValue::Solid { value } => value.meta.clone(),
KclValue::Helix { value } => value.meta.clone(),
KclValue::ImportedGeometry(x) => x.meta.clone(),
KclValue::Function { meta, .. } => meta.clone(),
KclValue::Module { meta, .. } => meta.clone(),
KclValue::KclNone { meta, .. } => meta.clone(),
KclValue::Type { meta, .. } => meta.clone(),
}
}
#[allow(unused)]
pub(crate) fn none() -> Self {
Self::KclNone {
value: Default::default(),
meta: Default::default(),
}
}
/// Returns true if we should generate an [`crate::execution::Operation`] to
/// display in the Feature Tree for variable declarations initialized with
/// this value.
pub(crate) fn show_variable_in_feature_tree(&self) -> bool {
match self {
KclValue::Uuid { .. } => false,
KclValue::Bool { .. } | KclValue::Number { .. } | KclValue::String { .. } => true,
KclValue::Tuple { .. }
| KclValue::HomArray { .. }
| KclValue::Object { .. }
| KclValue::TagIdentifier(_)
| KclValue::TagDeclarator(_)
| KclValue::Plane { .. }
| KclValue::Face { .. }
| KclValue::Sketch { .. }
| KclValue::Solid { .. }
| KclValue::Helix { .. }
| KclValue::ImportedGeometry(_)
| KclValue::Function { .. }
| KclValue::Module { .. }
| KclValue::Type { .. }
| KclValue::KclNone { .. } => false,
}
}
/// Human readable type name used in error messages. Should not be relied
/// on for program logic.
pub(crate) fn human_friendly_type(&self) -> String {
match self {
KclValue::Uuid { .. } => "a unique ID (uuid)".to_owned(),
KclValue::TagDeclarator(_) => "a tag declarator".to_owned(),
KclValue::TagIdentifier(_) => "a tag identifier".to_owned(),
KclValue::Solid { .. } => "a solid".to_owned(),
KclValue::Sketch { .. } => "a sketch".to_owned(),
KclValue::Helix { .. } => "a helix".to_owned(),
KclValue::ImportedGeometry(_) => "an imported geometry".to_owned(),
KclValue::Function { .. } => "a function".to_owned(),
KclValue::Plane { .. } => "a plane".to_owned(),
KclValue::Face { .. } => "a face".to_owned(),
KclValue::Bool { .. } => "a boolean (`true` or `false`)".to_owned(),
KclValue::Number {
ty: NumericType::Unknown,
..
} => "a number with unknown units".to_owned(),
KclValue::Number {
ty: NumericType::Known(units),
..
} => format!("a number ({units})"),
KclValue::Number { .. } => "a number".to_owned(),
KclValue::String { .. } => "a string".to_owned(),
KclValue::Object { .. } => "an object".to_owned(),
KclValue::Module { .. } => "a module".to_owned(),
KclValue::Type { .. } => "a type".to_owned(),
KclValue::KclNone { .. } => "none".to_owned(),
KclValue::Tuple { value, .. } | KclValue::HomArray { value, .. } => {
if value.is_empty() {
"an empty array".to_owned()
} else {
// A max of 3 is good because it's common to use 3D points.
const MAX: usize = 3;
let len = value.len();
let element_tys = value
.iter()
.take(MAX)
.map(|elem| elem.principal_type_string())
.collect::<Vec<_>>()
.join(", ");
let mut result = format!("an array of {element_tys}");
if len > MAX {
result.push_str(&format!(", ... with {len} values"));
}
if len == 1 {
result.push_str(" with 1 value");
}
result
}
}
}
}
pub(crate) fn from_literal(literal: Node<Literal>, exec_state: &mut ExecState) -> Self {
let meta = vec![literal.metadata()];
match literal.inner.value {
LiteralValue::Number { value, suffix } => {
let ty = NumericType::from_parsed(suffix, &exec_state.mod_local.settings);
if let NumericType::Default { len, .. } = &ty {
if !exec_state.mod_local.explicit_length_units && *len != UnitLen::Mm {
exec_state.warn(
CompilationError::err(
literal.as_source_range(),
"Project-wide units are deprecated. Prefer to use per-file default units.",
)
.with_suggestion(
"Fix by adding per-file settings",
format!("@{SETTINGS}({SETTINGS_UNIT_LENGTH} = {len})\n"),
// Insert at the start of the file.
Some(SourceRange::new(0, 0, literal.module_id)),
crate::errors::Tag::Deprecated,
),
);
}
}
KclValue::Number { value, meta, ty }
}
LiteralValue::String(value) => KclValue::String { value, meta },
LiteralValue::Bool(value) => KclValue::Bool { value, meta },
}
}
pub(crate) fn from_default_param(param: DefaultParamVal, exec_state: &mut ExecState) -> Self {
match param {
DefaultParamVal::Literal(lit) => Self::from_literal(lit, exec_state),
DefaultParamVal::KclNone(value) => KclValue::KclNone {
value,
meta: Default::default(),
},
}
}
pub(crate) fn map_env_ref(&self, old_env: usize, new_env: usize) -> Self {
let mut result = self.clone();
if let KclValue::Function {
value: FunctionSource::User { ref mut memory, .. },
..
} = result
{
memory.replace_env(old_env, new_env);
}
result
}
pub const fn from_number_with_type(f: f64, ty: NumericType, meta: Vec<Metadata>) -> Self {
Self::Number { value: f, meta, ty }
}
/// Put the point into a KCL value.
pub fn from_point2d(p: [f64; 2], ty: NumericType, meta: Vec<Metadata>) -> Self {
Self::Tuple {
value: vec![
Self::Number {
value: p[0],
meta: meta.clone(),
ty: ty.clone(),
},
Self::Number {
value: p[1],
meta: meta.clone(),
ty,
},
],
meta,
}
}
pub(crate) fn as_usize(&self) -> Option<usize> {
match self {
KclValue::Number { value, .. } => crate::try_f64_to_usize(*value),
_ => None,
}
}
pub fn as_int(&self) -> Option<i64> {
match self {
KclValue::Number { value, .. } => crate::try_f64_to_i64(*value),
_ => None,
}
}
pub fn as_int_with_ty(&self) -> Option<(i64, NumericType)> {
match self {
KclValue::Number { value, ty, .. } => crate::try_f64_to_i64(*value).map(|i| (i, ty.clone())),
_ => None,
}
}
pub fn as_object(&self) -> Option<&KclObjectFields> {
match self {
KclValue::Object { value, .. } => Some(value),
_ => None,
}
}
pub fn into_object(self) -> Option<KclObjectFields> {
match self {
KclValue::Object { value, .. } => Some(value),
_ => None,
}
}
pub fn as_str(&self) -> Option<&str> {
match self {
KclValue::String { value, .. } => Some(value),
_ => None,
}
}
pub fn into_array(self) -> Vec<KclValue> {
match self {
KclValue::Tuple { value, .. } | KclValue::HomArray { value, .. } => value,
_ => vec![self],
}
}
pub fn as_point2d(&self) -> Option<[TyF64; 2]> {
let value = match self {
KclValue::Tuple { value, .. } | KclValue::HomArray { value, .. } => value,
_ => return None,
};
if value.len() != 2 {
return None;
}
let x = value[0].as_ty_f64()?;
let y = value[1].as_ty_f64()?;
Some([x, y])
}
pub fn as_point3d(&self) -> Option<[TyF64; 3]> {
let value = match self {
KclValue::Tuple { value, .. } | KclValue::HomArray { value, .. } => value,
_ => return None,
};
if value.len() != 3 {
return None;
}
let x = value[0].as_ty_f64()?;
let y = value[1].as_ty_f64()?;
let z = value[2].as_ty_f64()?;
Some([x, y, z])
}
pub fn as_uuid(&self) -> Option<uuid::Uuid> {
match self {
KclValue::Uuid { value, .. } => Some(*value),
_ => None,
}
}
pub fn as_plane(&self) -> Option<&Plane> {
match self {
KclValue::Plane { value, .. } => Some(value),
_ => None,
}
}
pub fn as_solid(&self) -> Option<&Solid> {
match self {
KclValue::Solid { value, .. } => Some(value),
_ => None,
}
}
pub fn as_sketch(&self) -> Option<&Sketch> {
match self {
KclValue::Sketch { value, .. } => Some(value),
_ => None,
}
}
pub fn as_mut_sketch(&mut self) -> Option<&mut Sketch> {
match self {
KclValue::Sketch { value } => Some(value),
_ => None,
}
}
pub fn as_mut_tag(&mut self) -> Option<&mut TagIdentifier> {
match self {
KclValue::TagIdentifier(value) => Some(value),
_ => None,
}
}
#[cfg(test)]
pub fn as_f64(&self) -> Option<f64> {
match self {
KclValue::Number { value, .. } => Some(*value),
_ => None,
}
}
pub fn as_ty_f64(&self) -> Option<TyF64> {
match self {
KclValue::Number { value, ty, .. } => Some(TyF64::new(*value, ty.clone())),
_ => None,
}
}
pub fn as_bool(&self) -> Option<bool> {
match self {
KclValue::Bool { value, .. } => Some(*value),
_ => None,
}
}
/// If this value is of type function, return it.
pub fn as_function(&self) -> Option<&FunctionSource> {
match self {
KclValue::Function { value, .. } => Some(value),
_ => None,
}
}
/// Get a tag identifier from a memory item.
pub fn get_tag_identifier(&self) -> Result<TagIdentifier, KclError> {
match self {
KclValue::TagIdentifier(t) => Ok(*t.clone()),
_ => Err(KclError::new_semantic(KclErrorDetails::new(
format!("Not a tag identifier: {:?}", self),
self.clone().into(),
))),
}
}
/// Get a tag declarator from a memory item.
pub fn get_tag_declarator(&self) -> Result<TagNode, KclError> {
match self {
KclValue::TagDeclarator(t) => Ok((**t).clone()),
_ => Err(KclError::new_semantic(KclErrorDetails::new(
format!("Not a tag declarator: {:?}", self),
self.clone().into(),
))),
}
}
/// If this KCL value is a bool, retrieve it.
pub fn get_bool(&self) -> Result<bool, KclError> {
self.as_bool().ok_or_else(|| {
KclError::new_type(KclErrorDetails::new(
format!("Expected bool, found {}", self.human_friendly_type()),
self.into(),
))
})
}
pub fn is_unknown_number(&self) -> bool {
match self {
KclValue::Number { ty, .. } => !ty.is_fully_specified(),
_ => false,
}
}
pub fn value_str(&self) -> Option<String> {
match self {
KclValue::Bool { value, .. } => Some(format!("{value}")),
KclValue::Number { value, .. } => Some(format!("{value}")),
KclValue::String { value, .. } => Some(format!("'{value}'")),
KclValue::Uuid { value, .. } => Some(format!("{value}")),
KclValue::TagDeclarator(tag) => Some(format!("${}", tag.name)),
KclValue::TagIdentifier(tag) => Some(format!("${}", tag.value)),
// TODO better Array and Object stringification
KclValue::Tuple { .. } => Some("[...]".to_owned()),
KclValue::HomArray { .. } => Some("[...]".to_owned()),
KclValue::Object { .. } => Some("{ ... }".to_owned()),
KclValue::Module { .. }
| KclValue::Solid { .. }
| KclValue::Sketch { .. }
| KclValue::Helix { .. }
| KclValue::ImportedGeometry(_)
| KclValue::Function { .. }
| KclValue::Plane { .. }
| KclValue::Face { .. }
| KclValue::KclNone { .. }
| KclValue::Type { .. } => None,
}
}
}
Add clone (#5462) * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> updates Signed-off-by: Jess Frazelle <github@jessfraz.com> updates Signed-off-by: Jess Frazelle <github@jessfraz.com> updates Signed-off-by: Jess Frazelle <github@jessfraz.com> update the extrude idds Signed-off-by: Jess Frazelle <github@jessfraz.com> updates Signed-off-by: Jess Frazelle <github@jessfraz.com> fix sample Signed-off-by: Jess Frazelle <github@jessfraz.com> better docs Signed-off-by: Jess Frazelle <github@jessfraz.com> fix the start and end tag Signed-off-by: Jess Frazelle <github@jessfraz.com> better docs Signed-off-by: Jess Frazelle <github@jessfraz.com> updates Signed-off-by: Jess Frazelle <github@jessfraz.com> new tests Signed-off-by: Jess Frazelle <github@jessfraz.com> codespell Signed-off-by: Jess Frazelle <github@jessfraz.com> updates Signed-off-by: Jess Frazelle <github@jessfraz.com> updates Signed-off-by: Jess Frazelle <github@jessfraz.com> updates Signed-off-by: Jess Frazelle <github@jessfraz.com> * fix examples Signed-off-by: Jess Frazelle <github@jessfraz.com> * fix some stuff Signed-off-by: Jess Frazelle <github@jessfraz.com> * fixes Signed-off-by: Jess Frazelle <github@jessfraz.com> * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> * add another test for fillet Signed-off-by: Jess Frazelle <github@jessfraz.com> * Update rust/kcl-lib/src/std/clone.rs Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com> * fixes Signed-off-by: Jess Frazelle <github@jessfraz.com> * add sweep test Signed-off-by: Jess Frazelle <github@jessfraz.com> * revolve test; Signed-off-by: Jess Frazelle <github@jessfraz.com> * Update rust/kcl-lib/src/std/clone.rs Co-authored-by: Jonathan Tran <jonnytran@gmail.com> * add another test for fillet Signed-off-by: Jess Frazelle <github@jessfraz.com> * allow cloning an imported geometry; Signed-off-by: Jess Frazelle <github@jessfraz.com> * allow for imported geometry Signed-off-by: Jess Frazelle <github@jessfraz.com> * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> * update docs Signed-off-by: Jess Frazelle <github@jessfraz.com> --------- Signed-off-by: Jess Frazelle <github@jessfraz.com> Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com> Co-authored-by: Jonathan Tran <jonnytran@gmail.com>
2025-04-23 21:26:09 -07:00
impl From<Geometry> for KclValue {
fn from(value: Geometry) -> Self {
match value {
Geometry::Sketch(x) => Self::Sketch { value: Box::new(x) },
Geometry::Solid(x) => Self::Solid { value: Box::new(x) },
}
}
}
impl From<GeometryWithImportedGeometry> for KclValue {
fn from(value: GeometryWithImportedGeometry) -> Self {
match value {
GeometryWithImportedGeometry::Sketch(x) => Self::Sketch { value: Box::new(x) },
GeometryWithImportedGeometry::Solid(x) => Self::Solid { value: Box::new(x) },
GeometryWithImportedGeometry::ImportedGeometry(x) => Self::ImportedGeometry(*x),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::exec::UnitType;
#[test]
fn test_human_friendly_type() {
let len = KclValue::Number {
value: 1.0,
ty: NumericType::Known(UnitType::Length(UnitLen::Unknown)),
meta: vec![],
};
assert_eq!(len.human_friendly_type(), "a number (Length)".to_string());
let unknown = KclValue::Number {
value: 1.0,
ty: NumericType::Unknown,
meta: vec![],
};
assert_eq!(unknown.human_friendly_type(), "a number with unknown units".to_string());
let mm = KclValue::Number {
value: 1.0,
ty: NumericType::Known(UnitType::Length(UnitLen::Mm)),
meta: vec![],
};
assert_eq!(mm.human_friendly_type(), "a number (mm)".to_string());
let array1_mm = KclValue::HomArray {
value: vec![mm.clone()],
ty: RuntimeType::any(),
};
assert_eq!(
array1_mm.human_friendly_type(),
"an array of `number(mm)` with 1 value".to_string()
);
let array2_mm = KclValue::HomArray {
value: vec![mm.clone(), mm.clone()],
ty: RuntimeType::any(),
};
assert_eq!(
array2_mm.human_friendly_type(),
"an array of `number(mm)`, `number(mm)`".to_string()
);
let array3_mm = KclValue::HomArray {
value: vec![mm.clone(), mm.clone(), mm.clone()],
ty: RuntimeType::any(),
};
assert_eq!(
array3_mm.human_friendly_type(),
"an array of `number(mm)`, `number(mm)`, `number(mm)`".to_string()
);
let inches = KclValue::Number {
value: 1.0,
ty: NumericType::Known(UnitType::Length(UnitLen::Inches)),
meta: vec![],
};
let array4 = KclValue::HomArray {
value: vec![mm.clone(), mm.clone(), inches.clone(), mm.clone()],
ty: RuntimeType::any(),
};
assert_eq!(
array4.human_friendly_type(),
"an array of `number(mm)`, `number(mm)`, `number(in)`, ... with 4 values".to_string()
);
let empty_array = KclValue::HomArray {
value: vec![],
ty: RuntimeType::any(),
};
assert_eq!(empty_array.human_friendly_type(), "an empty array".to_string());
let array_nested = KclValue::HomArray {
value: vec![array2_mm.clone()],
ty: RuntimeType::any(),
};
assert_eq!(
array_nested.human_friendly_type(),
"an array of `[any; 2]` with 1 value".to_string()
);
}
}