diff --git a/docs/kcl/loft.md b/docs/kcl/loft.md
index bdc912630f..e73aa69cfa 100644
--- a/docs/kcl/loft.md
+++ b/docs/kcl/loft.md
@@ -9,7 +9,7 @@ Create a 3D surface or solid by interpolating between two or more sketches.
The sketches need to closed and on the same plane.
```js
-loft(sketches: [Sketch], v_degree: NonZeroU32, bez_approximate_rational: bool, base_curve_index?: u32, tolerance?: number) -> Solid
+loft(sketches: [Sketch], v_degree: NonZeroU32, bez_approximate_rational: bool, base_curve_index?: integer, tolerance?: number) -> Solid
```
@@ -20,7 +20,7 @@ loft(sketches: [Sketch], v_degree: NonZeroU32, bez_approximate_rational: bool, b
| `sketches` | [`[Sketch]`](/docs/kcl/types/Sketch) | Which sketches to loft. Must include at least 2 sketches. | Yes |
| `v_degree` | `NonZeroU32` | Degree of the interpolation. Must be greater than zero. For example, use 2 for quadratic, or 3 for cubic interpolation in the V direction. This defaults to 2, if not specified. | Yes |
| `bez_approximate_rational` | `bool` | Attempt to approximate rational curves (such as arcs) using a bezier. This will remove banding around interpolations between arcs and non-arcs. It may produce errors in other scenarios Over time, this field won't be necessary. | Yes |
-| `base_curve_index` | `u32` | This can be set to override the automatically determined topological base curve, which is usually the first section encountered. | No |
+| `base_curve_index` | `integer` | This can be set to override the automatically determined topological base curve, which is usually the first section encountered. | No |
| `tolerance` | `number` | Tolerance for the loft operation. | No |
### Returns
diff --git a/docs/kcl/patternTransform.md b/docs/kcl/patternTransform.md
index 6cba339bb0..2b4854ba70 100644
--- a/docs/kcl/patternTransform.md
+++ b/docs/kcl/patternTransform.md
@@ -35,7 +35,7 @@ The transform function returns a transform object. All properties of the object
- `rotation.origin` (either "local" i.e. rotate around its own center, "global" i.e. rotate around the scene's center, or a 3D point, defaults to "local")
```js
-patternTransform(total_instances: u32, transform_function: FunctionParam, solid_set: SolidSet) -> [Solid]
+patternTransform(total_instances: integer, transform_function: FunctionParam, solid_set: SolidSet) -> [Solid]
```
@@ -43,7 +43,7 @@ patternTransform(total_instances: u32, transform_function: FunctionParam, solid_
| Name | Type | Description | Required |
|----------|------|-------------|----------|
-| `total_instances` | `u32` | | Yes |
+| `total_instances` | `integer` | | Yes |
| `transform_function` | `FunctionParam` | | Yes |
| `solid_set` | [`SolidSet`](/docs/kcl/types/SolidSet) | A solid or a group of solids. | Yes |
diff --git a/docs/kcl/patternTransform2d.md b/docs/kcl/patternTransform2d.md
index 749246bd9b..353ce75b5d 100644
--- a/docs/kcl/patternTransform2d.md
+++ b/docs/kcl/patternTransform2d.md
@@ -9,7 +9,7 @@ Just like patternTransform, but works on 2D sketches not 3D solids.
```js
-patternTransform2d(total_instances: u32, transform_function: FunctionParam, solid_set: SketchSet) -> [Sketch]
+patternTransform2d(total_instances: integer, transform_function: FunctionParam, solid_set: SketchSet) -> [Sketch]
```
@@ -17,7 +17,7 @@ patternTransform2d(total_instances: u32, transform_function: FunctionParam, soli
| Name | Type | Description | Required |
|----------|------|-------------|----------|
-| `total_instances` | `u32` | | Yes |
+| `total_instances` | `integer` | | Yes |
| `transform_function` | `FunctionParam` | | Yes |
| `solid_set` | [`SketchSet`](/docs/kcl/types/SketchSet) | A sketch or a group of sketches. | Yes |
diff --git a/docs/kcl/std.json b/docs/kcl/std.json
index d66b087a7d..2e71fda040 100644
--- a/docs/kcl/std.json
+++ b/docs/kcl/std.json
@@ -97135,7 +97135,7 @@
},
{
"name": "base_curve_index",
- "type": "u32",
+ "type": "integer",
"schema": {
"$schema": "https://spec.openapis.org/oas/3.0/schema/2019-04-02#/definitions/Schema",
"title": "Nullable_uint32",
@@ -101932,6 +101932,31 @@
}
}
},
+ {
+ "type": "object",
+ "required": [
+ "__meta",
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "Module"
+ ]
+ },
+ "value": {
+ "$ref": "#/components/schemas/ModuleId"
+ },
+ "__meta": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/Metadata"
+ }
+ }
+ }
+ },
{
"type": "object",
"required": [
@@ -103313,6 +103338,12 @@
}
}
},
+ "ModuleId": {
+ "description": "Identifier of a source file. Uses a u32 to keep the size small.",
+ "type": "integer",
+ "format": "uint32",
+ "minimum": 0.0
+ },
"KclNone": {
"description": "KCL value for an optional parameter which was not given an argument. (remember, parameters are in the function declaration, arguments are in the function call/application).",
"type": "object",
@@ -103931,6 +103962,31 @@
}
}
},
+ {
+ "type": "object",
+ "required": [
+ "__meta",
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "Module"
+ ]
+ },
+ "value": {
+ "$ref": "#/components/schemas/ModuleId"
+ },
+ "__meta": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/Metadata"
+ }
+ }
+ }
+ },
{
"type": "object",
"required": [
@@ -105312,6 +105368,12 @@
}
}
},
+ "ModuleId": {
+ "description": "Identifier of a source file. Uses a u32 to keep the size small.",
+ "type": "integer",
+ "format": "uint32",
+ "minimum": 0.0
+ },
"KclNone": {
"description": "KCL value for an optional parameter which was not given an argument. (remember, parameters are in the function declaration, arguments are in the function call/application).",
"type": "object",
@@ -105934,6 +105996,31 @@
}
}
},
+ {
+ "type": "object",
+ "required": [
+ "__meta",
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "Module"
+ ]
+ },
+ "value": {
+ "$ref": "#/components/schemas/ModuleId"
+ },
+ "__meta": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/Metadata"
+ }
+ }
+ }
+ },
{
"type": "object",
"required": [
@@ -107315,6 +107402,12 @@
}
}
},
+ "ModuleId": {
+ "description": "Identifier of a source file. Uses a u32 to keep the size small.",
+ "type": "integer",
+ "format": "uint32",
+ "minimum": 0.0
+ },
"KclNone": {
"description": "KCL value for an optional parameter which was not given an argument. (remember, parameters are in the function declaration, arguments are in the function call/application).",
"type": "object",
@@ -122705,7 +122798,7 @@
"args": [
{
"name": "total_instances",
- "type": "u32",
+ "type": "integer",
"schema": {
"$schema": "https://spec.openapis.org/oas/3.0/schema/2019-04-02#/definitions/Schema",
"title": "uint32",
@@ -125482,7 +125575,7 @@
"args": [
{
"name": "total_instances",
- "type": "u32",
+ "type": "integer",
"schema": {
"$schema": "https://spec.openapis.org/oas/3.0/schema/2019-04-02#/definitions/Schema",
"title": "uint32",
@@ -137258,6 +137351,31 @@
}
}
},
+ {
+ "type": "object",
+ "required": [
+ "__meta",
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "Module"
+ ]
+ },
+ "value": {
+ "$ref": "#/components/schemas/ModuleId"
+ },
+ "__meta": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/Metadata"
+ }
+ }
+ }
+ },
{
"type": "object",
"required": [
@@ -138639,6 +138757,12 @@
}
}
},
+ "ModuleId": {
+ "description": "Identifier of a source file. Uses a u32 to keep the size small.",
+ "type": "integer",
+ "format": "uint32",
+ "minimum": 0.0
+ },
"KclNone": {
"description": "KCL value for an optional parameter which was not given an argument. (remember, parameters are in the function declaration, arguments are in the function call/application).",
"type": "object",
@@ -139254,6 +139378,31 @@
}
}
},
+ {
+ "type": "object",
+ "required": [
+ "__meta",
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "Module"
+ ]
+ },
+ "value": {
+ "$ref": "#/components/schemas/ModuleId"
+ },
+ "__meta": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/Metadata"
+ }
+ }
+ }
+ },
{
"type": "object",
"required": [
@@ -139869,6 +140018,31 @@
}
}
},
+ {
+ "type": "object",
+ "required": [
+ "__meta",
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "Module"
+ ]
+ },
+ "value": {
+ "$ref": "#/components/schemas/ModuleId"
+ },
+ "__meta": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/Metadata"
+ }
+ }
+ }
+ },
{
"type": "object",
"required": [
@@ -141250,6 +141424,12 @@
}
}
},
+ "ModuleId": {
+ "description": "Identifier of a source file. Uses a u32 to keep the size small.",
+ "type": "integer",
+ "format": "uint32",
+ "minimum": 0.0
+ },
"KclNone": {
"description": "KCL value for an optional parameter which was not given an argument. (remember, parameters are in the function declaration, arguments are in the function call/application).",
"type": "object",
@@ -141866,6 +142046,31 @@
}
}
},
+ {
+ "type": "object",
+ "required": [
+ "__meta",
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "Module"
+ ]
+ },
+ "value": {
+ "$ref": "#/components/schemas/ModuleId"
+ },
+ "__meta": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/Metadata"
+ }
+ }
+ }
+ },
{
"type": "object",
"required": [
@@ -142508,6 +142713,31 @@
}
}
},
+ {
+ "type": "object",
+ "required": [
+ "__meta",
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "Module"
+ ]
+ },
+ "value": {
+ "$ref": "#/components/schemas/ModuleId"
+ },
+ "__meta": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/Metadata"
+ }
+ }
+ }
+ },
{
"type": "object",
"required": [
@@ -143862,6 +144092,12 @@
}
}
},
+ "ModuleId": {
+ "description": "Identifier of a source file. Uses a u32 to keep the size small.",
+ "type": "integer",
+ "format": "uint32",
+ "minimum": 0.0
+ },
"KclNone": {
"description": "KCL value for an optional parameter which was not given an argument. (remember, parameters are in the function declaration, arguments are in the function call/application).",
"type": "object",
@@ -144496,6 +144732,31 @@
}
}
},
+ {
+ "type": "object",
+ "required": [
+ "__meta",
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "Module"
+ ]
+ },
+ "value": {
+ "$ref": "#/components/schemas/ModuleId"
+ },
+ "__meta": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/Metadata"
+ }
+ }
+ }
+ },
{
"type": "object",
"required": [
@@ -145877,6 +146138,12 @@
}
}
},
+ "ModuleId": {
+ "description": "Identifier of a source file. Uses a u32 to keep the size small.",
+ "type": "integer",
+ "format": "uint32",
+ "minimum": 0.0
+ },
"KclNone": {
"description": "KCL value for an optional parameter which was not given an argument. (remember, parameters are in the function declaration, arguments are in the function call/application).",
"type": "object",
@@ -146492,6 +146759,31 @@
}
}
},
+ {
+ "type": "object",
+ "required": [
+ "__meta",
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "Module"
+ ]
+ },
+ "value": {
+ "$ref": "#/components/schemas/ModuleId"
+ },
+ "__meta": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/Metadata"
+ }
+ }
+ }
+ },
{
"type": "object",
"required": [
@@ -147107,6 +147399,31 @@
}
}
},
+ {
+ "type": "object",
+ "required": [
+ "__meta",
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "Module"
+ ]
+ },
+ "value": {
+ "$ref": "#/components/schemas/ModuleId"
+ },
+ "__meta": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/Metadata"
+ }
+ }
+ }
+ },
{
"type": "object",
"required": [
@@ -148488,6 +148805,12 @@
}
}
},
+ "ModuleId": {
+ "description": "Identifier of a source file. Uses a u32 to keep the size small.",
+ "type": "integer",
+ "format": "uint32",
+ "minimum": 0.0
+ },
"KclNone": {
"description": "KCL value for an optional parameter which was not given an argument. (remember, parameters are in the function declaration, arguments are in the function call/application).",
"type": "object",
@@ -149106,6 +149429,31 @@
}
}
},
+ {
+ "type": "object",
+ "required": [
+ "__meta",
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "Module"
+ ]
+ },
+ "value": {
+ "$ref": "#/components/schemas/ModuleId"
+ },
+ "__meta": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/Metadata"
+ }
+ }
+ }
+ },
{
"type": "object",
"required": [
@@ -150487,6 +150835,12 @@
}
}
},
+ "ModuleId": {
+ "description": "Identifier of a source file. Uses a u32 to keep the size small.",
+ "type": "integer",
+ "format": "uint32",
+ "minimum": 0.0
+ },
"KclNone": {
"description": "KCL value for an optional parameter which was not given an argument. (remember, parameters are in the function declaration, arguments are in the function call/application).",
"type": "object",
@@ -151103,6 +151457,31 @@
}
}
},
+ {
+ "type": "object",
+ "required": [
+ "__meta",
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "Module"
+ ]
+ },
+ "value": {
+ "$ref": "#/components/schemas/ModuleId"
+ },
+ "__meta": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/Metadata"
+ }
+ }
+ }
+ },
{
"type": "object",
"required": [
@@ -151745,6 +152124,31 @@
}
}
},
+ {
+ "type": "object",
+ "required": [
+ "__meta",
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "Module"
+ ]
+ },
+ "value": {
+ "$ref": "#/components/schemas/ModuleId"
+ },
+ "__meta": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/Metadata"
+ }
+ }
+ }
+ },
{
"type": "object",
"required": [
@@ -153099,6 +153503,12 @@
}
}
},
+ "ModuleId": {
+ "description": "Identifier of a source file. Uses a u32 to keep the size small.",
+ "type": "integer",
+ "format": "uint32",
+ "minimum": 0.0
+ },
"KclNone": {
"description": "KCL value for an optional parameter which was not given an argument. (remember, parameters are in the function declaration, arguments are in the function call/application).",
"type": "object",
diff --git a/docs/kcl/types/AngledLineData.md b/docs/kcl/types/AngledLineData.md
index 8b75d8b486..f49fc8c5c9 100644
--- a/docs/kcl/types/AngledLineData.md
+++ b/docs/kcl/types/AngledLineData.md
@@ -13,13 +13,18 @@ Data to draw an angled line.
An angle and length with explicitly named parameters
-[`PolarCoordsData`](/docs/kcl/types/PolarCoordsData)
+**Type:** `object`
+## Properties
+| Property | Type | Description | Required |
+|----------|------|-------------|----------|
+| `angle` |`number`| The angle of the line (in degrees). | No |
+| `length` |`number`| The length of the line. | No |
----
diff --git a/docs/kcl/types/KclValue.md b/docs/kcl/types/KclValue.md
index f71daf6ab9..cabf63161f 100644
--- a/docs/kcl/types/KclValue.md
+++ b/docs/kcl/types/KclValue.md
@@ -329,6 +329,23 @@ Data for an imported geometry.
+## Properties
+
+| Property | Type | Description | Required |
+|----------|------|-------------|----------|
+| `type` |enum: `Module`| | No |
+| `value` |[`ModuleId`](/docs/kcl/types/ModuleId)| Any KCL value. | No |
+| `__meta` |`[` [`Metadata`](/docs/kcl/types/Metadata) `]`| | No |
+
+
+----
+
+**Type:** `object`
+
+
+
+
+
## Properties
| Property | Type | Description | Required |
diff --git a/docs/kcl/types/ModuleId.md b/docs/kcl/types/ModuleId.md
new file mode 100644
index 0000000000..9ed25fcfe4
--- /dev/null
+++ b/docs/kcl/types/ModuleId.md
@@ -0,0 +1,16 @@
+---
+title: "ModuleId"
+excerpt: "Identifier of a source file. Uses a u32 to keep the size small."
+layout: manual
+---
+
+Identifier of a source file. Uses a u32 to keep the size small.
+
+**Type:** `integer` (`uint32`)
+
+
+
+
+
+
+
diff --git a/src/lang/queryAst.ts b/src/lang/queryAst.ts
index 1509e843d8..08b5032da2 100644
--- a/src/lang/queryAst.ts
+++ b/src/lang/queryAst.ts
@@ -397,6 +397,7 @@ function moreNodePathFromSourceRange(
}
return path
}
+ return path
}
console.error('not implemented: ' + node.type)
diff --git a/src/lang/wasm.ts b/src/lang/wasm.ts
index 3c2d3f6cfa..3b1ed0de65 100644
--- a/src/lang/wasm.ts
+++ b/src/lang/wasm.ts
@@ -259,7 +259,7 @@ export function emptyExecState(): ExecState {
function execStateFromRaw(raw: RawExecState): ExecState {
return {
- memory: ProgramMemory.fromRaw(raw.memory),
+ memory: ProgramMemory.fromRaw(raw.modLocal.memory),
}
}
diff --git a/src/wasm-lib/derive-docs/src/lib.rs b/src/wasm-lib/derive-docs/src/lib.rs
index ce79611270..5a1d30c237 100644
--- a/src/wasm-lib/derive-docs/src/lib.rs
+++ b/src/wasm-lib/derive-docs/src/lib.rs
@@ -779,6 +779,8 @@ fn rust_type_to_openapi_type(t: &str) -> String {
if t == "f64" {
return "number".to_string();
+ } else if t == "u32" {
+ return "integer".to_string();
} else if t == "str" {
return "string".to_string();
} else {
@@ -813,7 +815,7 @@ fn generate_code_block_test(fn_name: &str, code_block: &str, index: usize) -> pr
context_type: crate::execution::ContextType::Mock,
};
- ctx.run(program.into(), &mut crate::ExecState::default()).await.unwrap();
+ ctx.run(program.into(), &mut crate::ExecState::new()).await.unwrap();
}
#[tokio::test(flavor = "multi_thread", worker_threads = 5)]
diff --git a/src/wasm-lib/derive-docs/tests/args_with_lifetime.gen b/src/wasm-lib/derive-docs/tests/args_with_lifetime.gen
index 33132ca66c..0b93b33a85 100644
--- a/src/wasm-lib/derive-docs/tests/args_with_lifetime.gen
+++ b/src/wasm-lib/derive-docs/tests/args_with_lifetime.gen
@@ -14,7 +14,7 @@ mod test_examples_someFn {
settings: Default::default(),
context_type: crate::execution::ContextType::Mock,
};
- ctx.run(program.into(), &mut crate::ExecState::default())
+ ctx.run(program.into(), &mut crate::ExecState::new())
.await
.unwrap();
}
diff --git a/src/wasm-lib/derive-docs/tests/args_with_refs.gen b/src/wasm-lib/derive-docs/tests/args_with_refs.gen
index 102fe4202b..08b80d4b21 100644
--- a/src/wasm-lib/derive-docs/tests/args_with_refs.gen
+++ b/src/wasm-lib/derive-docs/tests/args_with_refs.gen
@@ -14,7 +14,7 @@ mod test_examples_someFn {
settings: Default::default(),
context_type: crate::execution::ContextType::Mock,
};
- ctx.run(program.into(), &mut crate::ExecState::default())
+ ctx.run(program.into(), &mut crate::ExecState::new())
.await
.unwrap();
}
diff --git a/src/wasm-lib/derive-docs/tests/array.gen b/src/wasm-lib/derive-docs/tests/array.gen
index 7769ef97ab..b4016e3b5f 100644
--- a/src/wasm-lib/derive-docs/tests/array.gen
+++ b/src/wasm-lib/derive-docs/tests/array.gen
@@ -15,7 +15,7 @@ mod test_examples_show {
settings: Default::default(),
context_type: crate::execution::ContextType::Mock,
};
- ctx.run(program.into(), &mut crate::ExecState::default())
+ ctx.run(program.into(), &mut crate::ExecState::new())
.await
.unwrap();
}
@@ -52,7 +52,7 @@ mod test_examples_show {
settings: Default::default(),
context_type: crate::execution::ContextType::Mock,
};
- ctx.run(program.into(), &mut crate::ExecState::default())
+ ctx.run(program.into(), &mut crate::ExecState::new())
.await
.unwrap();
}
diff --git a/src/wasm-lib/derive-docs/tests/box.gen b/src/wasm-lib/derive-docs/tests/box.gen
index 88f22ad596..fc220c90d6 100644
--- a/src/wasm-lib/derive-docs/tests/box.gen
+++ b/src/wasm-lib/derive-docs/tests/box.gen
@@ -15,7 +15,7 @@ mod test_examples_show {
settings: Default::default(),
context_type: crate::execution::ContextType::Mock,
};
- ctx.run(program.into(), &mut crate::ExecState::default())
+ ctx.run(program.into(), &mut crate::ExecState::new())
.await
.unwrap();
}
diff --git a/src/wasm-lib/derive-docs/tests/doc_comment_with_code.gen b/src/wasm-lib/derive-docs/tests/doc_comment_with_code.gen
index a2e12d706d..01292dabd5 100644
--- a/src/wasm-lib/derive-docs/tests/doc_comment_with_code.gen
+++ b/src/wasm-lib/derive-docs/tests/doc_comment_with_code.gen
@@ -16,7 +16,7 @@ mod test_examples_my_func {
settings: Default::default(),
context_type: crate::execution::ContextType::Mock,
};
- ctx.run(program.into(), &mut crate::ExecState::default())
+ ctx.run(program.into(), &mut crate::ExecState::new())
.await
.unwrap();
}
@@ -53,7 +53,7 @@ mod test_examples_my_func {
settings: Default::default(),
context_type: crate::execution::ContextType::Mock,
};
- ctx.run(program.into(), &mut crate::ExecState::default())
+ ctx.run(program.into(), &mut crate::ExecState::new())
.await
.unwrap();
}
diff --git a/src/wasm-lib/derive-docs/tests/lineTo.gen b/src/wasm-lib/derive-docs/tests/lineTo.gen
index c486ebe695..52b909dcad 100644
--- a/src/wasm-lib/derive-docs/tests/lineTo.gen
+++ b/src/wasm-lib/derive-docs/tests/lineTo.gen
@@ -16,7 +16,7 @@ mod test_examples_line_to {
settings: Default::default(),
context_type: crate::execution::ContextType::Mock,
};
- ctx.run(program.into(), &mut crate::ExecState::default())
+ ctx.run(program.into(), &mut crate::ExecState::new())
.await
.unwrap();
}
@@ -53,7 +53,7 @@ mod test_examples_line_to {
settings: Default::default(),
context_type: crate::execution::ContextType::Mock,
};
- ctx.run(program.into(), &mut crate::ExecState::default())
+ ctx.run(program.into(), &mut crate::ExecState::new())
.await
.unwrap();
}
diff --git a/src/wasm-lib/derive-docs/tests/min.gen b/src/wasm-lib/derive-docs/tests/min.gen
index 1f264dd5c2..f42a101295 100644
--- a/src/wasm-lib/derive-docs/tests/min.gen
+++ b/src/wasm-lib/derive-docs/tests/min.gen
@@ -15,7 +15,7 @@ mod test_examples_min {
settings: Default::default(),
context_type: crate::execution::ContextType::Mock,
};
- ctx.run(program.into(), &mut crate::ExecState::default())
+ ctx.run(program.into(), &mut crate::ExecState::new())
.await
.unwrap();
}
@@ -52,7 +52,7 @@ mod test_examples_min {
settings: Default::default(),
context_type: crate::execution::ContextType::Mock,
};
- ctx.run(program.into(), &mut crate::ExecState::default())
+ ctx.run(program.into(), &mut crate::ExecState::new())
.await
.unwrap();
}
diff --git a/src/wasm-lib/derive-docs/tests/option.gen b/src/wasm-lib/derive-docs/tests/option.gen
index 22d5b76f8f..edbec4ca4c 100644
--- a/src/wasm-lib/derive-docs/tests/option.gen
+++ b/src/wasm-lib/derive-docs/tests/option.gen
@@ -15,7 +15,7 @@ mod test_examples_show {
settings: Default::default(),
context_type: crate::execution::ContextType::Mock,
};
- ctx.run(program.into(), &mut crate::ExecState::default())
+ ctx.run(program.into(), &mut crate::ExecState::new())
.await
.unwrap();
}
diff --git a/src/wasm-lib/derive-docs/tests/option_input_format.gen b/src/wasm-lib/derive-docs/tests/option_input_format.gen
index 014bbabc52..26f56a3abc 100644
--- a/src/wasm-lib/derive-docs/tests/option_input_format.gen
+++ b/src/wasm-lib/derive-docs/tests/option_input_format.gen
@@ -15,7 +15,7 @@ mod test_examples_import {
settings: Default::default(),
context_type: crate::execution::ContextType::Mock,
};
- ctx.run(program.into(), &mut crate::ExecState::default())
+ ctx.run(program.into(), &mut crate::ExecState::new())
.await
.unwrap();
}
diff --git a/src/wasm-lib/derive-docs/tests/return_vec_box_sketch.gen b/src/wasm-lib/derive-docs/tests/return_vec_box_sketch.gen
index 41c376e56d..31c5155ff5 100644
--- a/src/wasm-lib/derive-docs/tests/return_vec_box_sketch.gen
+++ b/src/wasm-lib/derive-docs/tests/return_vec_box_sketch.gen
@@ -15,7 +15,7 @@ mod test_examples_import {
settings: Default::default(),
context_type: crate::execution::ContextType::Mock,
};
- ctx.run(program.into(), &mut crate::ExecState::default())
+ ctx.run(program.into(), &mut crate::ExecState::new())
.await
.unwrap();
}
diff --git a/src/wasm-lib/derive-docs/tests/return_vec_sketch.gen b/src/wasm-lib/derive-docs/tests/return_vec_sketch.gen
index 3156e6db92..2f2d87f1c6 100644
--- a/src/wasm-lib/derive-docs/tests/return_vec_sketch.gen
+++ b/src/wasm-lib/derive-docs/tests/return_vec_sketch.gen
@@ -15,7 +15,7 @@ mod test_examples_import {
settings: Default::default(),
context_type: crate::execution::ContextType::Mock,
};
- ctx.run(program.into(), &mut crate::ExecState::default())
+ ctx.run(program.into(), &mut crate::ExecState::new())
.await
.unwrap();
}
diff --git a/src/wasm-lib/derive-docs/tests/show.gen b/src/wasm-lib/derive-docs/tests/show.gen
index a5fde2bc57..8ca23679da 100644
--- a/src/wasm-lib/derive-docs/tests/show.gen
+++ b/src/wasm-lib/derive-docs/tests/show.gen
@@ -15,7 +15,7 @@ mod test_examples_show {
settings: Default::default(),
context_type: crate::execution::ContextType::Mock,
};
- ctx.run(program.into(), &mut crate::ExecState::default())
+ ctx.run(program.into(), &mut crate::ExecState::new())
.await
.unwrap();
}
diff --git a/src/wasm-lib/derive-docs/tests/test_args_with_exec_state.gen b/src/wasm-lib/derive-docs/tests/test_args_with_exec_state.gen
index e9f681ab84..428784f1e9 100644
--- a/src/wasm-lib/derive-docs/tests/test_args_with_exec_state.gen
+++ b/src/wasm-lib/derive-docs/tests/test_args_with_exec_state.gen
@@ -14,7 +14,7 @@ mod test_examples_some_function {
settings: Default::default(),
context_type: crate::execution::ContextType::Mock,
};
- ctx.run(program.into(), &mut crate::ExecState::default())
+ ctx.run(program.into(), &mut crate::ExecState::new())
.await
.unwrap();
}
diff --git a/src/wasm-lib/kcl-test-server/src/lib.rs b/src/wasm-lib/kcl-test-server/src/lib.rs
index dc7c34244d..35de21defc 100644
--- a/src/wasm-lib/kcl-test-server/src/lib.rs
+++ b/src/wasm-lib/kcl-test-server/src/lib.rs
@@ -164,7 +164,7 @@ async fn snapshot_endpoint(body: Bytes, state: ExecutorContext) -> Response
Result {
let ctx = ExecutorContext::new_forwarded_mock(Arc::new(Box::new(
crate::conn_mock_core::EngineConnection::new(ref_result).await?,
)));
- ctx.run(program.into(), &mut ExecState::default()).await?;
+ ctx.run(program.into(), &mut ExecState::new()).await?;
let result = result.lock().expect("mutex lock").clone();
Ok(result)
diff --git a/src/wasm-lib/kcl/src/docs/gen_std_tests.rs b/src/wasm-lib/kcl/src/docs/gen_std_tests.rs
index 2024724e3e..b110293a2d 100644
--- a/src/wasm-lib/kcl/src/docs/gen_std_tests.rs
+++ b/src/wasm-lib/kcl/src/docs/gen_std_tests.rs
@@ -604,24 +604,6 @@ fn clean_function_name(name: &str) -> String {
fn_name
}
-/// Check if a schema is the same as another schema, but don't check the description.
-fn is_same_schema(sa: &schemars::schema::Schema, sb: &schemars::schema::Schema) -> bool {
- let schemars::schema::Schema::Object(a) = sa else {
- return sa == sb;
- };
-
- let schemars::schema::Schema::Object(b) = sb else {
- return sa == sb;
- };
-
- let mut a = a.clone();
- a.metadata = None;
- let mut b = b.clone();
- b.metadata = None;
-
- a == b
-}
-
/// Recursively create references for types we already know about.
fn recurse_and_create_references(
name: &str,
@@ -655,24 +637,6 @@ fn recurse_and_create_references(
return Ok(schemars::schema::Schema::Object(obj));
}
- // Check if this is the type we already know about.
- for (n, s) in types {
- if is_same_schema(schema, s) && name != n && !n.starts_with("[") {
- // Return a reference to the type.
- let sref = schemars::schema::Schema::new_ref(n.to_string());
- // Add the existing metadata to the reference.
- let schemars::schema::Schema::Object(ro) = sref else {
- return Err(anyhow::anyhow!(
- "Failed to get object schema, should have not been a primitive"
- ));
- };
- let mut ro = ro.clone();
- ro.metadata = o.metadata.clone();
-
- return Ok(schemars::schema::Schema::Object(ro));
- }
- }
-
let mut obj = o.clone();
// If we have an object iterate over the properties and recursively create references.
diff --git a/src/wasm-lib/kcl/src/execution/exec_ast.rs b/src/wasm-lib/kcl/src/execution/exec_ast.rs
index e484517104..e9fd2c1445 100644
--- a/src/wasm-lib/kcl/src/execution/exec_ast.rs
+++ b/src/wasm-lib/kcl/src/execution/exec_ast.rs
@@ -29,7 +29,7 @@ impl BinaryPart {
match self {
BinaryPart::Literal(literal) => Ok(literal.into()),
BinaryPart::Identifier(identifier) => {
- let value = exec_state.memory.get(&identifier.name, identifier.into())?;
+ let value = exec_state.memory().get(&identifier.name, identifier.into())?;
Ok(value.clone())
}
BinaryPart::BinaryExpression(binary_expression) => binary_expression.get_result(exec_state, ctx).await,
@@ -47,7 +47,7 @@ impl Node {
let array = match &self.object {
MemberObject::MemberExpression(member_expr) => member_expr.get_result(exec_state)?,
MemberObject::Identifier(identifier) => {
- let value = exec_state.memory.get(&identifier.name, identifier.into())?;
+ let value = exec_state.memory().get(&identifier.name, identifier.into())?;
value.clone()
}
};
@@ -75,7 +75,7 @@ impl Node {
// TODO: Don't use recursion here, use a loop.
MemberObject::MemberExpression(member_expr) => member_expr.get_result(exec_state)?,
MemberObject::Identifier(identifier) => {
- let value = exec_state.memory.get(&identifier.name, identifier.into())?;
+ let value = exec_state.memory().get(&identifier.name, identifier.into())?;
value.clone()
}
};
@@ -310,11 +310,11 @@ pub(crate) async fn execute_pipe_body(
// Now that we've evaluated the first child expression in the pipeline, following child expressions
// should use the previous child expression for %.
// This means there's no more need for the previous pipe_value from the parent AST node above this one.
- let previous_pipe_value = std::mem::replace(&mut exec_state.pipe_value, Some(output));
+ let previous_pipe_value = std::mem::replace(&mut exec_state.mod_local.pipe_value, Some(output));
// Evaluate remaining elements.
let result = inner_execute_pipe_body(exec_state, body, ctx).await;
// Restore the previous pipe value.
- exec_state.pipe_value = previous_pipe_value;
+ exec_state.mod_local.pipe_value = previous_pipe_value;
result
}
@@ -340,10 +340,10 @@ async fn inner_execute_pipe_body(
let output = ctx
.execute_expr(expression, exec_state, &metadata, StatementKind::Expression)
.await?;
- exec_state.pipe_value = Some(output);
+ exec_state.mod_local.pipe_value = Some(output);
}
// Safe to unwrap here, because pipe_value always has something pushed in when the `match first` executes.
- let final_output = exec_state.pipe_value.take().unwrap();
+ let final_output = exec_state.mod_local.pipe_value.take().unwrap();
Ok(final_output)
}
@@ -417,7 +417,7 @@ impl Node {
// before running, and we will likely want to use the
// return value. The call takes ownership of the args,
// so we need to build the op before the call.
- exec_state.operations.push(op);
+ exec_state.mod_local.operations.push(op);
}
result
};
@@ -431,8 +431,8 @@ impl Node {
let source_range = SourceRange::from(self);
// Clone the function so that we can use a mutable reference to
// exec_state.
- let func = exec_state.memory.get(fn_name, source_range)?.clone();
- let fn_dynamic_state = exec_state.dynamic_state.merge(&exec_state.memory);
+ let func = exec_state.memory().get(fn_name, source_range)?.clone();
+ let fn_dynamic_state = exec_state.mod_local.dynamic_state.merge(exec_state.memory());
// Track call operation.
let op_labeled_args = args
@@ -441,16 +441,20 @@ impl Node {
.iter()
.map(|(k, v)| (k.clone(), OpArg::new(v.source_range)))
.collect();
- exec_state.operations.push(Operation::UserDefinedFunctionCall {
- name: Some(fn_name.clone()),
- function_source_range: func.function_def_source_range().unwrap_or_default(),
- unlabeled_arg: args.kw_args.unlabeled.as_ref().map(|arg| OpArg::new(arg.source_range)),
- labeled_args: op_labeled_args,
- source_range: callsite,
- });
+ exec_state
+ .mod_local
+ .operations
+ .push(Operation::UserDefinedFunctionCall {
+ name: Some(fn_name.clone()),
+ function_source_range: func.function_def_source_range().unwrap_or_default(),
+ unlabeled_arg: args.kw_args.unlabeled.as_ref().map(|arg| OpArg::new(arg.source_range)),
+ labeled_args: op_labeled_args,
+ source_range: callsite,
+ });
let return_value = {
- let previous_dynamic_state = std::mem::replace(&mut exec_state.dynamic_state, fn_dynamic_state);
+ let previous_dynamic_state =
+ std::mem::replace(&mut exec_state.mod_local.dynamic_state, fn_dynamic_state);
let result = func
.call_fn_kw(args, exec_state, ctx.clone(), callsite)
.await
@@ -459,7 +463,7 @@ impl Node {
// TODO currently ignored by the frontend
e.add_source_ranges(vec![source_range])
});
- exec_state.dynamic_state = previous_dynamic_state;
+ exec_state.mod_local.dynamic_state = previous_dynamic_state;
result?
};
@@ -476,7 +480,10 @@ impl Node {
})?;
// Track return operation.
- exec_state.operations.push(Operation::UserDefinedFunctionReturn);
+ exec_state
+ .mod_local
+ .operations
+ .push(Operation::UserDefinedFunctionReturn);
Ok(result)
}
@@ -537,7 +544,7 @@ impl Node {
// before running, and we will likely want to use the
// return value. The call takes ownership of the args,
// so we need to build the op before the call.
- exec_state.operations.push(op);
+ exec_state.mod_local.operations.push(op);
}
result
};
@@ -551,27 +558,31 @@ impl Node {
let source_range = SourceRange::from(self);
// Clone the function so that we can use a mutable reference to
// exec_state.
- let func = exec_state.memory.get(fn_name, source_range)?.clone();
- let fn_dynamic_state = exec_state.dynamic_state.merge(&exec_state.memory);
+ let func = exec_state.memory().get(fn_name, source_range)?.clone();
+ let fn_dynamic_state = exec_state.mod_local.dynamic_state.merge(exec_state.memory());
// Track call operation.
- exec_state.operations.push(Operation::UserDefinedFunctionCall {
- name: Some(fn_name.clone()),
- function_source_range: func.function_def_source_range().unwrap_or_default(),
- unlabeled_arg: None,
- // TODO: Add the arguments for legacy positional parameters.
- labeled_args: Default::default(),
- source_range: callsite,
- });
+ exec_state
+ .mod_local
+ .operations
+ .push(Operation::UserDefinedFunctionCall {
+ name: Some(fn_name.clone()),
+ function_source_range: func.function_def_source_range().unwrap_or_default(),
+ unlabeled_arg: None,
+ // TODO: Add the arguments for legacy positional parameters.
+ labeled_args: Default::default(),
+ source_range: callsite,
+ });
let return_value = {
- let previous_dynamic_state = std::mem::replace(&mut exec_state.dynamic_state, fn_dynamic_state);
+ let previous_dynamic_state =
+ std::mem::replace(&mut exec_state.mod_local.dynamic_state, fn_dynamic_state);
let result = func.call_fn(fn_args, exec_state, ctx.clone()).await.map_err(|e| {
// Add the call expression to the source ranges.
// TODO currently ignored by the frontend
e.add_source_ranges(vec![source_range])
});
- exec_state.dynamic_state = previous_dynamic_state;
+ exec_state.mod_local.dynamic_state = previous_dynamic_state;
result?
};
@@ -588,7 +599,10 @@ impl Node {
})?;
// Track return operation.
- exec_state.operations.push(Operation::UserDefinedFunctionReturn);
+ exec_state
+ .mod_local
+ .operations
+ .push(Operation::UserDefinedFunctionReturn);
Ok(result)
}
@@ -604,7 +618,7 @@ fn update_memory_for_tags_of_geometry(result: &mut KclValue, exec_state: &mut Ex
match result {
KclValue::Sketch { value: ref mut sketch } => {
for (_, tag) in sketch.tags.iter() {
- exec_state.memory.update_tag(&tag.value, tag.clone())?;
+ exec_state.mut_memory().update_tag(&tag.value, tag.clone())?;
}
}
KclValue::Solid(ref mut solid) => {
@@ -642,7 +656,7 @@ fn update_memory_for_tags_of_geometry(result: &mut KclValue, exec_state: &mut Ex
info.sketch = solid.id;
t.info = Some(info);
- exec_state.memory.update_tag(&tag.name, t.clone())?;
+ exec_state.mut_memory().update_tag(&tag.name, t.clone())?;
// update the sketch tags.
solid.sketch.tags.insert(tag.name.clone(), t);
@@ -650,11 +664,8 @@ fn update_memory_for_tags_of_geometry(result: &mut KclValue, exec_state: &mut Ex
}
// Find the stale sketch in memory and update it.
- if let Some(current_env) = exec_state
- .memory
- .environments
- .get_mut(exec_state.memory.current_env.index())
- {
+ let cur_env_index = exec_state.memory().current_env.index();
+ if let Some(current_env) = exec_state.mut_memory().environments.get_mut(cur_env_index) {
current_env.update_sketch_tags(&solid.sketch);
}
}
@@ -673,7 +684,9 @@ impl Node {
}],
}));
- exec_state.memory.add(&self.name, memory_item.clone(), self.into())?;
+ exec_state
+ .mut_memory()
+ .add(&self.name, memory_item.clone(), self.into())?;
Ok(self.into())
}
@@ -868,7 +881,7 @@ impl Property {
Ok(Property::String(name.to_string()))
} else {
// Actually evaluate memory to compute the property.
- let prop = exec_state.memory.get(name, property_src)?;
+ let prop = exec_state.memory().get(name, property_src)?;
jvalue_to_prop(prop, property_sr, name)
}
}
diff --git a/src/wasm-lib/kcl/src/execution/kcl_value.rs b/src/wasm-lib/kcl/src/execution/kcl_value.rs
index 7a3d1648c3..756dffb29d 100644
--- a/src/wasm-lib/kcl/src/execution/kcl_value.rs
+++ b/src/wasm-lib/kcl/src/execution/kcl_value.rs
@@ -10,7 +10,7 @@ use crate::{
execution::{Face, ImportedGeometry, MemoryFunction, Metadata, Plane, SketchSet, Solid, SolidSet, TagIdentifier},
parsing::ast::types::{FunctionExpression, KclNone, LiteralValue, TagDeclarator, TagNode},
std::{args::Arg, FnAsArg},
- ExecState, ExecutorContext, KclError, SourceRange,
+ ExecState, ExecutorContext, KclError, ModuleId, SourceRange,
};
pub type KclObjectFields = HashMap;
@@ -84,6 +84,11 @@ pub enum KclValue {
#[serde(rename = "__meta")]
meta: Vec,
},
+ Module {
+ value: ModuleId,
+ #[serde(rename = "__meta")]
+ meta: Vec,
+ },
KclNone {
value: KclNone,
#[serde(rename = "__meta")]
@@ -143,6 +148,7 @@ impl From for Vec {
KclValue::String { meta, .. } => to_vec_sr(&meta),
KclValue::Array { meta, .. } => to_vec_sr(&meta),
KclValue::Object { meta, .. } => to_vec_sr(&meta),
+ KclValue::Module { meta, .. } => to_vec_sr(&meta),
KclValue::Uuid { meta, .. } => to_vec_sr(&meta),
KclValue::KclNone { meta, .. } => to_vec_sr(&meta),
}
@@ -173,6 +179,7 @@ impl From<&KclValue> for Vec {
KclValue::Uuid { meta, .. } => to_vec_sr(meta),
KclValue::Array { meta, .. } => to_vec_sr(meta),
KclValue::Object { meta, .. } => to_vec_sr(meta),
+ KclValue::Module { meta, .. } => to_vec_sr(meta),
KclValue::KclNone { meta, .. } => to_vec_sr(meta),
}
}
@@ -198,6 +205,7 @@ impl KclValue {
KclValue::Solids { value } => value.iter().flat_map(|sketch| &sketch.meta).copied().collect(),
KclValue::ImportedGeometry(x) => x.meta.clone(),
KclValue::Function { meta, .. } => meta.clone(),
+ KclValue::Module { meta, .. } => meta.clone(),
KclValue::KclNone { meta, .. } => meta.clone(),
}
}
@@ -263,6 +271,7 @@ impl KclValue {
KclValue::String { .. } => "string (text)",
KclValue::Array { .. } => "array (list)",
KclValue::Object { .. } => "object",
+ KclValue::Module { .. } => "module",
KclValue::KclNone { .. } => "None",
}
}
diff --git a/src/wasm-lib/kcl/src/execution/mod.rs b/src/wasm-lib/kcl/src/execution/mod.rs
index be8a231b15..b1b3c12b42 100644
--- a/src/wasm-lib/kcl/src/execution/mod.rs
+++ b/src/wasm-lib/kcl/src/execution/mod.rs
@@ -22,6 +22,7 @@ type Point3D = kcmc::shared::Point3d;
pub use function_param::FunctionParam;
pub use kcl_value::{KclObjectFields, KclValue};
+use uuid::Uuid;
pub(crate) mod cache;
mod cad_op;
@@ -35,7 +36,8 @@ use crate::{
execution::cache::{CacheInformation, CacheResult},
fs::{FileManager, FileSystem},
parsing::ast::types::{
- BodyItem, Expr, FunctionExpression, ImportSelector, ItemVisibility, Node, NodeRef, TagDeclarator, TagNode,
+ BodyItem, Expr, FunctionExpression, ImportSelector, ItemVisibility, Node, NodeRef, Program as AstProgram,
+ TagDeclarator, TagNode,
},
settings::types::UnitLength,
source_range::{ModuleId, SourceRange},
@@ -47,14 +49,32 @@ use crate::{
pub use cad_op::Operation;
/// State for executing a program.
-#[derive(Debug, Default, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
+#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[ts(export)]
#[serde(rename_all = "camelCase")]
pub struct ExecState {
- /// Program variable bindings.
- pub memory: ProgramMemory,
+ pub global: GlobalState,
+ pub mod_local: ModuleState,
+}
+
+#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
+#[ts(export)]
+#[serde(rename_all = "camelCase")]
+pub struct GlobalState {
/// The stable artifact ID generator.
pub id_generator: IdGenerator,
+ /// Map from source file absolute path to module ID.
+ pub path_to_source_id: IndexMap,
+ /// Map from module ID to module info.
+ pub module_infos: IndexMap,
+}
+
+#[derive(Debug, Default, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
+#[ts(export)]
+#[serde(rename_all = "camelCase")]
+pub struct ModuleState {
+ /// Program variable bindings.
+ pub memory: ProgramMemory,
/// Dynamic state that follows dynamic flow of the program.
pub dynamic_state: DynamicState,
/// The current value of the pipe operator returned from the previous
@@ -65,29 +85,104 @@ pub struct ExecState {
/// The stack of import statements for detecting circular module imports.
/// If this is empty, we're not currently executing an import statement.
pub import_stack: Vec,
- /// Map from source file absolute path to module ID.
- pub path_to_source_id: IndexMap,
- /// Map from module ID to module info.
- pub module_infos: IndexMap,
/// Operations that have been performed in execution order, for display in
/// the Feature Tree.
pub operations: Vec,
}
+impl Default for ExecState {
+ fn default() -> Self {
+ Self::new()
+ }
+}
+
impl ExecState {
- fn add_module(&mut self, path: std::path::PathBuf) -> ModuleId {
+ pub fn new() -> Self {
+ ExecState {
+ global: GlobalState::new(),
+ mod_local: ModuleState::default(),
+ }
+ }
+
+ fn reset(&mut self) {
+ let mut id_generator = self.global.id_generator.clone();
+ // We do not pop the ids, since we want to keep the same id generator.
+ // This is for the front end to keep track of the ids.
+ id_generator.next_id = 0;
+
+ let mut global = GlobalState::new();
+ global.id_generator = id_generator;
+
+ *self = ExecState {
+ global,
+ mod_local: ModuleState::default(),
+ };
+ }
+
+ pub fn memory(&self) -> &ProgramMemory {
+ &self.mod_local.memory
+ }
+
+ pub fn mut_memory(&mut self) -> &mut ProgramMemory {
+ &mut self.mod_local.memory
+ }
+
+ pub fn next_uuid(&mut self) -> Uuid {
+ self.global.id_generator.next_uuid()
+ }
+
+ async fn add_module(
+ &mut self,
+ path: std::path::PathBuf,
+ ctxt: &ExecutorContext,
+ source_range: SourceRange,
+ ) -> Result {
// Need to avoid borrowing self in the closure.
- let new_module_id = ModuleId::from_usize(self.path_to_source_id.len());
+ let new_module_id = ModuleId::from_usize(self.global.path_to_source_id.len());
let mut is_new = false;
- let id = *self.path_to_source_id.entry(path.clone()).or_insert_with(|| {
+ let id = *self.global.path_to_source_id.entry(path.clone()).or_insert_with(|| {
is_new = true;
new_module_id
});
+
if is_new {
- let module_info = ModuleInfo { id, path };
- self.module_infos.insert(id, module_info);
+ let source = ctxt.fs.read_to_string(&path, source_range).await?;
+ // TODO handle parsing errors properly
+ let parsed = crate::parsing::parse_str(&source, id).parse_errs_as_err()?;
+
+ let module_info = ModuleInfo {
+ id,
+ path,
+ parsed: Some(parsed),
+ };
+ self.global.module_infos.insert(id, module_info);
}
- id
+
+ Ok(id)
+ }
+}
+
+impl GlobalState {
+ fn new() -> Self {
+ let mut global = GlobalState {
+ id_generator: Default::default(),
+ path_to_source_id: Default::default(),
+ module_infos: Default::default(),
+ };
+
+ // TODO(#4434): Use the top-level file's path.
+ let root_path = PathBuf::new();
+ let root_id = ModuleId::default();
+ global.module_infos.insert(
+ root_id,
+ ModuleInfo {
+ id: root_id,
+ path: root_path.clone(),
+ parsed: None,
+ },
+ );
+ global.path_to_source_id.insert(root_path, root_id);
+ global
}
}
@@ -159,6 +254,13 @@ impl ProgramMemory {
}))
}
+ /// Returns all bindings in the current scope.
+ #[allow(dead_code)]
+ fn get_all_cur_scope(&self) -> IndexMap {
+ let env = &self.environments[self.current_env.index()];
+ env.bindings.clone()
+ }
+
/// Find all solids in the memory that are on a specific sketch id.
/// This does not look inside closures. But as long as we do not allow
/// mutation of variables in KCL, closure memory should be a subset of this.
@@ -274,18 +376,14 @@ pub struct DynamicState {
}
impl DynamicState {
- pub fn new() -> Self {
- Self::default()
- }
-
#[must_use]
- pub fn merge(&self, memory: &ProgramMemory) -> Self {
+ fn merge(&self, memory: &ProgramMemory) -> Self {
let mut merged = self.clone();
merged.append(memory);
merged
}
- pub fn append(&mut self, memory: &ProgramMemory) {
+ fn append(&mut self, memory: &ProgramMemory) {
for env in &memory.environments {
for item in env.bindings.values() {
if let KclValue::Solid(eg) = item {
@@ -295,7 +393,7 @@ impl DynamicState {
}
}
- pub fn edge_cut_ids_on_sketch(&self, sketch_id: uuid::Uuid) -> Vec {
+ pub(crate) fn edge_cut_ids_on_sketch(&self, sketch_id: uuid::Uuid) -> Vec {
self.solid_ids
.iter()
.flat_map(|eg| {
@@ -553,7 +651,7 @@ pub struct Plane {
impl Plane {
pub(crate) fn from_plane_data(value: crate::std::sketch::PlaneData, exec_state: &mut ExecState) -> Self {
- let id = exec_state.id_generator.next_uuid();
+ let id = exec_state.global.id_generator.next_uuid();
match value {
crate::std::sketch::PlaneData::XY => Plane {
id,
@@ -1001,13 +1099,14 @@ pub enum BodyType {
/// Info about a module. Right now, this is pretty minimal. We hope to cache
/// modules here in the future.
-#[derive(Debug, Default, Clone, PartialEq, Eq, Deserialize, Serialize, ts_rs::TS, JsonSchema)]
+#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS, JsonSchema)]
#[ts(export)]
pub struct ModuleInfo {
/// The ID of the module.
id: ModuleId,
/// Absolute path of the module's source file.
path: std::path::PathBuf,
+ parsed: Option>,
}
#[derive(Debug, Deserialize, Serialize, PartialEq, Clone, Copy, ts_rs::TS, JsonSchema)]
@@ -1796,7 +1895,7 @@ impl ExecutorContext {
source_range: crate::execution::SourceRange,
) -> Result<(), KclError> {
self.engine
- .clear_scene(&mut exec_state.id_generator, source_range)
+ .clear_scene(&mut exec_state.global.id_generator, source_range)
.await?;
// We do not create the planes here as the post hook in wasm will do that
@@ -1897,23 +1996,13 @@ impl ExecutorContext {
if cache_result.clear_scene && !self.is_mock() {
// Pop the execution state, since we are starting fresh.
- let mut id_generator = exec_state.id_generator.clone();
- // We do not pop the ids, since we want to keep the same id generator.
- // This is for the front end to keep track of the ids.
- id_generator.next_id = 0;
- *exec_state = ExecState {
- id_generator,
- ..Default::default()
- };
+ exec_state.reset();
// We don't do this in mock mode since there is no engine connection
// anyways and from the TS side we override memory and don't want to clear it.
self.reset_scene(exec_state, Default::default()).await?;
}
- // TODO: Use the top-level file's path.
- exec_state.add_module(std::path::PathBuf::from(""));
-
// Re-apply the settings, in case the cache was busted.
self.engine.reapply_settings(&self.settings, Default::default()).await?;
@@ -1937,11 +2026,13 @@ impl ExecutorContext {
match statement {
BodyItem::ImportStatement(import_stmt) => {
let source_range = SourceRange::from(import_stmt);
- let (module_memory, module_exports) =
- self.open_module(&import_stmt.path, exec_state, source_range).await?;
+ let module_id = self.open_module(&import_stmt.path, exec_state, source_range).await?;
match &import_stmt.selector {
ImportSelector::List { items } => {
+ let (_, module_memory, module_exports) = self
+ .exec_module(module_id, exec_state, ExecutionKind::Isolated, source_range)
+ .await?;
for import_item in items {
// Extract the item from the module.
let item =
@@ -1965,18 +2056,24 @@ impl ExecutorContext {
}
// Add the item to the current module.
- exec_state.memory.add(
+ exec_state.mut_memory().add(
import_item.identifier(),
item.clone(),
SourceRange::from(&import_item.name),
)?;
if let ItemVisibility::Export = import_stmt.visibility {
- exec_state.module_exports.push(import_item.identifier().to_owned());
+ exec_state
+ .mod_local
+ .module_exports
+ .push(import_item.identifier().to_owned());
}
}
}
ImportSelector::Glob(_) => {
+ let (_, module_memory, module_exports) = self
+ .exec_module(module_id, exec_state, ExecutionKind::Isolated, source_range)
+ .await?;
for name in module_exports.iter() {
let item = module_memory.get(name, source_range).map_err(|_err| {
KclError::Internal(KclErrorDetails {
@@ -1984,18 +2081,20 @@ impl ExecutorContext {
source_ranges: vec![source_range],
})
})?;
- exec_state.memory.add(name, item.clone(), source_range)?;
+ exec_state.mut_memory().add(name, item.clone(), source_range)?;
if let ItemVisibility::Export = import_stmt.visibility {
- exec_state.module_exports.push(name.clone());
+ exec_state.mod_local.module_exports.push(name.clone());
}
}
}
- ImportSelector::None(_) => {
- return Err(KclError::Semantic(KclErrorDetails {
- message: "Importing whole module is not yet implemented, sorry.".to_owned(),
- source_ranges: vec![source_range],
- }));
+ ImportSelector::None { .. } => {
+ let name = import_stmt.module_name().unwrap();
+ let item = KclValue::Module {
+ value: module_id,
+ meta: vec![source_range.into()],
+ };
+ exec_state.mut_memory().add(&name, item, source_range)?;
}
}
last_expr = None;
@@ -2025,11 +2124,11 @@ impl ExecutorContext {
StatementKind::Declaration { name: &var_name },
)
.await?;
- exec_state.memory.add(&var_name, memory_item, source_range)?;
+ exec_state.mut_memory().add(&var_name, memory_item, source_range)?;
// Track exports.
if let ItemVisibility::Export = variable_declaration.visibility {
- exec_state.module_exports.push(var_name);
+ exec_state.mod_local.module_exports.push(var_name);
}
last_expr = None;
}
@@ -2043,7 +2142,7 @@ impl ExecutorContext {
StatementKind::Expression,
)
.await?;
- exec_state.memory.return_ = Some(value);
+ exec_state.mut_memory().return_ = Some(value);
last_expr = None;
}
}
@@ -2069,18 +2168,19 @@ impl ExecutorContext {
path: &str,
exec_state: &mut ExecState,
source_range: SourceRange,
- ) -> Result<(ProgramMemory, Vec), KclError> {
+ ) -> Result {
let resolved_path = if let Some(project_dir) = &self.settings.project_directory {
project_dir.join(path)
} else {
std::path::PathBuf::from(&path)
};
- if exec_state.import_stack.contains(&resolved_path) {
+ if exec_state.mod_local.import_stack.contains(&resolved_path) {
return Err(KclError::ImportCycle(KclErrorDetails {
message: format!(
"circular import of modules is not allowed: {} -> {}",
exec_state
+ .mod_local
.import_stack
.iter()
.map(|p| p.as_path().to_string_lossy())
@@ -2091,31 +2191,44 @@ impl ExecutorContext {
source_ranges: vec![source_range],
}));
}
- let module_id = exec_state.add_module(resolved_path.clone());
- let source = self.fs.read_to_string(&resolved_path, source_range).await?;
- // TODO handle parsing errors properly
- let program = crate::parsing::parse_str(&source, module_id).parse_errs_as_err()?;
+ exec_state.add_module(resolved_path.clone(), self, source_range).await
+ }
+
+ async fn exec_module(
+ &self,
+ module_id: ModuleId,
+ exec_state: &mut ExecState,
+ exec_kind: ExecutionKind,
+ source_range: SourceRange,
+ ) -> Result<(Option, ProgramMemory, Vec), KclError> {
+ // TODO It sucks that we have to clone the whole module AST here
+ let info = exec_state.global.module_infos[&module_id].clone();
- exec_state.import_stack.push(resolved_path.clone());
- let original_execution = self.engine.replace_execution_kind(ExecutionKind::Isolated);
- let original_memory = std::mem::take(&mut exec_state.memory);
- let original_exports = std::mem::take(&mut exec_state.module_exports);
+ let mut local_state = ModuleState {
+ import_stack: exec_state.mod_local.import_stack.clone(),
+ ..Default::default()
+ };
+ local_state.import_stack.push(info.path.clone());
+ std::mem::swap(&mut exec_state.mod_local, &mut local_state);
+ let original_execution = self.engine.replace_execution_kind(exec_kind);
+
+ // The unwrap here is safe since we only elide the AST for the top module.
let result = self
- .inner_execute(&program, exec_state, crate::execution::BodyType::Root)
+ .inner_execute(&info.parsed.unwrap(), exec_state, crate::execution::BodyType::Root)
.await;
- let module_exports = std::mem::replace(&mut exec_state.module_exports, original_exports);
- let module_memory = std::mem::replace(&mut exec_state.memory, original_memory);
+
+ std::mem::swap(&mut exec_state.mod_local, &mut local_state);
self.engine.replace_execution_kind(original_execution);
- exec_state.import_stack.pop();
- result.map_err(|err| {
+ let result = result.map_err(|err| {
if let KclError::ImportCycle(_) = err {
// It was an import cycle. Keep the original message.
err.override_source_ranges(vec![source_range])
} else {
KclError::Semantic(KclErrorDetails {
message: format!(
- "Error loading imported file. Open it to view more details. {path}: {}",
+ "Error loading imported file. Open it to view more details. {}: {}",
+ info.path.display(),
err.message()
),
source_ranges: vec![source_range],
@@ -2123,7 +2236,7 @@ impl ExecutorContext {
}
})?;
- Ok((module_memory, module_exports))
+ Ok((result, local_state.memory, local_state.module_exports))
}
#[async_recursion]
@@ -2139,8 +2252,23 @@ impl ExecutorContext {
Expr::Literal(literal) => KclValue::from(literal),
Expr::TagDeclarator(tag) => tag.execute(exec_state).await?,
Expr::Identifier(identifier) => {
- let value = exec_state.memory.get(&identifier.name, identifier.into())?;
- value.clone()
+ let value = exec_state.memory().get(&identifier.name, identifier.into())?.clone();
+ if let KclValue::Module { value: module_id, meta } = value {
+ let (result, _, _) = self
+ .exec_module(module_id, exec_state, ExecutionKind::Normal, metadata.source_range)
+ .await?;
+ result.ok_or_else(|| {
+ KclError::Semantic(KclErrorDetails {
+ message: format!(
+ "Evaluating module `{}` as part of an assembly did not produce a result",
+ identifier.name
+ ),
+ source_ranges: vec![metadata.source_range, meta[0].source_range],
+ })
+ })?
+ } else {
+ value
+ }
}
Expr::BinaryExpression(binary_expression) => binary_expression.get_result(exec_state, self).await?,
Expr::FunctionExpression(function_expression) => {
@@ -2151,7 +2279,7 @@ impl ExecutorContext {
expression: function_expression.clone(),
meta: vec![metadata.to_owned()],
func: None,
- memory: Box::new(exec_state.memory.clone()),
+ memory: Box::new(exec_state.memory().clone()),
}
}
Expr::CallExpression(call_expression) => call_expression.execute(exec_state, self).await?,
@@ -2168,7 +2296,7 @@ impl ExecutorContext {
source_ranges: vec![pipe_substitution.into()],
}));
}
- StatementKind::Expression => match exec_state.pipe_value.clone() {
+ StatementKind::Expression => match exec_state.mod_local.pipe_value.clone() {
Some(x) => x,
None => {
return Err(KclError::Semantic(KclErrorDetails {
@@ -2188,7 +2316,9 @@ impl ExecutorContext {
let result = self
.execute_expr(&expr.expr, exec_state, metadata, statement_kind)
.await?;
- exec_state.memory.add(&expr.label.name, result.clone(), init.into())?;
+ exec_state
+ .mut_memory()
+ .add(&expr.label.name, result.clone(), init.into())?;
// TODO this lets us use the label as a variable name, but not as a tag in most cases
result
}
@@ -2373,12 +2503,12 @@ pub(crate) async fn call_user_defined_function(
// Execute the function body using the memory we just created.
let (result, fn_memory) = {
- let previous_memory = std::mem::replace(&mut exec_state.memory, fn_memory);
+ let previous_memory = std::mem::replace(&mut exec_state.mod_local.memory, fn_memory);
let result = ctx
.inner_execute(&function_expression.body, exec_state, BodyType::Block)
.await;
// Restore the previous memory.
- let fn_memory = std::mem::replace(&mut exec_state.memory, previous_memory);
+ let fn_memory = std::mem::replace(&mut exec_state.mod_local.memory, previous_memory);
(result, fn_memory)
};
@@ -2403,12 +2533,12 @@ pub(crate) async fn call_user_defined_function_kw(
// Execute the function body using the memory we just created.
let (result, fn_memory) = {
- let previous_memory = std::mem::replace(&mut exec_state.memory, fn_memory);
+ let previous_memory = std::mem::replace(&mut exec_state.mod_local.memory, fn_memory);
let result = ctx
.inner_execute(&function_expression.body, exec_state, BodyType::Block)
.await;
// Restore the previous memory.
- let fn_memory = std::mem::replace(&mut exec_state.memory, previous_memory);
+ let fn_memory = std::mem::replace(&mut exec_state.mod_local.memory, previous_memory);
(result, fn_memory)
};
@@ -2433,7 +2563,7 @@ mod tests {
OldAstState,
};
- pub async fn parse_execute(code: &str) -> Result<(Program, ExecutorContext, ExecState)> {
+ async fn parse_execute(code: &str) -> Result<(Program, ExecutorContext, ExecState)> {
let program = Program::parse_no_errs(code)?;
let ctx = ExecutorContext {
@@ -2450,6 +2580,7 @@ mod tests {
}
/// Convenience function to get a JSON value from memory and unwrap.
+ #[track_caller]
fn mem_get_json(memory: &ProgramMemory, name: &str) -> KclValue {
memory.get(name, SourceRange::default()).unwrap().to_owned()
}
@@ -2880,21 +3011,21 @@ let shape = layer() |> patternTransform(10, transform, %)
async fn test_math_execute_with_functions() {
let ast = r#"const myVar = 2 + min(100, -1 + legLen(5, 3))"#;
let (_, _, exec_state) = parse_execute(ast).await.unwrap();
- assert_eq!(5.0, mem_get_json(&exec_state.memory, "myVar").as_f64().unwrap());
+ assert_eq!(5.0, mem_get_json(exec_state.memory(), "myVar").as_f64().unwrap());
}
#[tokio::test(flavor = "multi_thread")]
async fn test_math_execute() {
let ast = r#"const myVar = 1 + 2 * (3 - 4) / -5 + 6"#;
let (_, _, exec_state) = parse_execute(ast).await.unwrap();
- assert_eq!(7.4, mem_get_json(&exec_state.memory, "myVar").as_f64().unwrap());
+ assert_eq!(7.4, mem_get_json(exec_state.memory(), "myVar").as_f64().unwrap());
}
#[tokio::test(flavor = "multi_thread")]
async fn test_math_execute_start_negative() {
let ast = r#"const myVar = -5 + 6"#;
let (_, _, exec_state) = parse_execute(ast).await.unwrap();
- assert_eq!(1.0, mem_get_json(&exec_state.memory, "myVar").as_f64().unwrap());
+ assert_eq!(1.0, mem_get_json(exec_state.memory(), "myVar").as_f64().unwrap());
}
#[tokio::test(flavor = "multi_thread")]
@@ -2903,7 +3034,7 @@ let shape = layer() |> patternTransform(10, transform, %)
let (_, _, exec_state) = parse_execute(ast).await.unwrap();
assert_eq!(
std::f64::consts::TAU,
- mem_get_json(&exec_state.memory, "myVar").as_f64().unwrap()
+ mem_get_json(exec_state.memory(), "myVar").as_f64().unwrap()
);
}
@@ -2911,7 +3042,7 @@ let shape = layer() |> patternTransform(10, transform, %)
async fn test_math_define_decimal_without_leading_zero() {
let ast = r#"let thing = .4 + 7"#;
let (_, _, exec_state) = parse_execute(ast).await.unwrap();
- assert_eq!(7.4, mem_get_json(&exec_state.memory, "thing").as_f64().unwrap());
+ assert_eq!(7.4, mem_get_json(exec_state.memory(), "thing").as_f64().unwrap());
}
#[tokio::test(flavor = "multi_thread")]
@@ -2951,10 +3082,10 @@ fn check = (x) => {
check(false)
"#;
let (_, _, exec_state) = parse_execute(ast).await.unwrap();
- assert_eq!(false, mem_get_json(&exec_state.memory, "notTrue").as_bool().unwrap());
- assert_eq!(true, mem_get_json(&exec_state.memory, "notFalse").as_bool().unwrap());
- assert_eq!(true, mem_get_json(&exec_state.memory, "c").as_bool().unwrap());
- assert_eq!(false, mem_get_json(&exec_state.memory, "d").as_bool().unwrap());
+ assert_eq!(false, mem_get_json(exec_state.memory(), "notTrue").as_bool().unwrap());
+ assert_eq!(true, mem_get_json(exec_state.memory(), "notFalse").as_bool().unwrap());
+ assert_eq!(true, mem_get_json(exec_state.memory(), "c").as_bool().unwrap());
+ assert_eq!(false, mem_get_json(exec_state.memory(), "d").as_bool().unwrap());
}
#[tokio::test(flavor = "multi_thread")]
@@ -3635,4 +3766,65 @@ shell({ faces = ['end'], thickness = 0.25 }, firstSketch)"#;
assert_eq!(result, None);
}
+
+ #[tokio::test(flavor = "multi_thread")]
+ async fn kcl_test_ids_stable_between_executions() {
+ let code = r#"sketch001 = startSketchOn('XZ')
+|> startProfileAt([61.74, 206.13], %)
+|> xLine(305.11, %, $seg01)
+|> yLine(-291.85, %)
+|> xLine(-segLen(seg01), %)
+|> lineTo([profileStartX(%), profileStartY(%)], %)
+|> close(%)
+|> extrude(40.14, %)
+|> shell({
+ faces: [seg01],
+ thickness: 3.14,
+}, %)
+"#;
+
+ let ctx = crate::test_server::new_context(UnitLength::Mm, true, None)
+ .await
+ .unwrap();
+ let old_program = crate::Program::parse_no_errs(code).unwrap();
+ // Execute the program.
+ let mut exec_state = Default::default();
+ let cache_info = crate::CacheInformation {
+ old: None,
+ new_ast: old_program.ast.clone(),
+ };
+ ctx.run(cache_info, &mut exec_state).await.unwrap();
+
+ // Get the id_generator from the first execution.
+ let id_generator = exec_state.global.id_generator.clone();
+
+ let code = r#"sketch001 = startSketchOn('XZ')
+|> startProfileAt([62.74, 206.13], %)
+|> xLine(305.11, %, $seg01)
+|> yLine(-291.85, %)
+|> xLine(-segLen(seg01), %)
+|> lineTo([profileStartX(%), profileStartY(%)], %)
+|> close(%)
+|> extrude(40.14, %)
+|> shell({
+ faces: [seg01],
+ thickness: 3.14,
+}, %)
+"#;
+
+ // Execute a slightly different program again.
+ let program: Program = crate::Program::parse_no_errs(code).unwrap();
+ let cache_info = crate::CacheInformation {
+ old: Some(crate::OldAstState {
+ ast: old_program.ast.clone(),
+ exec_state: exec_state.clone(),
+ settings: ctx.settings.clone(),
+ }),
+ new_ast: program.ast.clone(),
+ };
+ // Execute the program.
+ ctx.run(cache_info, &mut exec_state).await.unwrap();
+
+ assert_eq!(id_generator, exec_state.global.id_generator);
+ }
}
diff --git a/src/wasm-lib/kcl/src/lsp/kcl/mod.rs b/src/wasm-lib/kcl/src/lsp/kcl/mod.rs
index cbdd2f3fd9..a22447b0a9 100644
--- a/src/wasm-lib/kcl/src/lsp/kcl/mod.rs
+++ b/src/wasm-lib/kcl/src/lsp/kcl/mod.rs
@@ -726,11 +726,11 @@ impl Backend {
drop(last_successful_ast_state);
self.memory_map
- .insert(params.uri.to_string(), exec_state.memory.clone());
+ .insert(params.uri.to_string(), exec_state.memory().clone());
// Send the notification to the client that the memory was updated.
self.client
- .send_notification::(exec_state.memory)
+ .send_notification::(exec_state.mod_local.memory)
.await;
Ok(())
diff --git a/src/wasm-lib/kcl/src/lsp/tests.rs b/src/wasm-lib/kcl/src/lsp/tests.rs
index 81dd275bf7..9a242f046d 100644
--- a/src/wasm-lib/kcl/src/lsp/tests.rs
+++ b/src/wasm-lib/kcl/src/lsp/tests.rs
@@ -2344,6 +2344,7 @@ async fn kcl_test_kcl_lsp_diagnostics_on_execution_error() {
.await;
// Get the diagnostics.
+ // TODO warnings being stomped by execution errors?
assert_diagnostic_count(server.diagnostics_map.get("file:///test.kcl").as_deref(), 1);
// Update the text.
diff --git a/src/wasm-lib/kcl/src/parsing/ast/digest.rs b/src/wasm-lib/kcl/src/parsing/ast/digest.rs
index 463fc0b978..2943c98186 100644
--- a/src/wasm-lib/kcl/src/parsing/ast/digest.rs
+++ b/src/wasm-lib/kcl/src/parsing/ast/digest.rs
@@ -59,8 +59,8 @@ impl ImportStatement {
}
}
ImportSelector::Glob(_) => hasher.update(b"ImportSelector::Glob"),
- ImportSelector::None(None) => hasher.update(b"ImportSelector::None"),
- ImportSelector::None(Some(alias)) => {
+ ImportSelector::None { alias: None } => hasher.update(b"ImportSelector::None"),
+ ImportSelector::None { alias: Some(alias) } => {
hasher.update(b"ImportSelector::None");
hasher.update(alias.compute_digest());
}
diff --git a/src/wasm-lib/kcl/src/parsing/ast/types/mod.rs b/src/wasm-lib/kcl/src/parsing/ast/types/mod.rs
index 99af323315..1a7ef8bcb5 100644
--- a/src/wasm-lib/kcl/src/parsing/ast/types/mod.rs
+++ b/src/wasm-lib/kcl/src/parsing/ast/types/mod.rs
@@ -1225,7 +1225,7 @@ pub enum ImportSelector {
Glob(Node<()>),
/// Import the module itself (the param is an optional alias).
/// E.g., `import "foo.kcl" as bar`
- None(Option>),
+ None { alias: Option> },
}
impl ImportSelector {
@@ -1244,8 +1244,8 @@ impl ImportSelector {
None
}
ImportSelector::Glob(_) => None,
- ImportSelector::None(None) => None,
- ImportSelector::None(Some(alias)) => {
+ ImportSelector::None { alias: None } => None,
+ ImportSelector::None { alias: Some(alias) } => {
let alias_source_range = SourceRange::from(&*alias);
if !alias_source_range.contains(pos) {
return None;
@@ -1264,8 +1264,8 @@ impl ImportSelector {
}
}
ImportSelector::Glob(_) => {}
- ImportSelector::None(None) => {}
- ImportSelector::None(Some(alias)) => alias.rename(old_name, new_name),
+ ImportSelector::None { alias: None } => {}
+ ImportSelector::None { alias: Some(alias) } => alias.rename(old_name, new_name),
}
}
}
@@ -1296,7 +1296,7 @@ impl Node {
false
}
ImportSelector::Glob(_) => false,
- ImportSelector::None(_) => name == self.module_name().unwrap(),
+ ImportSelector::None { .. } => name == self.module_name().unwrap(),
}
}
@@ -1304,7 +1304,7 @@ impl Node {
/// Validated during parsing and guaranteed to return `Some` if the statement imports
/// the module itself (i.e., self.selector is ImportSelector::None).
pub fn module_name(&self) -> Option {
- if let ImportSelector::None(Some(alias)) = &self.selector {
+ if let ImportSelector::None { alias: Some(alias) } = &self.selector {
return Some(alias.name.clone());
}
diff --git a/src/wasm-lib/kcl/src/parsing/parser.rs b/src/wasm-lib/kcl/src/parsing/parser.rs
index 26ec22767b..587542f7ab 100644
--- a/src/wasm-lib/kcl/src/parsing/parser.rs
+++ b/src/wasm-lib/kcl/src/parsing/parser.rs
@@ -1444,7 +1444,7 @@ fn import_stmt(i: &mut TokenSlice) -> PResult> {
require_whitespace(i)?;
let (mut selector, path) = alt((
- string_literal.map(|s| (ImportSelector::None(None), Some(s))),
+ string_literal.map(|s| (ImportSelector::None { alias: None }, Some(s))),
glob.map(|t| {
let s = t.as_source_range();
(
@@ -1507,7 +1507,7 @@ fn import_stmt(i: &mut TokenSlice) -> PResult> {
));
}
- if let ImportSelector::None(ref mut a) = selector {
+ if let ImportSelector::None { alias: ref mut a } = selector {
if let Some(alias) = opt(preceded(
(whitespace, import_as_keyword, whitespace),
identifier.context(expected("an identifier to alias the import")),
diff --git a/src/wasm-lib/kcl/src/parsing/token/tokeniser.rs b/src/wasm-lib/kcl/src/parsing/token/tokeniser.rs
index 074514f574..6eb73f11ac 100644
--- a/src/wasm-lib/kcl/src/parsing/token/tokeniser.rs
+++ b/src/wasm-lib/kcl/src/parsing/token/tokeniser.rs
@@ -366,6 +366,7 @@ mod tests {
use super::*;
use crate::parsing::token::TokenSlice;
+
fn assert_parse_err<'i, P, O, E>(mut p: P, s: &'i str)
where
O: std::fmt::Debug,
diff --git a/src/wasm-lib/kcl/src/simulation_tests.rs b/src/wasm-lib/kcl/src/simulation_tests.rs
index c6bf7a707d..b9099607ca 100644
--- a/src/wasm-lib/kcl/src/simulation_tests.rs
+++ b/src/wasm-lib/kcl/src/simulation_tests.rs
@@ -127,7 +127,7 @@ async fn execute(test_name: &str, render_to_png: bool) {
});
assert_snapshot(test_name, "Operations executed", || {
- insta::assert_json_snapshot!("ops", e.exec_state.operations);
+ insta::assert_json_snapshot!("ops", e.exec_state.mod_local.operations);
});
}
e => {
@@ -711,6 +711,27 @@ mod import_glob {
super::execute(TEST_NAME, false).await
}
}
+mod import_whole {
+ const TEST_NAME: &str = "import_whole";
+
+ /// Test parsing KCL.
+ #[test]
+ fn parse() {
+ super::parse(TEST_NAME)
+ }
+
+ /// Test that parsing and unparsing KCL produces the original KCL input.
+ #[test]
+ fn unparse() {
+ super::unparse(TEST_NAME)
+ }
+
+ /// Test that KCL is executed correctly.
+ #[tokio::test(flavor = "multi_thread")]
+ async fn kcl_test_execute() {
+ super::execute(TEST_NAME, false).await
+ }
+}
mod import_side_effect {
const TEST_NAME: &str = "import_side_effect";
diff --git a/src/wasm-lib/kcl/src/std/args.rs b/src/wasm-lib/kcl/src/std/args.rs
index f8a48349ea..0c5c432f87 100644
--- a/src/wasm-lib/kcl/src/std/args.rs
+++ b/src/wasm-lib/kcl/src/std/args.rs
@@ -185,7 +185,7 @@ impl Args {
exec_state: &'e mut ExecState,
tag: &'a TagIdentifier,
) -> Result<&'e crate::execution::TagEngineInfo, KclError> {
- if let KclValue::TagIdentifier(t) = exec_state.memory.get(&tag.value, self.source_range)? {
+ if let KclValue::TagIdentifier(t) = exec_state.memory().get(&tag.value, self.source_range)? {
Ok(t.info.as_ref().ok_or_else(|| {
KclError::Type(KclErrorDetails {
message: format!("Tag `{}` does not have engine info", tag.value),
@@ -251,12 +251,12 @@ impl Args {
// Find all the solids on the same shared sketch.
ids.extend(
exec_state
- .memory
+ .memory()
.find_solids_on_sketch(solid.sketch.id)
.iter()
.flat_map(|eg| eg.get_all_edge_cut_ids()),
);
- ids.extend(exec_state.dynamic_state.edge_cut_ids_on_sketch(sketch_id));
+ ids.extend(exec_state.mod_local.dynamic_state.edge_cut_ids_on_sketch(sketch_id));
traversed_sketches.push(sketch_id);
}
diff --git a/src/wasm-lib/kcl/src/std/chamfer.rs b/src/wasm-lib/kcl/src/std/chamfer.rs
index bc69587870..9c4d6c864f 100644
--- a/src/wasm-lib/kcl/src/std/chamfer.rs
+++ b/src/wasm-lib/kcl/src/std/chamfer.rs
@@ -134,7 +134,7 @@ async fn inner_chamfer(
EdgeReference::Tag(edge_tag) => args.get_tag_engine_info(exec_state, &edge_tag)?.id,
};
- let id = exec_state.id_generator.next_uuid();
+ let id = exec_state.global.id_generator.next_uuid();
args.batch_end_cmd(
id,
ModelingCmd::from(mcmd::Solid3dFilletEdge {
diff --git a/src/wasm-lib/kcl/src/std/extrude.rs b/src/wasm-lib/kcl/src/std/extrude.rs
index d28fea9029..e8a672d125 100644
--- a/src/wasm-lib/kcl/src/std/extrude.rs
+++ b/src/wasm-lib/kcl/src/std/extrude.rs
@@ -84,7 +84,7 @@ async fn inner_extrude(
exec_state: &mut ExecState,
args: Args,
) -> Result {
- let id = exec_state.id_generator.next_uuid();
+ let id = exec_state.next_uuid();
// Extrude the element(s).
let sketches: Vec = sketch_set.into();
@@ -93,7 +93,7 @@ async fn inner_extrude(
// Before we extrude, we need to enable the sketch mode.
// We do this here in case extrude is called out of order.
args.batch_modeling_cmd(
- exec_state.id_generator.next_uuid(),
+ exec_state.next_uuid(),
ModelingCmd::from(mcmd::EnableSketchMode {
animated: false,
ortho: false,
@@ -121,7 +121,7 @@ async fn inner_extrude(
// Disable the sketch mode.
args.batch_modeling_cmd(
- exec_state.id_generator.next_uuid(),
+ exec_state.next_uuid(),
ModelingCmd::SketchModeDisable(mcmd::SketchModeDisable {}),
)
.await?;
@@ -140,7 +140,7 @@ pub(crate) async fn do_post_extrude(
// Bring the object to the front of the scene.
// See: https://github.com/KittyCAD/modeling-app/issues/806
args.batch_modeling_cmd(
- exec_state.id_generator.next_uuid(),
+ exec_state.next_uuid(),
ModelingCmd::from(mcmd::ObjectBringToFront { object_id: sketch.id }),
)
.await?;
@@ -163,7 +163,7 @@ pub(crate) async fn do_post_extrude(
let solid3d_info = args
.send_modeling_cmd(
- exec_state.id_generator.next_uuid(),
+ exec_state.next_uuid(),
ModelingCmd::from(mcmd::Solid3dGetExtrusionFaceInfo {
edge_id: any_edge_id,
object_id: sketch.id,
@@ -196,7 +196,7 @@ pub(crate) async fn do_post_extrude(
// Instead, the Typescript codebases (which handles WebSocket sends when compiled via Wasm)
// uses this to build the artifact graph, which the UI needs.
args.batch_modeling_cmd(
- exec_state.id_generator.next_uuid(),
+ exec_state.next_uuid(),
ModelingCmd::from(mcmd::Solid3dGetOppositeEdge {
edge_id: curve_id,
object_id: sketch.id,
@@ -206,7 +206,7 @@ pub(crate) async fn do_post_extrude(
.await?;
args.batch_modeling_cmd(
- exec_state.id_generator.next_uuid(),
+ exec_state.next_uuid(),
ModelingCmd::from(mcmd::Solid3dGetNextAdjacentEdge {
edge_id: curve_id,
object_id: sketch.id,
@@ -259,7 +259,7 @@ pub(crate) async fn do_post_extrude(
let extrude_surface = ExtrudeSurface::ExtrudePlane(crate::execution::ExtrudePlane {
// pushing this values with a fake face_id to make extrudes mock-execute safe
- face_id: exec_state.id_generator.next_uuid(),
+ face_id: exec_state.next_uuid(),
tag: path.get_base().tag.clone(),
geo_meta: GeoMeta {
id: path.get_base().geo_meta.id,
@@ -305,8 +305,8 @@ fn analyze_faces(exec_state: &mut ExecState, args: &Args, face_infos: Vec Result
}]
async fn inner_get_opposite_edge(tag: TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result {
if args.ctx.is_mock() {
- return Ok(exec_state.id_generator.next_uuid());
+ return Ok(exec_state.next_uuid());
}
let face_id = args.get_adjacent_face_to_tag(exec_state, &tag, false).await?;
- let id = exec_state.id_generator.next_uuid();
+ let id = exec_state.next_uuid();
let tagged_path = args.get_tag_engine_info(exec_state, &tag)?;
let resp = args
@@ -302,11 +302,11 @@ async fn inner_get_next_adjacent_edge(
args: Args,
) -> Result {
if args.ctx.is_mock() {
- return Ok(exec_state.id_generator.next_uuid());
+ return Ok(exec_state.next_uuid());
}
let face_id = args.get_adjacent_face_to_tag(exec_state, &tag, false).await?;
- let id = exec_state.id_generator.next_uuid();
+ let id = exec_state.next_uuid();
let tagged_path = args.get_tag_engine_info(exec_state, &tag)?;
let resp = args
@@ -387,11 +387,11 @@ async fn inner_get_previous_adjacent_edge(
args: Args,
) -> Result {
if args.ctx.is_mock() {
- return Ok(exec_state.id_generator.next_uuid());
+ return Ok(exec_state.next_uuid());
}
let face_id = args.get_adjacent_face_to_tag(exec_state, &tag, false).await?;
- let id = exec_state.id_generator.next_uuid();
+ let id = exec_state.next_uuid();
let tagged_path = args.get_tag_engine_info(exec_state, &tag)?;
let resp = args
diff --git a/src/wasm-lib/kcl/src/std/helix.rs b/src/wasm-lib/kcl/src/std/helix.rs
index 62c5cf7161..e4834e0799 100644
--- a/src/wasm-lib/kcl/src/std/helix.rs
+++ b/src/wasm-lib/kcl/src/std/helix.rs
@@ -61,7 +61,7 @@ async fn inner_helix(
exec_state: &mut ExecState,
args: Args,
) -> Result, KclError> {
- let id = exec_state.id_generator.next_uuid();
+ let id = exec_state.next_uuid();
args.batch_modeling_cmd(
id,
ModelingCmd::from(mcmd::EntityMakeHelix {
diff --git a/src/wasm-lib/kcl/src/std/import.rs b/src/wasm-lib/kcl/src/std/import.rs
index eb535defeb..89ad712a20 100644
--- a/src/wasm-lib/kcl/src/std/import.rs
+++ b/src/wasm-lib/kcl/src/std/import.rs
@@ -300,13 +300,13 @@ async fn inner_import(
if args.ctx.is_mock() {
return Ok(ImportedGeometry {
- id: exec_state.id_generator.next_uuid(),
+ id: exec_state.next_uuid(),
value: import_files.iter().map(|f| f.path.to_string()).collect(),
meta: vec![args.source_range.into()],
});
}
- let id = exec_state.id_generator.next_uuid();
+ let id = exec_state.next_uuid();
let resp = args
.send_modeling_cmd(
id,
diff --git a/src/wasm-lib/kcl/src/std/loft.rs b/src/wasm-lib/kcl/src/std/loft.rs
index 57606460fe..a43bbba0b4 100644
--- a/src/wasm-lib/kcl/src/std/loft.rs
+++ b/src/wasm-lib/kcl/src/std/loft.rs
@@ -142,7 +142,7 @@ async fn inner_loft(
}));
}
- let id = exec_state.id_generator.next_uuid();
+ let id = exec_state.next_uuid();
args.batch_modeling_cmd(
id,
ModelingCmd::from(mcmd::Loft {
diff --git a/src/wasm-lib/kcl/src/std/mirror.rs b/src/wasm-lib/kcl/src/std/mirror.rs
index 6c611dacc2..3882e611b6 100644
--- a/src/wasm-lib/kcl/src/std/mirror.rs
+++ b/src/wasm-lib/kcl/src/std/mirror.rs
@@ -121,7 +121,7 @@ async fn inner_mirror_2d(
let (axis, origin) = axis.axis_and_origin()?;
args.batch_modeling_cmd(
- exec_state.id_generator.next_uuid(),
+ exec_state.next_uuid(),
ModelingCmd::from(mcmd::EntityMirror {
ids: starting_sketches.iter().map(|sketch| sketch.id).collect(),
axis,
@@ -134,7 +134,7 @@ async fn inner_mirror_2d(
let edge_id = edge.get_engine_id(exec_state, &args)?;
args.batch_modeling_cmd(
- exec_state.id_generator.next_uuid(),
+ exec_state.next_uuid(),
ModelingCmd::from(mcmd::EntityMirrorAcrossEdge {
ids: starting_sketches.iter().map(|sketch| sketch.id).collect(),
edge_id,
diff --git a/src/wasm-lib/kcl/src/std/patterns.rs b/src/wasm-lib/kcl/src/std/patterns.rs
index c2cf56dd47..8833c354fc 100644
--- a/src/wasm-lib/kcl/src/std/patterns.rs
+++ b/src/wasm-lib/kcl/src/std/patterns.rs
@@ -379,7 +379,7 @@ async fn send_pattern_transform(
exec_state: &mut ExecState,
args: &Args,
) -> Result, KclError> {
- let id = exec_state.id_generator.next_uuid();
+ let id = exec_state.next_uuid();
let resp = args
.send_modeling_cmd(
@@ -1032,7 +1032,7 @@ async fn pattern_circular(
exec_state: &mut ExecState,
args: Args,
) -> Result {
- let id = exec_state.id_generator.next_uuid();
+ let id = exec_state.next_uuid();
let num_repetitions = match data.repetitions() {
RepetitionsNeeded::More(n) => n,
RepetitionsNeeded::None => {
diff --git a/src/wasm-lib/kcl/src/std/planes.rs b/src/wasm-lib/kcl/src/std/planes.rs
index 282f04ef7b..bc6c35e51b 100644
--- a/src/wasm-lib/kcl/src/std/planes.rs
+++ b/src/wasm-lib/kcl/src/std/planes.rs
@@ -209,7 +209,7 @@ async fn make_offset_plane_in_engine(plane: &Plane, exec_state: &mut ExecState,
// Set the color.
args.batch_modeling_cmd(
- exec_state.id_generator.next_uuid(),
+ exec_state.next_uuid(),
ModelingCmd::from(mcmd::PlaneSetColor {
color,
plane_id: plane.id,
diff --git a/src/wasm-lib/kcl/src/std/revolve.rs b/src/wasm-lib/kcl/src/std/revolve.rs
index db7eca9069..e617153e79 100644
--- a/src/wasm-lib/kcl/src/std/revolve.rs
+++ b/src/wasm-lib/kcl/src/std/revolve.rs
@@ -264,7 +264,7 @@ async fn inner_revolve(
let angle = Angle::from_degrees(data.angle.unwrap_or(360.0));
- let id = exec_state.id_generator.next_uuid();
+ let id = exec_state.next_uuid();
match data.axis {
AxisOrEdgeReference::Axis(axis) => {
let (axis, origin) = axis.axis_and_origin()?;
diff --git a/src/wasm-lib/kcl/src/std/shapes.rs b/src/wasm-lib/kcl/src/std/shapes.rs
index 2651cecca1..1aca88cbef 100644
--- a/src/wasm-lib/kcl/src/std/shapes.rs
+++ b/src/wasm-lib/kcl/src/std/shapes.rs
@@ -100,7 +100,7 @@ async fn inner_circle(
let angle_start = Angle::zero();
let angle_end = Angle::turn();
- let id = exec_state.id_generator.next_uuid();
+ let id = exec_state.next_uuid();
args.batch_modeling_cmd(
id,
@@ -269,7 +269,7 @@ async fn inner_polygon(
// Draw all the lines with unique IDs and modified tags
for vertex in vertices.iter().skip(1) {
let from = sketch.current_pen_position()?;
- let id = exec_state.id_generator.next_uuid();
+ let id = exec_state.next_uuid();
args.batch_modeling_cmd(
id,
@@ -304,7 +304,7 @@ async fn inner_polygon(
// Close the polygon by connecting back to the first vertex with a new ID
let from = sketch.current_pen_position()?;
- let close_id = exec_state.id_generator.next_uuid();
+ let close_id = exec_state.next_uuid();
args.batch_modeling_cmd(
close_id,
@@ -337,7 +337,7 @@ async fn inner_polygon(
sketch.paths.push(current_path);
args.batch_modeling_cmd(
- exec_state.id_generator.next_uuid(),
+ exec_state.next_uuid(),
ModelingCmd::from(mcmd::ClosePath { path_id: sketch.id }),
)
.await?;
diff --git a/src/wasm-lib/kcl/src/std/shell.rs b/src/wasm-lib/kcl/src/std/shell.rs
index a5acb8f382..68762ed432 100644
--- a/src/wasm-lib/kcl/src/std/shell.rs
+++ b/src/wasm-lib/kcl/src/std/shell.rs
@@ -230,7 +230,7 @@ async fn inner_shell(
}
args.batch_modeling_cmd(
- exec_state.id_generator.next_uuid(),
+ exec_state.next_uuid(),
ModelingCmd::from(mcmd::Solid3dShellFace {
hollow: false,
face_ids,
@@ -316,7 +316,7 @@ async fn inner_hollow(
args.flush_batch_for_solid_set(exec_state, solid.clone().into()).await?;
args.batch_modeling_cmd(
- exec_state.id_generator.next_uuid(),
+ exec_state.next_uuid(),
ModelingCmd::from(mcmd::Solid3dShellFace {
hollow: true,
face_ids: Vec::new(), // This is empty because we want to hollow the entire object.
diff --git a/src/wasm-lib/kcl/src/std/sketch.rs b/src/wasm-lib/kcl/src/std/sketch.rs
index 5060eabf8b..70617263b6 100644
--- a/src/wasm-lib/kcl/src/std/sketch.rs
+++ b/src/wasm-lib/kcl/src/std/sketch.rs
@@ -124,7 +124,7 @@ async fn inner_line_to(
args: Args,
) -> Result {
let from = sketch.current_pen_position()?;
- let id = exec_state.id_generator.next_uuid();
+ let id = exec_state.next_uuid();
args.batch_modeling_cmd(
id,
@@ -299,7 +299,7 @@ async fn inner_line(
let from = sketch.current_pen_position()?;
let to = [from.x + delta[0], from.y + delta[1]];
- let id = exec_state.id_generator.next_uuid();
+ let id = exec_state.next_uuid();
args.batch_modeling_cmd(
id,
@@ -488,7 +488,7 @@ async fn inner_angled_line(
let to: [f64; 2] = [from.x + delta[0], from.y + delta[1]];
- let id = exec_state.id_generator.next_uuid();
+ let id = exec_state.next_uuid();
args.batch_modeling_cmd(
id,
@@ -1230,7 +1230,7 @@ pub(crate) async fn inner_start_profile_at(
// Hide whatever plane we are sketching on.
// This is especially helpful for offset planes, which would be visible otherwise.
args.batch_end_cmd(
- exec_state.id_generator.next_uuid(),
+ exec_state.next_uuid(),
ModelingCmd::from(mcmd::ObjectVisible {
object_id: plane.id,
hidden: true,
@@ -1243,7 +1243,7 @@ pub(crate) async fn inner_start_profile_at(
// Enter sketch mode on the surface.
// We call this here so you can reuse the sketch surface for multiple sketches.
- let id = exec_state.id_generator.next_uuid();
+ let id = exec_state.next_uuid();
args.batch_modeling_cmd(
id,
ModelingCmd::from(mcmd::EnableSketchMode {
@@ -1261,8 +1261,8 @@ pub(crate) async fn inner_start_profile_at(
)
.await?;
- let id = exec_state.id_generator.next_uuid();
- let path_id = exec_state.id_generator.next_uuid();
+ let id = exec_state.next_uuid();
+ let path_id = exec_state.next_uuid();
args.batch_modeling_cmd(path_id, ModelingCmd::from(mcmd::StartPath {}))
.await?;
@@ -1427,7 +1427,7 @@ pub(crate) async fn inner_close(
let from = sketch.current_pen_position()?;
let to: Point2d = sketch.start.from.into();
- let id = exec_state.id_generator.next_uuid();
+ let id = exec_state.next_uuid();
args.batch_modeling_cmd(id, ModelingCmd::from(mcmd::ClosePath { path_id: sketch.id }))
.await?;
@@ -1436,7 +1436,7 @@ pub(crate) async fn inner_close(
if let SketchSurface::Plane(_) = sketch.on {
// We were on a plane, disable the sketch mode.
args.batch_modeling_cmd(
- exec_state.id_generator.next_uuid(),
+ exec_state.next_uuid(),
ModelingCmd::SketchModeDisable(mcmd::SketchModeDisable {}),
)
.await?;
@@ -1573,7 +1573,7 @@ pub(crate) async fn inner_arc(
}
let ccw = angle_start < angle_end;
- let id = exec_state.id_generator.next_uuid();
+ let id = exec_state.next_uuid();
args.batch_modeling_cmd(
id,
@@ -1652,7 +1652,7 @@ pub(crate) async fn inner_arc_to(
args: Args,
) -> Result {
let from: Point2d = sketch.current_pen_position()?;
- let id = exec_state.id_generator.next_uuid();
+ let id = exec_state.next_uuid();
// The start point is taken from the path you are extending.
args.batch_modeling_cmd(
@@ -1798,7 +1798,7 @@ async fn inner_tangential_arc(
let tangent_info = sketch.get_tangential_info_from_paths(); //this function desperately needs some documentation
let tan_previous_point = tangent_info.tan_previous_point(from.into());
- let id = exec_state.id_generator.next_uuid();
+ let id = exec_state.next_uuid();
let (center, to, ccw) = match data {
TangentialArcData::RadiusAndOffset { radius, offset } => {
@@ -1935,7 +1935,7 @@ async fn inner_tangential_arc_to(
});
let delta = [to_x - from.x, to_y - from.y];
- let id = exec_state.id_generator.next_uuid();
+ let id = exec_state.next_uuid();
args.batch_modeling_cmd(id, tan_arc_to(&sketch, &delta)).await?;
let current_path = Path::TangentialArcTo {
@@ -2018,7 +2018,7 @@ async fn inner_tangential_arc_to_relative(
}));
}
- let id = exec_state.id_generator.next_uuid();
+ let id = exec_state.next_uuid();
args.batch_modeling_cmd(id, tan_arc_to(&sketch, &delta)).await?;
let current_path = Path::TangentialArcTo {
@@ -2138,7 +2138,7 @@ async fn inner_bezier_curve(
let delta = data.to;
let to = [from.x + data.to[0], from.y + data.to[1]];
- let id = exec_state.id_generator.next_uuid();
+ let id = exec_state.next_uuid();
args.batch_modeling_cmd(
id,
@@ -2230,7 +2230,7 @@ async fn inner_hole(
let hole_sketches: Vec = hole_sketch.into();
for hole_sketch in hole_sketches {
args.batch_modeling_cmd(
- exec_state.id_generator.next_uuid(),
+ exec_state.next_uuid(),
ModelingCmd::from(mcmd::Solid2dAddHole {
object_id: sketch.id,
hole_id: hole_sketch.id,
@@ -2241,7 +2241,7 @@ async fn inner_hole(
// suggestion (mike)
// we also hide the source hole since its essentially "consumed" by this operation
args.batch_modeling_cmd(
- exec_state.id_generator.next_uuid(),
+ exec_state.next_uuid(),
ModelingCmd::from(mcmd::ObjectVisible {
object_id: hole_sketch.id,
hidden: true,
diff --git a/src/wasm-lib/kcl/src/std/sweep.rs b/src/wasm-lib/kcl/src/std/sweep.rs
index 4de34c4bc8..02566e2ca2 100644
--- a/src/wasm-lib/kcl/src/std/sweep.rs
+++ b/src/wasm-lib/kcl/src/std/sweep.rs
@@ -87,7 +87,7 @@ async fn inner_sweep(
exec_state: &mut ExecState,
args: Args,
) -> Result, KclError> {
- let id = exec_state.id_generator.next_uuid();
+ let id = exec_state.next_uuid();
args.batch_modeling_cmd(
id,
ModelingCmd::from(mcmd::Sweep {
diff --git a/src/wasm-lib/kcl/src/test_server.rs b/src/wasm-lib/kcl/src/test_server.rs
index 5962818f7f..5e00ed66dd 100644
--- a/src/wasm-lib/kcl/src/test_server.rs
+++ b/src/wasm-lib/kcl/src/test_server.rs
@@ -41,7 +41,7 @@ pub async fn execute_and_snapshot_ast(
let ctx = new_context(units, true, project_directory).await?;
do_execute_and_snapshot(&ctx, ast)
.await
- .map(|(state, snap)| (state.memory, state.operations, snap))
+ .map(|(state, snap)| (state.mod_local.memory, state.mod_local.operations, snap))
}
pub async fn execute_and_snapshot_no_auth(
diff --git a/src/wasm-lib/kcl/src/unparser.rs b/src/wasm-lib/kcl/src/unparser.rs
index d587c21e83..a02a2135bb 100644
--- a/src/wasm-lib/kcl/src/unparser.rs
+++ b/src/wasm-lib/kcl/src/unparser.rs
@@ -146,11 +146,11 @@ impl ImportStatement {
string.push_str(" from ");
}
ImportSelector::Glob(_) => string.push_str("* from "),
- ImportSelector::None(_) => {}
+ ImportSelector::None { .. } => {}
}
string.push_str(&format!("\"{}\"", self.path));
- if let ImportSelector::None(Some(alias)) = &self.selector {
+ if let ImportSelector::None { alias: Some(alias) } = &self.selector {
string.push_str(" as ");
string.push_str(&alias.name);
}
diff --git a/src/wasm-lib/kcl/tests/import_side_effect/execution_error.snap b/src/wasm-lib/kcl/tests/import_side_effect/execution_error.snap
index 09cd4bdb64..278cc7eac0 100644
--- a/src/wasm-lib/kcl/tests/import_side_effect/execution_error.snap
+++ b/src/wasm-lib/kcl/tests/import_side_effect/execution_error.snap
@@ -5,8 +5,9 @@ description: Error from executing import_side_effect.kcl
KCL Semantic error
× semantic: Error loading imported file. Open it to view more details.
- │ export_side_effect.kcl: Cannot send modeling commands while importing.
- │ Wrap your code in a function if you want to import the file.
+ │ tests/import_side_effect/export_side_effect.kcl: Cannot send modeling
+ │ commands while importing. Wrap your code in a function if you want to
+ │ import the file.
╭────
1 │ import foo from "export_side_effect.kcl"
· ────────────────────────────────────────
diff --git a/src/wasm-lib/kcl/tests/import_side_effect/ops.snap b/src/wasm-lib/kcl/tests/import_side_effect/ops.snap
index 8914f7c0f5..d6327de12f 100644
--- a/src/wasm-lib/kcl/tests/import_side_effect/ops.snap
+++ b/src/wasm-lib/kcl/tests/import_side_effect/ops.snap
@@ -1,27 +1,5 @@
---
source: kcl/src/simulation_tests.rs
description: Operations executed import_side_effect.kcl
-snapshot_kind: text
---
-[
- {
- "isError": true,
- "labeledArgs": {
- "data": {
- "sourceRange": [
- 95,
- 99,
- 1
- ]
- }
- },
- "name": "startSketchOn",
- "sourceRange": [
- 81,
- 100,
- 1
- ],
- "type": "StdLibCall",
- "unlabeledArg": null
- }
-]
+[]
diff --git a/src/wasm-lib/kcl/tests/import_whole/ast.snap b/src/wasm-lib/kcl/tests/import_whole/ast.snap
new file mode 100644
index 0000000000..123b3996d3
--- /dev/null
+++ b/src/wasm-lib/kcl/tests/import_whole/ast.snap
@@ -0,0 +1,150 @@
+---
+source: kcl/src/simulation_tests.rs
+description: Result of parsing import_whole.kcl
+---
+{
+ "Ok": {
+ "body": [
+ {
+ "end": 32,
+ "path": "exported_mod.kcl",
+ "selector": {
+ "type": "None",
+ "alias": {
+ "end": 32,
+ "name": "foo",
+ "start": 29,
+ "type": "Identifier"
+ }
+ },
+ "start": 0,
+ "type": "ImportStatement",
+ "type": "ImportStatement"
+ },
+ {
+ "declaration": {
+ "end": 96,
+ "id": {
+ "end": 37,
+ "name": "bar",
+ "start": 34,
+ "type": "Identifier"
+ },
+ "init": {
+ "body": [
+ {
+ "end": 43,
+ "name": "foo",
+ "start": 40,
+ "type": "Identifier",
+ "type": "Identifier"
+ },
+ {
+ "arguments": [
+ {
+ "end": 92,
+ "properties": [
+ {
+ "end": 72,
+ "key": {
+ "end": 62,
+ "name": "faces",
+ "start": 57,
+ "type": "Identifier"
+ },
+ "start": 57,
+ "type": "ObjectProperty",
+ "value": {
+ "elements": [
+ {
+ "end": 71,
+ "raw": "'end'",
+ "start": 66,
+ "type": "Literal",
+ "type": "Literal",
+ "value": "end"
+ }
+ ],
+ "end": 72,
+ "start": 65,
+ "type": "ArrayExpression",
+ "type": "ArrayExpression"
+ }
+ },
+ {
+ "end": 90,
+ "key": {
+ "end": 83,
+ "name": "thickness",
+ "start": 74,
+ "type": "Identifier"
+ },
+ "start": 74,
+ "type": "ObjectProperty",
+ "value": {
+ "end": 90,
+ "raw": "0.25",
+ "start": 86,
+ "type": "Literal",
+ "type": "Literal",
+ "value": 0.25
+ }
+ }
+ ],
+ "start": 55,
+ "type": "ObjectExpression",
+ "type": "ObjectExpression"
+ },
+ {
+ "end": 95,
+ "start": 94,
+ "type": "PipeSubstitution",
+ "type": "PipeSubstitution"
+ }
+ ],
+ "callee": {
+ "end": 54,
+ "name": "shell",
+ "start": 49,
+ "type": "Identifier"
+ },
+ "end": 96,
+ "start": 49,
+ "type": "CallExpression",
+ "type": "CallExpression"
+ }
+ ],
+ "end": 96,
+ "start": 40,
+ "type": "PipeExpression",
+ "type": "PipeExpression"
+ },
+ "start": 34,
+ "type": "VariableDeclarator"
+ },
+ "end": 96,
+ "kind": "const",
+ "start": 34,
+ "type": "VariableDeclaration",
+ "type": "VariableDeclaration"
+ }
+ ],
+ "end": 97,
+ "nonCodeMeta": {
+ "nonCodeNodes": {
+ "0": [
+ {
+ "end": 34,
+ "start": 32,
+ "type": "NonCodeNode",
+ "value": {
+ "type": "newLine"
+ }
+ }
+ ]
+ },
+ "startNodes": []
+ },
+ "start": 0
+ }
+}
diff --git a/src/wasm-lib/kcl/tests/import_whole/exported_mod.kcl b/src/wasm-lib/kcl/tests/import_whole/exported_mod.kcl
new file mode 100644
index 0000000000..a803a59fc3
--- /dev/null
+++ b/src/wasm-lib/kcl/tests/import_whole/exported_mod.kcl
@@ -0,0 +1,3 @@
+startSketchOn('XY')
+ |> circle({ center = [5, 5], radius = 10 }, %)
+ |> extrude(10, %)
diff --git a/src/wasm-lib/kcl/tests/import_whole/input.kcl b/src/wasm-lib/kcl/tests/import_whole/input.kcl
new file mode 100644
index 0000000000..48ec0647a8
--- /dev/null
+++ b/src/wasm-lib/kcl/tests/import_whole/input.kcl
@@ -0,0 +1,4 @@
+import "exported_mod.kcl" as foo
+
+bar = foo
+ |> shell({ faces = ['end'], thickness = 0.25 }, %)
diff --git a/src/wasm-lib/kcl/tests/import_whole/ops.snap b/src/wasm-lib/kcl/tests/import_whole/ops.snap
new file mode 100644
index 0000000000..276b9d484d
--- /dev/null
+++ b/src/wasm-lib/kcl/tests/import_whole/ops.snap
@@ -0,0 +1,32 @@
+---
+source: kcl/src/simulation_tests.rs
+description: Operations executed import_whole.kcl
+---
+[
+ {
+ "labeledArgs": {
+ "data": {
+ "sourceRange": [
+ 55,
+ 92,
+ 0
+ ]
+ },
+ "solid_set": {
+ "sourceRange": [
+ 94,
+ 95,
+ 0
+ ]
+ }
+ },
+ "name": "shell",
+ "sourceRange": [
+ 49,
+ 96,
+ 0
+ ],
+ "type": "StdLibCall",
+ "unlabeledArg": null
+ }
+]
diff --git a/src/wasm-lib/kcl/tests/import_whole/program_memory.snap b/src/wasm-lib/kcl/tests/import_whole/program_memory.snap
new file mode 100644
index 0000000000..7795e95ce5
--- /dev/null
+++ b/src/wasm-lib/kcl/tests/import_whole/program_memory.snap
@@ -0,0 +1,164 @@
+---
+source: kcl/src/simulation_tests.rs
+description: Program memory after executing import_whole.kcl
+---
+{
+ "environments": [
+ {
+ "bindings": {
+ "HALF_TURN": {
+ "type": "Number",
+ "value": 180.0,
+ "__meta": []
+ },
+ "QUARTER_TURN": {
+ "type": "Number",
+ "value": 90.0,
+ "__meta": []
+ },
+ "THREE_QUARTER_TURN": {
+ "type": "Number",
+ "value": 270.0,
+ "__meta": []
+ },
+ "ZERO": {
+ "type": "Number",
+ "value": 0.0,
+ "__meta": []
+ },
+ "bar": {
+ "type": "Solid",
+ "type": "Solid",
+ "id": "[uuid]",
+ "value": [
+ {
+ "faceId": "[uuid]",
+ "id": "[uuid]",
+ "sourceRange": [
+ 25,
+ 68,
+ 1
+ ],
+ "tag": null,
+ "type": "extrudeArc"
+ }
+ ],
+ "sketch": {
+ "type": "Sketch",
+ "id": "[uuid]",
+ "paths": [
+ {
+ "__geoMeta": {
+ "id": "[uuid]",
+ "sourceRange": [
+ 25,
+ 68,
+ 1
+ ]
+ },
+ "ccw": true,
+ "center": [
+ 5.0,
+ 5.0
+ ],
+ "from": [
+ 15.0,
+ 5.0
+ ],
+ "radius": 10.0,
+ "tag": null,
+ "to": [
+ 15.0,
+ 5.0
+ ],
+ "type": "Circle"
+ }
+ ],
+ "on": {
+ "type": "plane",
+ "id": "[uuid]",
+ "value": "XY",
+ "origin": {
+ "x": 0.0,
+ "y": 0.0,
+ "z": 0.0
+ },
+ "xAxis": {
+ "x": 1.0,
+ "y": 0.0,
+ "z": 0.0
+ },
+ "yAxis": {
+ "x": 0.0,
+ "y": 1.0,
+ "z": 0.0
+ },
+ "zAxis": {
+ "x": 0.0,
+ "y": 0.0,
+ "z": 1.0
+ },
+ "__meta": []
+ },
+ "start": {
+ "from": [
+ 15.0,
+ 5.0
+ ],
+ "to": [
+ 15.0,
+ 5.0
+ ],
+ "tag": null,
+ "__geoMeta": {
+ "id": "[uuid]",
+ "sourceRange": [
+ 25,
+ 68,
+ 1
+ ]
+ }
+ },
+ "__meta": [
+ {
+ "sourceRange": [
+ 25,
+ 68,
+ 1
+ ]
+ }
+ ]
+ },
+ "height": 10.0,
+ "startCapId": "[uuid]",
+ "endCapId": "[uuid]",
+ "__meta": [
+ {
+ "sourceRange": [
+ 25,
+ 68,
+ 1
+ ]
+ }
+ ]
+ },
+ "foo": {
+ "type": "Module",
+ "value": 1,
+ "__meta": [
+ {
+ "sourceRange": [
+ 0,
+ 32,
+ 0
+ ]
+ }
+ ]
+ }
+ },
+ "parent": null
+ }
+ ],
+ "currentEnv": 0,
+ "return": null
+}
diff --git a/src/wasm-lib/src/wasm.rs b/src/wasm-lib/src/wasm.rs
index 33db3f5902..83a2f6168d 100644
--- a/src/wasm-lib/src/wasm.rs
+++ b/src/wasm-lib/src/wasm.rs
@@ -86,7 +86,7 @@ pub async fn execute(
// Populate from the old exec state if it exists.
if let Some(program_memory_override) = program_memory_override {
- exec_state.memory = program_memory_override;
+ exec_state.mod_local.memory = program_memory_override;
} else {
// If we are in mock mode, we don't want to use any cache.
if let Some(old) = read_old_ast_memory().await {
@@ -110,7 +110,7 @@ pub async fn execute(
}
// Add additional outputs to the error.
- let error = KclErrorWithOutputs::new(err, exec_state.operations.clone());
+ let error = KclErrorWithOutputs::new(err, exec_state.mod_local.operations.clone());
// Throw the error.
return Err(serde_json::to_string(&error).map_err(|serde_err| serde_err.to_string())?);
diff --git a/src/wasm-lib/tests/executor/main.rs b/src/wasm-lib/tests/executor/main.rs
index d76094aa2a..3006fcf1c6 100644
--- a/src/wasm-lib/tests/executor/main.rs
+++ b/src/wasm-lib/tests/executor/main.rs
@@ -1,7 +1,7 @@
mod cache;
use kcl_lib::{
- test_server::{execute_and_snapshot, execute_and_snapshot_no_auth, new_context},
+ test_server::{execute_and_snapshot, execute_and_snapshot_no_auth},
UnitLength,
};
@@ -2001,62 +2001,3 @@ async fn kcl_test_error_no_auth_websocket() {
.to_string()
.contains("Please send the following object over this websocket"));
}
-
-#[tokio::test(flavor = "multi_thread")]
-async fn kcl_test_ids_stable_between_executions() {
- let code = r#"sketch001 = startSketchOn('XZ')
- |> startProfileAt([61.74, 206.13], %)
- |> xLine(305.11, %, $seg01)
- |> yLine(-291.85, %)
- |> xLine(-segLen(seg01), %)
- |> lineTo([profileStartX(%), profileStartY(%)], %)
- |> close(%)
- |> extrude(40.14, %)
- |> shell({
- faces: [seg01],
- thickness: 3.14,
- }, %)
-"#;
-
- let ctx = new_context(UnitLength::Mm, true, None).await.unwrap();
- let old_program = kcl_lib::Program::parse_no_errs(code).unwrap();
- // Execute the program.
- let mut exec_state = Default::default();
- let cache_info = kcl_lib::CacheInformation {
- old: None,
- new_ast: old_program.ast.clone(),
- };
- ctx.run(cache_info, &mut exec_state).await.unwrap();
-
- // Get the id_generator from the first execution.
- let id_generator = exec_state.id_generator.clone();
-
- let code = r#"sketch001 = startSketchOn('XZ')
- |> startProfileAt([62.74, 206.13], %)
- |> xLine(305.11, %, $seg01)
- |> yLine(-291.85, %)
- |> xLine(-segLen(seg01), %)
- |> lineTo([profileStartX(%), profileStartY(%)], %)
- |> close(%)
- |> extrude(40.14, %)
- |> shell({
- faces: [seg01],
- thickness: 3.14,
- }, %)
-"#;
-
- // Execute a slightly different program again.
- let program = kcl_lib::Program::parse_no_errs(code).unwrap();
- let cache_info = kcl_lib::CacheInformation {
- old: Some(kcl_lib::OldAstState {
- ast: old_program.ast.clone(),
- exec_state: exec_state.clone(),
- settings: ctx.settings.clone(),
- }),
- new_ast: program.ast.clone(),
- };
- // Execute the program.
- ctx.run(cache_info, &mut exec_state).await.unwrap();
-
- assert_eq!(id_generator, exec_state.id_generator);
-}
diff --git a/src/wasm-lib/tests/modify/main.rs b/src/wasm-lib/tests/modify/main.rs
index 677eb895d4..22c813d74b 100644
--- a/src/wasm-lib/tests/modify/main.rs
+++ b/src/wasm-lib/tests/modify/main.rs
@@ -15,8 +15,8 @@ async fn setup(code: &str, name: &str) -> Result<(ExecutorContext, Program, Modu
// We need to get the sketch ID.
// Get the sketch ID from memory.
- let KclValue::Sketch { value: sketch } = exec_state.memory.get(name, SourceRange::default()).unwrap() else {
- anyhow::bail!("part001 not found in memory: {:?}", exec_state.memory);
+ let KclValue::Sketch { value: sketch } = exec_state.memory().get(name, SourceRange::default()).unwrap() else {
+ anyhow::bail!("part001 not found in memory: {:?}", exec_state.memory());
};
let sketch_id = sketch.id;