use indexmap::IndexMap;
use serde::Serialize;
use super::ArtifactId;
use super::KclValue;
use super::types::NumericType;
use crate::ModuleId;
use crate::NodePath;
use crate::SourceRange;
use crate::front::ObjectId;
use crate::parsing::ast::types::ItemVisibility;
#[allow(clippy::large_enum_variant)]
#[derive(Debug, Clone, Serialize, PartialEq, ts_rs::TS)]
#[ts(export_to = "Operation.ts")]
#[serde(tag = "type")]
pub enum Operation {
#[serde(rename_all = "camelCase")]
StdLibCall {
name: String,
unlabeled_arg: Option<OpArg>,
labeled_args: IndexMap<String, OpArg>,
node_path: NodePath,
source_range: SourceRange,
#[serde(default, skip_serializing_if = "Option::is_none")]
stdlib_entry_source_range: Option<SourceRange>,
#[serde(default, skip_serializing_if = "is_false")]
is_error: bool,
},
#[serde(rename_all = "camelCase")]
VariableDeclaration {
name: String,
value: OpKclValue,
visibility: ItemVisibility,
node_path: NodePath,
source_range: SourceRange,
},
#[serde(rename_all = "camelCase")]
GroupBegin {
group: Group,
node_path: NodePath,
source_range: SourceRange,
},
GroupEnd,
#[allow(dead_code)]
#[serde(rename_all = "camelCase")]
SketchSolve {
sketch_id: ObjectId,
node_path: NodePath,
source_range: SourceRange,
},
}
impl Operation {
pub(crate) fn set_std_lib_call_is_error(&mut self, is_err: bool) {
match self {
Self::StdLibCall { is_error, .. } => *is_error = is_err,
Self::VariableDeclaration { .. } | Self::GroupBegin { .. } | Self::GroupEnd | Self::SketchSolve { .. } => {}
}
}
#[cfg(feature = "artifact-graph")]
pub(crate) fn fill_node_paths(&mut self, programs: &crate::execution::ProgramLookup, cached_body_items: usize) {
match self {
Operation::StdLibCall {
node_path,
source_range,
stdlib_entry_source_range,
..
} => {
let range = stdlib_entry_source_range.as_ref().unwrap_or(source_range);
node_path.fill_placeholder(programs, cached_body_items, *range);
}
Operation::VariableDeclaration {
node_path,
source_range,
..
}
| Operation::GroupBegin {
node_path,
source_range,
..
} => {
node_path.fill_placeholder(programs, cached_body_items, *source_range);
}
Operation::GroupEnd => {}
Operation::SketchSolve {
node_path,
source_range,
..
} => {
node_path.fill_placeholder(programs, cached_body_items, *source_range);
}
}
}
}
#[derive(Debug, Clone, Serialize, PartialEq, ts_rs::TS)]
#[ts(export_to = "Operation.ts")]
#[serde(tag = "type")]
#[expect(clippy::large_enum_variant)]
pub enum Group {
#[serde(rename_all = "camelCase")]
FunctionCall {
name: Option<String>,
function_source_range: SourceRange,
unlabeled_arg: Option<OpArg>,
labeled_args: IndexMap<String, OpArg>,
},
#[allow(dead_code)]
#[serde(rename_all = "camelCase")]
ModuleInstance {
name: String,
module_id: ModuleId,
},
}
#[derive(Debug, Clone, Serialize, PartialEq, ts_rs::TS)]
#[ts(export_to = "Operation.ts")]
#[serde(rename_all = "camelCase")]
pub struct OpArg {
value: OpKclValue,
source_range: SourceRange,
}
impl OpArg {
pub(crate) fn new(value: OpKclValue, source_range: SourceRange) -> Self {
Self { value, source_range }
}
}
fn is_false(b: &bool) -> bool {
!*b
}
#[derive(Debug, Clone, Serialize, PartialEq, ts_rs::TS)]
#[ts(export_to = "Operation.ts")]
#[serde(tag = "type")]
pub enum OpKclValue {
Uuid {
value: ::uuid::Uuid,
},
Bool {
value: bool,
},
Number {
value: f64,
ty: NumericType,
},
String {
value: String,
},
SketchVar {
value: f64,
ty: NumericType,
},
Array {
value: Vec<OpKclValue>,
},
Object {
value: OpKclObjectFields,
},
TagIdentifier {
value: String,
artifact_id: Option<ArtifactId>,
},
TagDeclarator {
name: String,
},
GdtAnnotation {
artifact_id: ArtifactId,
},
Plane {
artifact_id: ArtifactId,
},
Face {
artifact_id: ArtifactId,
},
Sketch {
value: Box<OpSketch>,
},
Segment {
artifact_id: ArtifactId,
},
Solid {
value: Box<OpSolid>,
},
Helix {
value: Box<OpHelix>,
},
ImportedGeometry {
artifact_id: ArtifactId,
},
Function {},
Module {},
Type {},
KclNone {},
BoundedEdge {},
}
pub type OpKclObjectFields = IndexMap<String, OpKclValue>;
#[derive(Debug, Clone, Serialize, PartialEq, ts_rs::TS)]
#[ts(export_to = "Operation.ts")]
#[serde(rename_all = "camelCase")]
pub struct OpSketch {
artifact_id: ArtifactId,
}
#[derive(Debug, Clone, Serialize, PartialEq, ts_rs::TS)]
#[ts(export_to = "Operation.ts")]
#[serde(rename_all = "camelCase")]
pub struct OpSolid {
artifact_id: ArtifactId,
}
#[derive(Debug, Clone, Serialize, PartialEq, ts_rs::TS)]
#[ts(export_to = "Operation.ts")]
#[serde(rename_all = "camelCase")]
pub struct OpHelix {
artifact_id: ArtifactId,
}
impl From<&KclValue> for OpKclValue {
fn from(value: &KclValue) -> Self {
match value {
KclValue::Uuid { value, .. } => Self::Uuid { value: *value },
KclValue::Bool { value, .. } => Self::Bool { value: *value },
KclValue::Number { value, ty, .. } => Self::Number { value: *value, ty: *ty },
KclValue::String { value, .. } => Self::String { value: value.clone() },
KclValue::SketchVar { value, .. } => Self::SketchVar {
value: value.initial_value,
ty: value.ty,
},
KclValue::SketchConstraint { .. } => {
debug_assert!(false, "Sketch constraint cannot be represented in operations");
Self::KclNone {}
}
KclValue::Tuple { value, .. } | KclValue::HomArray { value, .. } => {
let value = value.iter().map(Self::from).collect();
Self::Array { value }
}
KclValue::Object { value, .. } => {
let value = value.iter().map(|(k, v)| (k.clone(), Self::from(v))).collect();
Self::Object { value }
}
KclValue::TagIdentifier(tag_identifier) => Self::TagIdentifier {
value: tag_identifier.value.clone(),
artifact_id: tag_identifier.get_cur_info().map(|info| ArtifactId::new(info.id)),
},
KclValue::TagDeclarator(node) => Self::TagDeclarator {
name: node.name.clone(),
},
KclValue::GdtAnnotation { value } => Self::GdtAnnotation {
artifact_id: ArtifactId::new(value.id),
},
KclValue::Plane { value } => Self::Plane {
artifact_id: value.artifact_id,
},
KclValue::Face { value } => Self::Face {
artifact_id: value.artifact_id,
},
KclValue::Segment { value } => match &value.repr {
crate::execution::geometry::SegmentRepr::Unsolved { .. } => {
Self::KclNone {}
}
crate::execution::geometry::SegmentRepr::Solved { segment, .. } => Self::Segment {
artifact_id: ArtifactId::new(segment.id),
},
},
KclValue::Sketch { value } => Self::Sketch {
value: Box::new(OpSketch {
artifact_id: value.artifact_id,
}),
},
KclValue::Solid { value } => Self::Solid {
value: Box::new(OpSolid {
artifact_id: value.artifact_id,
}),
},
KclValue::Helix { value } => Self::Helix {
value: Box::new(OpHelix {
artifact_id: value.artifact_id,
}),
},
KclValue::ImportedGeometry(imported_geometry) => Self::ImportedGeometry {
artifact_id: ArtifactId::new(imported_geometry.id),
},
KclValue::Function { .. } => Self::Function {},
KclValue::Module { .. } => Self::Module {},
KclValue::KclNone { .. } => Self::KclNone {},
KclValue::Type { .. } => Self::Type {},
KclValue::BoundedEdge { .. } => Self::BoundedEdge {},
}
}
}