2025-03-21 10:56:55 +13:00
|
|
|
use std::collections::HashMap;
|
2024-11-21 10:47:32 -06:00
|
|
|
|
|
|
|
use anyhow::Result;
|
|
|
|
use schemars::JsonSchema;
|
2025-03-21 10:56:55 +13:00
|
|
|
use serde::Serialize;
|
2024-11-21 10:47:32 -06:00
|
|
|
|
2025-04-29 19:11:02 -07:00
|
|
|
use super::types::UnitType;
|
2024-11-21 10:47:32 -06:00
|
|
|
use crate::{
|
|
|
|
errors::KclErrorDetails,
|
2025-01-07 19:10:53 -08:00
|
|
|
execution::{
|
2025-03-26 01:59:43 -04:00
|
|
|
annotations::{SETTINGS, SETTINGS_UNIT_LENGTH},
|
2025-04-16 11:52:14 -07:00
|
|
|
types::{NumericType, PrimitiveType, RuntimeType, UnitLen},
|
2025-04-23 21:26:09 -07:00
|
|
|
EnvironmentRef, ExecState, Face, Geometry, GeometryWithImportedGeometry, Helix, ImportedGeometry, MetaSettings,
|
|
|
|
Metadata, Plane, Sketch, Solid, TagIdentifier,
|
2025-01-07 19:10:53 -08:00
|
|
|
},
|
2025-03-21 10:56:55 +13:00
|
|
|
parsing::ast::types::{
|
|
|
|
DefaultParamVal, FunctionExpression, KclNone, Literal, LiteralValue, Node, TagDeclarator, TagNode,
|
2025-03-17 17:57:26 +13:00
|
|
|
},
|
2025-04-07 16:13:15 +12:00
|
|
|
std::{args::TyF64, StdFnProps},
|
2025-03-26 01:59:43 -04:00
|
|
|
CompilationError, KclError, ModuleId, SourceRange,
|
2024-11-21 10:47:32 -06:00
|
|
|
};
|
|
|
|
|
2024-11-26 09:51:43 -06:00
|
|
|
pub type KclObjectFields = HashMap<String, KclValue>;
|
|
|
|
|
2024-11-21 10:47:32 -06:00
|
|
|
/// Any KCL value.
|
2025-03-08 04:04:57 +13:00
|
|
|
#[derive(Debug, Clone, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
|
2024-11-21 10:47:32 -06:00
|
|
|
#[ts(export)]
|
|
|
|
#[serde(tag = "type")]
|
|
|
|
pub enum KclValue {
|
|
|
|
Uuid {
|
|
|
|
value: ::uuid::Uuid,
|
2025-03-13 11:13:33 -07:00
|
|
|
#[serde(skip)]
|
2024-11-21 10:47:32 -06:00
|
|
|
meta: Vec<Metadata>,
|
|
|
|
},
|
|
|
|
Bool {
|
|
|
|
value: bool,
|
2025-03-13 11:13:33 -07:00
|
|
|
#[serde(skip)]
|
2024-11-21 10:47:32 -06:00
|
|
|
meta: Vec<Metadata>,
|
|
|
|
},
|
|
|
|
Number {
|
|
|
|
value: f64,
|
2025-02-14 13:03:23 +13:00
|
|
|
ty: NumericType,
|
2025-03-13 11:13:33 -07:00
|
|
|
#[serde(skip)]
|
2024-11-21 10:47:32 -06:00
|
|
|
meta: Vec<Metadata>,
|
|
|
|
},
|
|
|
|
String {
|
|
|
|
value: String,
|
2025-03-13 11:13:33 -07:00
|
|
|
#[serde(skip)]
|
2024-11-21 10:47:32 -06:00
|
|
|
meta: Vec<Metadata>,
|
|
|
|
},
|
2025-05-11 23:57:31 -04:00
|
|
|
Tuple {
|
2024-11-21 10:47:32 -06:00
|
|
|
value: Vec<KclValue>,
|
2025-03-13 11:13:33 -07:00
|
|
|
#[serde(skip)]
|
2024-11-21 10:47:32 -06:00
|
|
|
meta: Vec<Metadata>,
|
|
|
|
},
|
2025-03-17 17:57:26 +13:00
|
|
|
// 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)]
|
2025-03-21 10:56:55 +13:00
|
|
|
ty: RuntimeType,
|
2025-03-17 17:57:26 +13:00
|
|
|
},
|
2024-11-21 10:47:32 -06:00
|
|
|
Object {
|
2024-11-26 09:51:43 -06:00
|
|
|
value: KclObjectFields,
|
2025-03-13 11:13:33 -07:00
|
|
|
#[serde(skip)]
|
2024-11-21 10:47:32 -06:00
|
|
|
meta: Vec<Metadata>,
|
|
|
|
},
|
|
|
|
TagIdentifier(Box<TagIdentifier>),
|
2024-12-05 17:56:49 +13:00
|
|
|
TagDeclarator(crate::parsing::ast::types::BoxNode<TagDeclarator>),
|
2025-01-22 09:42:09 +13:00
|
|
|
Plane {
|
|
|
|
value: Box<Plane>,
|
|
|
|
},
|
|
|
|
Face {
|
|
|
|
value: Box<Face>,
|
|
|
|
},
|
2024-11-21 10:47:32 -06:00
|
|
|
Sketch {
|
|
|
|
value: Box<Sketch>,
|
|
|
|
},
|
2025-01-22 09:42:09 +13:00
|
|
|
Solid {
|
|
|
|
value: Box<Solid>,
|
|
|
|
},
|
|
|
|
Helix {
|
|
|
|
value: Box<Helix>,
|
|
|
|
},
|
2024-11-21 10:47:32 -06:00
|
|
|
ImportedGeometry(ImportedGeometry),
|
|
|
|
Function {
|
2025-05-05 23:40:18 -04:00
|
|
|
#[serde(serialize_with = "function_value_stub")]
|
|
|
|
#[ts(type = "null")]
|
2025-02-22 20:16:29 +13:00
|
|
|
value: FunctionSource,
|
2025-03-13 11:13:33 -07:00
|
|
|
#[serde(skip)]
|
2024-11-21 10:47:32 -06:00
|
|
|
meta: Vec<Metadata>,
|
|
|
|
},
|
2024-12-17 09:38:32 +13:00
|
|
|
Module {
|
|
|
|
value: ModuleId,
|
2025-03-13 11:13:33 -07:00
|
|
|
#[serde(skip)]
|
2024-12-17 09:38:32 +13:00
|
|
|
meta: Vec<Metadata>,
|
|
|
|
},
|
2025-03-08 03:53:34 +13:00
|
|
|
#[ts(skip)]
|
|
|
|
Type {
|
|
|
|
#[serde(skip)]
|
2025-03-21 10:56:55 +13:00
|
|
|
value: TypeDef,
|
2025-03-13 11:13:33 -07:00
|
|
|
#[serde(skip)]
|
2025-03-08 03:53:34 +13:00
|
|
|
meta: Vec<Metadata>,
|
|
|
|
},
|
2024-11-21 10:47:32 -06:00
|
|
|
KclNone {
|
|
|
|
value: KclNone,
|
2025-03-13 11:13:33 -07:00
|
|
|
#[serde(skip)]
|
2024-11-21 10:47:32 -06:00
|
|
|
meta: Vec<Metadata>,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2025-05-05 23:40:18 -04:00
|
|
|
fn function_value_stub<S>(_value: &FunctionSource, serializer: S) -> Result<S::Ok, S::Error>
|
|
|
|
where
|
|
|
|
S: serde::Serializer,
|
|
|
|
{
|
|
|
|
serializer.serialize_unit()
|
|
|
|
}
|
|
|
|
|
2025-02-22 20:16:29 +13:00
|
|
|
#[derive(Debug, Clone, PartialEq, Default)]
|
|
|
|
pub enum FunctionSource {
|
|
|
|
#[default]
|
|
|
|
None,
|
|
|
|
Std {
|
|
|
|
func: crate::std::StdFn,
|
2025-03-24 21:55:24 +13:00
|
|
|
ast: crate::parsing::ast::types::BoxNode<FunctionExpression>,
|
2025-02-22 20:16:29 +13:00
|
|
|
props: StdFnProps,
|
|
|
|
},
|
|
|
|
User {
|
|
|
|
ast: crate::parsing::ast::types::BoxNode<FunctionExpression>,
|
2025-03-08 04:04:57 +13:00
|
|
|
settings: MetaSettings,
|
2025-02-22 20:16:29 +13:00
|
|
|
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::<()>()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-03-21 10:56:55 +13:00
|
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
|
|
pub enum TypeDef {
|
|
|
|
RustRepr(PrimitiveType, StdFnProps),
|
|
|
|
Alias(RuntimeType),
|
|
|
|
}
|
|
|
|
|
2025-03-17 17:57:26 +13:00
|
|
|
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(),
|
2025-03-21 10:56:55 +13:00
|
|
|
ty: RuntimeType::Primitive(PrimitiveType::Sketch),
|
2025-03-17 17:57:26 +13:00
|
|
|
}
|
2024-11-21 10:47:32 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-03-17 17:57:26 +13:00
|
|
|
impl From<Vec<Solid>> for KclValue {
|
|
|
|
fn from(mut eg: Vec<Solid>) -> Self {
|
2024-11-21 10:47:32 -06:00
|
|
|
if eg.len() == 1 {
|
2025-03-17 17:57:26 +13:00
|
|
|
KclValue::Solid {
|
|
|
|
value: Box::new(eg.pop().unwrap()),
|
|
|
|
}
|
2024-11-21 10:47:32 -06:00
|
|
|
} else {
|
2025-03-17 17:57:26 +13:00
|
|
|
KclValue::HomArray {
|
|
|
|
value: eg.into_iter().map(|s| KclValue::Solid { value: Box::new(s) }).collect(),
|
2025-03-21 10:56:55 +13:00
|
|
|
ty: RuntimeType::Primitive(PrimitiveType::Solid),
|
2025-03-17 17:57:26 +13:00
|
|
|
}
|
2024-11-21 10:47:32 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2025-03-17 17:57:26 +13:00
|
|
|
|
2024-11-21 10:47:32 -06:00
|
|
|
impl From<KclValue> for Vec<SourceRange> {
|
|
|
|
fn from(item: KclValue) -> Self {
|
|
|
|
match item {
|
2024-12-03 16:39:51 +13:00
|
|
|
KclValue::TagDeclarator(t) => vec![SourceRange::new(t.start, t.end, t.module_id)],
|
2024-11-21 10:47:32 -06:00
|
|
|
KclValue::TagIdentifier(t) => to_vec_sr(&t.meta),
|
2025-01-22 09:42:09 +13:00
|
|
|
KclValue::Solid { value } => to_vec_sr(&value.meta),
|
2024-11-21 10:47:32 -06:00
|
|
|
KclValue::Sketch { value } => to_vec_sr(&value.meta),
|
2025-01-22 09:42:09 +13:00
|
|
|
KclValue::Helix { value } => to_vec_sr(&value.meta),
|
2024-11-21 10:47:32 -06:00
|
|
|
KclValue::ImportedGeometry(i) => to_vec_sr(&i.meta),
|
|
|
|
KclValue::Function { meta, .. } => to_vec_sr(&meta),
|
2025-01-22 09:42:09 +13:00
|
|
|
KclValue::Plane { value } => to_vec_sr(&value.meta),
|
|
|
|
KclValue::Face { value } => to_vec_sr(&value.meta),
|
2024-11-21 10:47:32 -06:00
|
|
|
KclValue::Bool { meta, .. } => to_vec_sr(&meta),
|
|
|
|
KclValue::Number { meta, .. } => to_vec_sr(&meta),
|
|
|
|
KclValue::String { meta, .. } => to_vec_sr(&meta),
|
2025-05-11 23:57:31 -04:00
|
|
|
KclValue::Tuple { meta, .. } => to_vec_sr(&meta),
|
2025-03-17 17:57:26 +13:00
|
|
|
KclValue::HomArray { value, .. } => value.iter().flat_map(Into::<Vec<SourceRange>>::into).collect(),
|
2024-11-21 10:47:32 -06:00
|
|
|
KclValue::Object { meta, .. } => to_vec_sr(&meta),
|
2024-12-17 09:38:32 +13:00
|
|
|
KclValue::Module { meta, .. } => to_vec_sr(&meta),
|
2024-11-21 10:47:32 -06:00
|
|
|
KclValue::Uuid { meta, .. } => to_vec_sr(&meta),
|
2025-03-08 03:53:34 +13:00
|
|
|
KclValue::Type { meta, .. } => to_vec_sr(&meta),
|
2024-11-21 10:47:32 -06:00
|
|
|
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 {
|
2024-12-03 16:39:51 +13:00
|
|
|
KclValue::TagDeclarator(t) => vec![SourceRange::new(t.start, t.end, t.module_id)],
|
2024-11-21 10:47:32 -06:00
|
|
|
KclValue::TagIdentifier(t) => to_vec_sr(&t.meta),
|
2025-01-22 09:42:09 +13:00
|
|
|
KclValue::Solid { value } => to_vec_sr(&value.meta),
|
2024-11-21 10:47:32 -06:00
|
|
|
KclValue::Sketch { value } => to_vec_sr(&value.meta),
|
2025-01-22 09:42:09 +13:00
|
|
|
KclValue::Helix { value } => to_vec_sr(&value.meta),
|
2024-11-21 10:47:32 -06:00
|
|
|
KclValue::ImportedGeometry(i) => to_vec_sr(&i.meta),
|
|
|
|
KclValue::Function { meta, .. } => to_vec_sr(meta),
|
2025-01-22 09:42:09 +13:00
|
|
|
KclValue::Plane { value } => to_vec_sr(&value.meta),
|
|
|
|
KclValue::Face { value } => to_vec_sr(&value.meta),
|
2024-11-21 10:47:32 -06:00
|
|
|
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),
|
2025-05-11 23:57:31 -04:00
|
|
|
KclValue::Tuple { meta, .. } => to_vec_sr(meta),
|
2025-03-17 17:57:26 +13:00
|
|
|
KclValue::HomArray { value, .. } => value.iter().flat_map(Into::<Vec<SourceRange>>::into).collect(),
|
2024-11-21 10:47:32 -06:00
|
|
|
KclValue::Object { meta, .. } => to_vec_sr(meta),
|
2024-12-17 09:38:32 +13:00
|
|
|
KclValue::Module { meta, .. } => to_vec_sr(meta),
|
2024-11-21 10:47:32 -06:00
|
|
|
KclValue::KclNone { meta, .. } => to_vec_sr(meta),
|
2025-03-08 03:53:34 +13:00
|
|
|
KclValue::Type { meta, .. } => to_vec_sr(meta),
|
2024-11-21 10:47:32 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-03-08 03:53:34 +13:00
|
|
|
impl From<&KclValue> for SourceRange {
|
|
|
|
fn from(item: &KclValue) -> Self {
|
|
|
|
let v: Vec<_> = item.into();
|
|
|
|
v.into_iter().next().unwrap_or_default()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-11-21 10:47:32 -06:00
|
|
|
impl KclValue {
|
2024-11-26 12:27:09 -06:00
|
|
|
pub(crate) fn metadata(&self) -> Vec<Metadata> {
|
|
|
|
match self {
|
|
|
|
KclValue::Uuid { value: _, meta } => meta.clone(),
|
|
|
|
KclValue::Bool { value: _, meta } => meta.clone(),
|
2025-02-14 13:03:23 +13:00
|
|
|
KclValue::Number { meta, .. } => meta.clone(),
|
2024-11-26 12:27:09 -06:00
|
|
|
KclValue::String { value: _, meta } => meta.clone(),
|
2025-05-11 23:57:31 -04:00
|
|
|
KclValue::Tuple { value: _, meta } => meta.clone(),
|
2025-03-17 17:57:26 +13:00
|
|
|
KclValue::HomArray { value, .. } => value.iter().flat_map(|v| v.metadata()).collect(),
|
2024-11-26 12:27:09 -06:00
|
|
|
KclValue::Object { value: _, meta } => meta.clone(),
|
|
|
|
KclValue::TagIdentifier(x) => x.meta.clone(),
|
|
|
|
KclValue::TagDeclarator(x) => vec![x.metadata()],
|
2025-01-22 09:42:09 +13:00
|
|
|
KclValue::Plane { value } => value.meta.clone(),
|
|
|
|
KclValue::Face { value } => value.meta.clone(),
|
2024-11-26 12:27:09 -06:00
|
|
|
KclValue::Sketch { value } => value.meta.clone(),
|
2025-01-22 09:42:09 +13:00
|
|
|
KclValue::Solid { value } => value.meta.clone(),
|
|
|
|
KclValue::Helix { value } => value.meta.clone(),
|
2024-11-26 12:27:09 -06:00
|
|
|
KclValue::ImportedGeometry(x) => x.meta.clone(),
|
|
|
|
KclValue::Function { meta, .. } => meta.clone(),
|
2024-12-17 09:38:32 +13:00
|
|
|
KclValue::Module { meta, .. } => meta.clone(),
|
2024-11-26 12:27:09 -06:00
|
|
|
KclValue::KclNone { meta, .. } => meta.clone(),
|
2025-03-08 03:53:34 +13:00
|
|
|
KclValue::Type { meta, .. } => meta.clone(),
|
2024-11-26 12:27:09 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-12-05 21:04:40 -06:00
|
|
|
#[allow(unused)]
|
|
|
|
pub(crate) fn none() -> Self {
|
|
|
|
Self::KclNone {
|
|
|
|
value: Default::default(),
|
|
|
|
meta: Default::default(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-11-26 12:27:09 -06:00
|
|
|
/// Human readable type name used in error messages. Should not be relied
|
|
|
|
/// on for program logic.
|
|
|
|
pub(crate) fn human_friendly_type(&self) -> &'static str {
|
|
|
|
match self {
|
|
|
|
KclValue::Uuid { .. } => "Unique ID (uuid)",
|
|
|
|
KclValue::TagDeclarator(_) => "TagDeclarator",
|
|
|
|
KclValue::TagIdentifier(_) => "TagIdentifier",
|
2025-01-22 09:42:09 +13:00
|
|
|
KclValue::Solid { .. } => "Solid",
|
2024-11-26 12:27:09 -06:00
|
|
|
KclValue::Sketch { .. } => "Sketch",
|
2025-01-22 09:42:09 +13:00
|
|
|
KclValue::Helix { .. } => "Helix",
|
2024-11-26 12:27:09 -06:00
|
|
|
KclValue::ImportedGeometry(_) => "ImportedGeometry",
|
|
|
|
KclValue::Function { .. } => "Function",
|
2025-01-22 09:42:09 +13:00
|
|
|
KclValue::Plane { .. } => "Plane",
|
|
|
|
KclValue::Face { .. } => "Face",
|
2024-11-26 12:27:09 -06:00
|
|
|
KclValue::Bool { .. } => "boolean (true/false value)",
|
2025-04-29 12:24:18 +12:00
|
|
|
KclValue::Number {
|
|
|
|
ty: NumericType::Unknown,
|
|
|
|
..
|
|
|
|
} => "number(unknown units)",
|
|
|
|
KclValue::Number {
|
|
|
|
ty: NumericType::Known(UnitType::Length(_)),
|
|
|
|
..
|
|
|
|
} => "number(Length)",
|
|
|
|
KclValue::Number {
|
|
|
|
ty: NumericType::Known(UnitType::Angle(_)),
|
|
|
|
..
|
|
|
|
} => "number(Angle)",
|
2024-11-26 12:27:09 -06:00
|
|
|
KclValue::Number { .. } => "number",
|
|
|
|
KclValue::String { .. } => "string (text)",
|
2025-05-11 23:57:31 -04:00
|
|
|
KclValue::Tuple { .. } => "tuple (list)",
|
2025-03-17 17:57:26 +13:00
|
|
|
KclValue::HomArray { .. } => "array (list)",
|
2024-11-26 12:27:09 -06:00
|
|
|
KclValue::Object { .. } => "object",
|
2024-12-17 09:38:32 +13:00
|
|
|
KclValue::Module { .. } => "module",
|
2025-03-08 03:53:34 +13:00
|
|
|
KclValue::Type { .. } => "type",
|
2024-11-26 12:27:09 -06:00
|
|
|
KclValue::KclNone { .. } => "None",
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-03-26 01:59:43 -04:00
|
|
|
pub(crate) fn from_literal(literal: Node<Literal>, exec_state: &mut ExecState) -> Self {
|
2025-02-14 13:03:23 +13:00
|
|
|
let meta = vec![literal.metadata()];
|
|
|
|
match literal.inner.value {
|
2025-03-26 01:59:43 -04:00
|
|
|
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 }
|
|
|
|
}
|
2024-12-05 21:04:40 -06:00
|
|
|
LiteralValue::String(value) => KclValue::String { value, meta },
|
|
|
|
LiteralValue::Bool(value) => KclValue::Bool { value, meta },
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-03-26 01:59:43 -04:00
|
|
|
pub(crate) fn from_default_param(param: DefaultParamVal, exec_state: &mut ExecState) -> Self {
|
2025-02-14 13:03:23 +13:00
|
|
|
match param {
|
2025-03-26 01:59:43 -04:00
|
|
|
DefaultParamVal::Literal(lit) => Self::from_literal(lit, exec_state),
|
2025-02-14 13:03:23 +13:00
|
|
|
DefaultParamVal::KclNone(none) => KclValue::KclNone {
|
|
|
|
value: none,
|
|
|
|
meta: Default::default(),
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-03-17 12:28:51 +13:00
|
|
|
pub(crate) fn map_env_ref(&self, old_env: usize, new_env: usize) -> Self {
|
2025-02-12 10:22:56 +13:00
|
|
|
let mut result = self.clone();
|
2025-02-20 19:33:21 +13:00
|
|
|
if let KclValue::Function {
|
2025-02-22 20:16:29 +13:00
|
|
|
value: FunctionSource::User { ref mut memory, .. },
|
2025-02-20 19:33:21 +13:00
|
|
|
..
|
|
|
|
} = result
|
|
|
|
{
|
2025-03-17 12:28:51 +13:00
|
|
|
memory.replace_env(old_env, new_env);
|
2025-02-12 10:22:56 +13:00
|
|
|
}
|
|
|
|
result
|
|
|
|
}
|
|
|
|
|
2025-02-14 13:03:23 +13:00
|
|
|
pub const fn from_number_with_type(f: f64, ty: NumericType, meta: Vec<Metadata>) -> Self {
|
|
|
|
Self::Number { value: f, meta, ty }
|
2024-11-21 10:47:32 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Put the point into a KCL value.
|
2025-02-14 13:03:23 +13:00
|
|
|
pub fn from_point2d(p: [f64; 2], ty: NumericType, meta: Vec<Metadata>) -> Self {
|
2025-05-11 23:57:31 -04:00
|
|
|
Self::Tuple {
|
2024-11-21 10:47:32 -06:00
|
|
|
value: vec![
|
|
|
|
Self::Number {
|
|
|
|
value: p[0],
|
|
|
|
meta: meta.clone(),
|
2025-02-14 13:03:23 +13:00
|
|
|
ty: ty.clone(),
|
2024-11-21 10:47:32 -06:00
|
|
|
},
|
|
|
|
Self::Number {
|
|
|
|
value: p[1],
|
|
|
|
meta: meta.clone(),
|
2025-02-14 13:03:23 +13:00
|
|
|
ty,
|
2024-11-21 10:47:32 -06:00
|
|
|
},
|
|
|
|
],
|
|
|
|
meta,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn as_usize(&self) -> Option<usize> {
|
|
|
|
match self {
|
2024-11-25 10:50:43 +13:00
|
|
|
KclValue::Number { value, .. } => crate::try_f64_to_usize(*value),
|
2024-11-21 10:47:32 -06:00
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn as_int(&self) -> Option<i64> {
|
2024-11-25 10:50:43 +13:00
|
|
|
match self {
|
|
|
|
KclValue::Number { value, .. } => crate::try_f64_to_i64(*value),
|
|
|
|
_ => None,
|
2024-11-21 10:47:32 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-05-12 01:30:33 -04:00
|
|
|
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,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-11-26 09:51:43 -06:00
|
|
|
pub fn as_object(&self) -> Option<&KclObjectFields> {
|
2024-11-21 10:47:32 -06:00
|
|
|
if let KclValue::Object { value, meta: _ } = &self {
|
|
|
|
Some(value)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-11-26 09:51:43 -06:00
|
|
|
pub fn into_object(self) -> Option<KclObjectFields> {
|
2024-11-21 10:47:32 -06:00
|
|
|
if let KclValue::Object { value, meta: _ } = self {
|
|
|
|
Some(value)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn as_str(&self) -> Option<&str> {
|
|
|
|
if let KclValue::String { value, meta: _ } = &self {
|
|
|
|
Some(value)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn as_array(&self) -> Option<&[KclValue]> {
|
2025-04-14 05:58:19 -04:00
|
|
|
match self {
|
2025-05-11 23:57:31 -04:00
|
|
|
KclValue::Tuple { value, .. } | KclValue::HomArray { value, .. } => Some(value),
|
2025-04-14 05:58:19 -04:00
|
|
|
_ => None,
|
2024-11-21 10:47:32 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-04-14 05:58:19 -04:00
|
|
|
pub fn as_point2d(&self) -> Option<[TyF64; 2]> {
|
2024-11-21 10:47:32 -06:00
|
|
|
let arr = self.as_array()?;
|
|
|
|
if arr.len() != 2 {
|
|
|
|
return None;
|
|
|
|
}
|
2025-04-14 05:58:19 -04:00
|
|
|
let x = arr[0].as_ty_f64()?;
|
|
|
|
let y = arr[1].as_ty_f64()?;
|
2024-11-21 10:47:32 -06:00
|
|
|
Some([x, y])
|
|
|
|
}
|
|
|
|
|
2025-04-14 05:58:19 -04:00
|
|
|
pub fn as_point3d(&self) -> Option<[TyF64; 3]> {
|
|
|
|
let arr = self.as_array()?;
|
|
|
|
if arr.len() != 3 {
|
|
|
|
return None;
|
|
|
|
}
|
|
|
|
let x = arr[0].as_ty_f64()?;
|
|
|
|
let y = arr[1].as_ty_f64()?;
|
|
|
|
let z = arr[2].as_ty_f64()?;
|
|
|
|
Some([x, y, z])
|
|
|
|
}
|
|
|
|
|
2024-11-21 10:47:32 -06:00
|
|
|
pub fn as_uuid(&self) -> Option<uuid::Uuid> {
|
|
|
|
if let KclValue::Uuid { value, meta: _ } = &self {
|
|
|
|
Some(*value)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn as_plane(&self) -> Option<&Plane> {
|
2025-01-22 09:42:09 +13:00
|
|
|
if let KclValue::Plane { value } = &self {
|
2024-11-21 10:47:32 -06:00
|
|
|
Some(value)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn as_solid(&self) -> Option<&Solid> {
|
2025-01-22 09:42:09 +13:00
|
|
|
if let KclValue::Solid { value } = &self {
|
2024-11-21 10:47:32 -06:00
|
|
|
Some(value)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-03-17 17:57:26 +13:00
|
|
|
pub fn as_sketch(&self) -> Option<&Sketch> {
|
|
|
|
if let KclValue::Sketch { value } = self {
|
|
|
|
Some(value)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-03-17 12:28:51 +13:00
|
|
|
pub fn as_mut_sketch(&mut self) -> Option<&mut Sketch> {
|
2025-02-12 10:22:56 +13:00
|
|
|
if let KclValue::Sketch { value } = self {
|
|
|
|
Some(value)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-03-17 12:28:51 +13:00
|
|
|
pub fn as_mut_tag(&mut self) -> Option<&mut TagIdentifier> {
|
|
|
|
if let KclValue::TagIdentifier(value) = self {
|
|
|
|
Some(value)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
2025-04-07 16:13:15 +12:00
|
|
|
|
2025-04-14 05:58:19 -04:00
|
|
|
#[cfg(test)]
|
2024-11-21 10:47:32 -06:00
|
|
|
pub fn as_f64(&self) -> Option<f64> {
|
2025-02-14 13:03:23 +13:00
|
|
|
if let KclValue::Number { value, .. } = &self {
|
2024-11-21 10:47:32 -06:00
|
|
|
Some(*value)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-04-07 16:13:15 +12:00
|
|
|
pub fn as_ty_f64(&self) -> Option<TyF64> {
|
|
|
|
if let KclValue::Number { value, ty, .. } = &self {
|
|
|
|
Some(TyF64::new(*value, ty.clone()))
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-11-21 10:47:32 -06:00
|
|
|
pub fn as_bool(&self) -> Option<bool> {
|
|
|
|
if let KclValue::Bool { value, meta: _ } = &self {
|
|
|
|
Some(*value)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// If this value fits in a u32, return it.
|
|
|
|
pub fn get_u32(&self, source_ranges: Vec<SourceRange>) -> Result<u32, KclError> {
|
|
|
|
let u = self.as_int().and_then(|n| u64::try_from(n).ok()).ok_or_else(|| {
|
|
|
|
KclError::Semantic(KclErrorDetails {
|
|
|
|
message: "Expected an integer >= 0".to_owned(),
|
|
|
|
source_ranges: source_ranges.clone(),
|
|
|
|
})
|
|
|
|
})?;
|
|
|
|
u32::try_from(u).map_err(|_| {
|
|
|
|
KclError::Semantic(KclErrorDetails {
|
|
|
|
message: "Number was too big".to_owned(),
|
|
|
|
source_ranges,
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
/// If this value is of type function, return it.
|
2025-02-22 20:16:29 +13:00
|
|
|
pub fn get_function(&self) -> Option<&FunctionSource> {
|
|
|
|
match self {
|
|
|
|
KclValue::Function { value, .. } => Some(value),
|
|
|
|
_ => None,
|
|
|
|
}
|
2024-11-21 10:47:32 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
/// 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::Semantic(KclErrorDetails {
|
|
|
|
message: format!("Not a tag identifier: {:?}", self),
|
|
|
|
source_ranges: 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::Semantic(KclErrorDetails {
|
|
|
|
message: format!("Not a tag declarator: {:?}", self),
|
|
|
|
source_ranges: self.clone().into(),
|
|
|
|
})),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// If this KCL value is a bool, retrieve it.
|
|
|
|
pub fn get_bool(&self) -> Result<bool, KclError> {
|
|
|
|
let Self::Bool { value: b, .. } = self else {
|
|
|
|
return Err(KclError::Type(KclErrorDetails {
|
|
|
|
source_ranges: self.into(),
|
|
|
|
message: format!("Expected bool, found {}", self.human_friendly_type()),
|
|
|
|
}));
|
|
|
|
};
|
|
|
|
Ok(*b)
|
|
|
|
}
|
|
|
|
|
2025-03-24 21:55:24 +13:00
|
|
|
pub fn as_fn(&self) -> Option<&FunctionSource> {
|
2025-02-22 20:16:29 +13:00
|
|
|
match self {
|
2025-03-24 21:55:24 +13:00
|
|
|
KclValue::Function { value, .. } => Some(value),
|
|
|
|
_ => None,
|
2024-12-09 22:11:16 -06:00
|
|
|
}
|
|
|
|
}
|
2025-03-04 22:53:31 +13:00
|
|
|
|
|
|
|
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
|
2025-05-11 23:57:31 -04:00
|
|
|
KclValue::Tuple { .. } => Some("[...]".to_owned()),
|
2025-03-17 17:57:26 +13:00
|
|
|
KclValue::HomArray { .. } => Some("[...]".to_owned()),
|
2025-03-04 22:53:31 +13:00
|
|
|
KclValue::Object { .. } => Some("{ ... }".to_owned()),
|
|
|
|
KclValue::Module { .. }
|
|
|
|
| KclValue::Solid { .. }
|
|
|
|
| KclValue::Sketch { .. }
|
|
|
|
| KclValue::Helix { .. }
|
|
|
|
| KclValue::ImportedGeometry(_)
|
|
|
|
| KclValue::Function { .. }
|
|
|
|
| KclValue::Plane { .. }
|
|
|
|
| KclValue::Face { .. }
|
|
|
|
| KclValue::KclNone { .. }
|
2025-03-17 12:28:51 +13:00
|
|
|
| KclValue::Type { .. } => None,
|
2025-03-04 22:53:31 +13:00
|
|
|
}
|
|
|
|
}
|
2024-11-21 10:47:32 -06:00
|
|
|
}
|
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),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|