Skip to main content

kcl_api/
cad_op.rs

1use indexmap::IndexMap;
2use kcl_error::SourceRange;
3use serde::Serialize;
4
5use super::ArtifactId;
6use crate::ModuleId;
7use crate::NumericType;
8use crate::ast::ItemVisibility;
9use crate::ast::node_path::NodePath;
10use crate::front::ObjectId;
11
12/// A CAD modeling operation for display in the feature tree, AKA operations
13/// timeline.
14#[allow(clippy::large_enum_variant)]
15#[derive(Debug, Clone, Serialize, PartialEq, ts_rs::TS)]
16#[ts(export_to = "Operation.ts")]
17#[serde(tag = "type")]
18pub enum Operation {
19    #[serde(rename_all = "camelCase")]
20    StdLibCall {
21        name: String,
22        /// The unlabeled argument to the function.
23        unlabeled_arg: Option<OpArg>,
24        /// The labeled keyword arguments to the function.
25        labeled_args: IndexMap<String, OpArg>,
26        /// The node path of the operation in the source code.
27        node_path: NodePath,
28        /// The true source range of the operation in the source code.
29        source_range: SourceRange,
30        /// The source range that's the boundary of calling the standard
31        /// library.
32        #[serde(default, skip_serializing_if = "Option::is_none")]
33        stdlib_entry_source_range: Option<SourceRange>,
34        /// True if the operation resulted in an error.
35        #[serde(default, skip_serializing_if = "is_false")]
36        is_error: bool,
37    },
38    #[serde(rename_all = "camelCase")]
39    VariableDeclaration {
40        /// The variable name.
41        name: String,
42        /// The value of the variable.
43        value: OpKclValue,
44        /// The visibility modifier of the variable, e.g. `export`.  `Default`
45        /// means there is no visibility modifier.
46        visibility: ItemVisibility,
47        /// The node path of the operation in the source code.
48        node_path: NodePath,
49        /// The source range of the operation in the source code.
50        source_range: SourceRange,
51    },
52    #[serde(rename_all = "camelCase")]
53    GroupBegin {
54        /// The details of the group.
55        group: Group,
56        /// The node path of the operation in the source code.
57        node_path: NodePath,
58        /// The source range of the operation in the source code.
59        source_range: SourceRange,
60    },
61    #[serde(rename_all = "camelCase")]
62    ModuleInstance {
63        /// The name of the module being used.
64        name: String,
65        /// The ID of the module which can be used to determine its path.
66        module_id: ModuleId,
67        /// Whether this is a glob import (`import * from "foo.kcl"`).
68        #[serde(default, skip_serializing_if = "std::ops::Not::not")]
69        glob: bool,
70        /// The node path of the operation in the source code.
71        node_path: NodePath,
72        /// The source range of the operation in the source code.
73        source_range: SourceRange,
74    },
75    GroupEnd,
76}
77
78impl Operation {
79    /// If the variant is `StdLibCall`, set the `is_error` field.
80    pub fn set_std_lib_call_is_error(&mut self, is_err: bool) {
81        match self {
82            Self::StdLibCall { is_error, .. } => *is_error = is_err,
83            Self::VariableDeclaration { .. }
84            | Self::GroupBegin { .. }
85            | Self::ModuleInstance { .. }
86            | Self::GroupEnd => {}
87        }
88    }
89}
90
91#[derive(Debug, Clone, Serialize, PartialEq, ts_rs::TS)]
92#[ts(export_to = "Operation.ts")]
93#[serde(tag = "type")]
94#[cfg_attr(not(target_arch = "wasm32"), expect(clippy::large_enum_variant))]
95pub enum Group {
96    /// A function call.
97    #[serde(rename_all = "camelCase")]
98    FunctionCall {
99        /// The name of the user-defined function being called.  Anonymous
100        /// functions have no name.
101        name: Option<String>,
102        /// The location of the function being called so that there's enough
103        /// info to go to its definition.
104        function_source_range: SourceRange,
105        /// The unlabeled argument to the function.
106        unlabeled_arg: Option<OpArg>,
107        /// The labeled keyword arguments to the function.
108        labeled_args: IndexMap<String, OpArg>,
109    },
110    /// A sketch block.
111    #[allow(dead_code)]
112    #[serde(rename_all = "camelCase")]
113    SketchBlock {
114        /// The ID of the sketch this group wraps.
115        sketch_id: ObjectId,
116    },
117}
118
119/// An argument to a CAD modeling operation.
120#[derive(Debug, Clone, Serialize, PartialEq, ts_rs::TS)]
121#[ts(export_to = "Operation.ts")]
122#[serde(rename_all = "camelCase")]
123pub struct OpArg {
124    /// The runtime value of the argument.  Instead of using [`KclValue`], we
125    /// refer to scene objects using their [`ArtifactId`]s.
126    value: OpKclValue,
127    /// The KCL code expression for the argument.  This is used in the UI so
128    /// that the user can edit the expression.
129    source_range: SourceRange,
130}
131
132impl OpArg {
133    pub fn new(value: OpKclValue, source_range: SourceRange) -> Self {
134        Self { value, source_range }
135    }
136}
137
138fn is_false(b: &bool) -> bool {
139    !*b
140}
141
142/// A KCL value used in Operations.  `ArtifactId`s are used to refer to the
143/// actual scene objects.  Any data not needed in the UI may be omitted.
144#[derive(Debug, Clone, Serialize, PartialEq, ts_rs::TS)]
145#[ts(export_to = "Operation.ts")]
146#[serde(tag = "type")]
147pub enum OpKclValue {
148    Uuid {
149        value: ::uuid::Uuid,
150    },
151    Bool {
152        value: bool,
153    },
154    Number {
155        value: f64,
156        ty: NumericType,
157    },
158    String {
159        value: String,
160    },
161    /// Shown in the feature tree by nominal identity, e.g. `Color::Red`, not by
162    /// the variant's representation.
163    Enum {
164        enum_name: String,
165        variant: String,
166    },
167    SketchVar {
168        value: f64,
169        ty: NumericType,
170    },
171    Array {
172        value: Vec<OpKclValue>,
173    },
174    Object {
175        value: OpKclObjectFields,
176    },
177    TagIdentifier {
178        /// The name of the tag identifier.
179        value: String,
180        /// The artifact ID of the object it refers to.
181        artifact_id: Option<ArtifactId>,
182    },
183    TagDeclarator {
184        name: String,
185    },
186    GdtAnnotation {
187        artifact_id: ArtifactId,
188    },
189    Plane {
190        artifact_id: ArtifactId,
191    },
192    Face {
193        artifact_id: ArtifactId,
194    },
195    Sketch {
196        value: Box<OpSketch>,
197    },
198    Segment {
199        artifact_id: ArtifactId,
200    },
201    Solid {
202        value: Box<OpSolid>,
203    },
204    Helix {
205        value: Box<OpHelix>,
206    },
207    ImportedGeometry {
208        artifact_id: ArtifactId,
209    },
210    Function {},
211    Module {},
212    Type {},
213    KclNone {},
214    BoundedEdge {},
215}
216
217pub type OpKclObjectFields = IndexMap<String, OpKclValue>;
218
219#[derive(Debug, Clone, Serialize, PartialEq, ts_rs::TS)]
220#[ts(export_to = "Operation.ts")]
221#[serde(rename_all = "camelCase")]
222pub struct OpSketch {
223    artifact_id: ArtifactId,
224}
225
226impl OpSketch {
227    pub fn new(artifact_id: ArtifactId) -> Self {
228        Self { artifact_id }
229    }
230}
231
232#[derive(Debug, Clone, Serialize, PartialEq, ts_rs::TS)]
233#[ts(export_to = "Operation.ts")]
234#[serde(rename_all = "camelCase")]
235pub struct OpSolid {
236    artifact_id: ArtifactId,
237}
238
239impl OpSolid {
240    pub fn new(artifact_id: ArtifactId) -> Self {
241        Self { artifact_id }
242    }
243}
244
245#[derive(Debug, Clone, Serialize, PartialEq, ts_rs::TS)]
246#[ts(export_to = "Operation.ts")]
247#[serde(rename_all = "camelCase")]
248pub struct OpHelix {
249    artifact_id: ArtifactId,
250}
251
252impl OpHelix {
253    pub fn new(artifact_id: ArtifactId) -> Self {
254        Self { artifact_id }
255    }
256}