Misc tidying up around KclValue, etc. (#5653)

* Make some things a little less public

Signed-off-by: Nick Cameron <nrc@ncameron.org>

* Rename KclValue::Array to MixedArray

Signed-off-by: Nick Cameron <nrc@ncameron.org>

* Add settings to KclValue::Function

Signed-off-by: Nick Cameron <nrc@ncameron.org>

* Remove a bunch of dead code, simplifying mock exec and meaning KclValue no longer needs to deserialize

Signed-off-by: Nick Cameron <nrc@ncameron.org>

---------

Signed-off-by: Nick Cameron <nrc@ncameron.org>
This commit is contained in:
Nick Cameron
2025-03-08 04:04:57 +13:00
committed by GitHub
parent 5d25f4a0e5
commit 6cce3cda36
39 changed files with 163 additions and 470 deletions

View File

@ -144287,7 +144287,7 @@
"type": { "type": {
"type": "string", "type": "string",
"enum": [ "enum": [
"Array" "MixedArray"
] ]
}, },
"value": { "value": {
@ -146899,7 +146899,7 @@
"type": { "type": {
"type": "string", "type": "string",
"enum": [ "enum": [
"Array" "MixedArray"
] ]
}, },
"value": { "value": {
@ -149515,7 +149515,7 @@
"type": { "type": {
"type": "string", "type": "string",
"enum": [ "enum": [
"Array" "MixedArray"
] ]
}, },
"value": { "value": {
@ -222893,7 +222893,7 @@
"type": { "type": {
"type": "string", "type": "string",
"enum": [ "enum": [
"Array" "MixedArray"
] ]
}, },
"value": { "value": {
@ -225504,7 +225504,7 @@
"type": { "type": {
"type": "string", "type": "string",
"enum": [ "enum": [
"Array" "MixedArray"
] ]
}, },
"value": { "value": {
@ -226408,7 +226408,7 @@
"type": { "type": {
"type": "string", "type": "string",
"enum": [ "enum": [
"Array" "MixedArray"
] ]
}, },
"value": { "value": {
@ -233813,7 +233813,7 @@
"type": { "type": {
"type": "string", "type": "string",
"enum": [ "enum": [
"Array" "MixedArray"
] ]
}, },
"value": { "value": {
@ -236422,7 +236422,7 @@
"type": { "type": {
"type": "string", "type": "string",
"enum": [ "enum": [
"Array" "MixedArray"
] ]
}, },
"value": { "value": {
@ -236946,7 +236946,7 @@
"type": { "type": {
"type": "string", "type": "string",
"enum": [ "enum": [
"Array" "MixedArray"
] ]
}, },
"value": { "value": {
@ -239556,7 +239556,7 @@
"type": { "type": {
"type": "string", "type": "string",
"enum": [ "enum": [
"Array" "MixedArray"
] ]
}, },
"value": { "value": {
@ -240460,7 +240460,7 @@
"type": { "type": {
"type": "string", "type": "string",
"enum": [ "enum": [
"Array" "MixedArray"
] ]
}, },
"value": { "value": {
@ -242708,7 +242708,7 @@
"type": { "type": {
"type": "string", "type": "string",
"enum": [ "enum": [
"Array" "MixedArray"
] ]
}, },
"value": { "value": {
@ -245317,7 +245317,7 @@
"type": { "type": {
"type": "string", "type": "string",
"enum": [ "enum": [
"Array" "MixedArray"
] ]
}, },
"value": { "value": {
@ -245841,7 +245841,7 @@
"type": { "type": {
"type": "string", "type": "string",
"enum": [ "enum": [
"Array" "MixedArray"
] ]
}, },
"value": { "value": {
@ -248453,7 +248453,7 @@
"type": { "type": {
"type": "string", "type": "string",
"enum": [ "enum": [
"Array" "MixedArray"
] ]
}, },
"value": { "value": {
@ -251063,7 +251063,7 @@
"type": { "type": {
"type": "string", "type": "string",
"enum": [ "enum": [
"Array" "MixedArray"
] ]
}, },
"value": { "value": {
@ -251967,7 +251967,7 @@
"type": { "type": {
"type": "string", "type": "string",
"enum": [ "enum": [
"Array" "MixedArray"
] ]
}, },
"value": { "value": {

View File

@ -92,7 +92,7 @@ Any KCL value.
| Property | Type | Description | Required | | Property | Type | Description | Required |
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `type` |enum: `Array`| | No | | `type` |enum: `MixedArray`| | No |
| `value` |`[` [`KclValue`](/docs/kcl/types/KclValue) `]`| | No | | `value` |`[` [`KclValue`](/docs/kcl/types/KclValue) `]`| | No |
| `__meta` |`[` [`Metadata`](/docs/kcl/types/Metadata) `]`| | No | | `__meta` |`[` [`Metadata`](/docs/kcl/types/Metadata) `]`| | No |

View File

@ -234,7 +234,7 @@ impl From<&KclValue> for OpKclValue {
ty: ty.clone(), ty: ty.clone(),
}, },
KclValue::String { value, .. } => Self::String { value: value.clone() }, KclValue::String { value, .. } => Self::String { value: value.clone() },
KclValue::Array { value, .. } => { KclValue::MixedArray { value, .. } => {
let value = value.iter().map(Self::from).collect(); let value = value.iter().map(Self::from).collect();
Self::Array { value } Self::Array { value }
} }

View File

@ -588,6 +588,7 @@ impl ExecutorContext {
KclValue::Function { KclValue::Function {
value: FunctionSource::User { value: FunctionSource::User {
ast: function_expression.clone(), ast: function_expression.clone(),
settings: exec_state.mod_local.settings.clone(),
memory: exec_state.mut_stack().snapshot(), memory: exec_state.mut_stack().snapshot(),
}, },
meta: vec![metadata.to_owned()], meta: vec![metadata.to_owned()],
@ -754,7 +755,7 @@ impl Node<MemberExpression> {
} }
}; };
let KclValue::Array { value: array, meta: _ } = array else { let KclValue::MixedArray { value: array, meta: _ } = array else {
return Err(KclError::Semantic(KclErrorDetails { return Err(KclError::Semantic(KclErrorDetails {
message: format!("MemberExpression array is not an array: {:?}", array), message: format!("MemberExpression array is not an array: {:?}", array),
source_ranges: vec![self.clone().into()], source_ranges: vec![self.clone().into()],
@ -804,7 +805,7 @@ impl Node<MemberExpression> {
source_ranges: vec![self.clone().into()], source_ranges: vec![self.clone().into()],
})) }))
} }
(KclValue::Array { value: arr, meta: _ }, Property::UInt(index)) => { (KclValue::MixedArray { value: arr, meta: _ }, Property::UInt(index)) => {
let value_of_arr = arr.get(index); let value_of_arr = arr.get(index);
if let Some(value) = value_of_arr { if let Some(value) = value_of_arr {
Ok(value.to_owned()) Ok(value.to_owned())
@ -815,7 +816,7 @@ impl Node<MemberExpression> {
})) }))
} }
} }
(KclValue::Array { .. }, p) => { (KclValue::MixedArray { .. }, p) => {
let t = p.type_name(); let t = p.type_name();
let article = article_for(t); let article = article_for(t);
Err(KclError::Semantic(KclErrorDetails { Err(KclError::Semantic(KclErrorDetails {
@ -1489,7 +1490,7 @@ impl Node<ArrayExpression> {
results.push(value); results.push(value);
} }
Ok(KclValue::Array { Ok(KclValue::MixedArray {
value: results, value: results,
meta: vec![self.into()], meta: vec![self.into()],
}) })
@ -1538,7 +1539,7 @@ impl Node<ArrayRangeExpression> {
let meta = vec![Metadata { let meta = vec![Metadata {
source_range: self.into(), source_range: self.into(),
}]; }];
Ok(KclValue::Array { Ok(KclValue::MixedArray {
value: range value: range
.into_iter() .into_iter()
.map(|num| KclValue::Number { .map(|num| KclValue::Number {
@ -1952,7 +1953,7 @@ impl FunctionSource {
func(exec_state, args).await.map(Some) func(exec_state, args).await.map(Some)
} }
FunctionSource::User { ast, memory } => { FunctionSource::User { ast, memory, .. } => {
call_user_defined_function(args, *memory, ast, exec_state, ctx).await call_user_defined_function(args, *memory, ast, exec_state, ctx).await
} }
FunctionSource::None => unreachable!(), FunctionSource::None => unreachable!(),

View File

@ -28,7 +28,7 @@ use crate::{
pub type KclObjectFields = HashMap<String, KclValue>; pub type KclObjectFields = HashMap<String, KclValue>;
/// Any KCL value. /// Any KCL value.
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)] #[derive(Debug, Clone, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[ts(export)] #[ts(export)]
#[serde(tag = "type")] #[serde(tag = "type")]
pub enum KclValue { pub enum KclValue {
@ -53,7 +53,7 @@ pub enum KclValue {
#[serde(rename = "__meta")] #[serde(rename = "__meta")]
meta: Vec<Metadata>, meta: Vec<Metadata>,
}, },
Array { MixedArray {
value: Vec<KclValue>, value: Vec<KclValue>,
#[serde(rename = "__meta")] #[serde(rename = "__meta")]
meta: Vec<Metadata>, meta: Vec<Metadata>,
@ -129,6 +129,7 @@ pub enum FunctionSource {
}, },
User { User {
ast: crate::parsing::ast::types::BoxNode<FunctionExpression>, ast: crate::parsing::ast::types::BoxNode<FunctionExpression>,
settings: MetaSettings,
memory: EnvironmentRef, memory: EnvironmentRef,
}, },
} }
@ -194,7 +195,7 @@ impl From<KclValue> for Vec<SourceRange> {
KclValue::Bool { meta, .. } => to_vec_sr(&meta), KclValue::Bool { meta, .. } => to_vec_sr(&meta),
KclValue::Number { meta, .. } => to_vec_sr(&meta), KclValue::Number { meta, .. } => to_vec_sr(&meta),
KclValue::String { meta, .. } => to_vec_sr(&meta), KclValue::String { meta, .. } => to_vec_sr(&meta),
KclValue::Array { meta, .. } => to_vec_sr(&meta), KclValue::MixedArray { meta, .. } => to_vec_sr(&meta),
KclValue::Object { meta, .. } => to_vec_sr(&meta), KclValue::Object { meta, .. } => to_vec_sr(&meta),
KclValue::Module { meta, .. } => to_vec_sr(&meta), KclValue::Module { meta, .. } => to_vec_sr(&meta),
KclValue::Uuid { meta, .. } => to_vec_sr(&meta), KclValue::Uuid { meta, .. } => to_vec_sr(&meta),
@ -227,7 +228,7 @@ impl From<&KclValue> for Vec<SourceRange> {
KclValue::Number { meta, .. } => to_vec_sr(meta), KclValue::Number { meta, .. } => to_vec_sr(meta),
KclValue::String { meta, .. } => to_vec_sr(meta), KclValue::String { meta, .. } => to_vec_sr(meta),
KclValue::Uuid { meta, .. } => to_vec_sr(meta), KclValue::Uuid { meta, .. } => to_vec_sr(meta),
KclValue::Array { meta, .. } => to_vec_sr(meta), KclValue::MixedArray { meta, .. } => to_vec_sr(meta),
KclValue::Object { meta, .. } => to_vec_sr(meta), KclValue::Object { meta, .. } => to_vec_sr(meta),
KclValue::Module { meta, .. } => to_vec_sr(meta), KclValue::Module { meta, .. } => to_vec_sr(meta),
KclValue::KclNone { meta, .. } => to_vec_sr(meta), KclValue::KclNone { meta, .. } => to_vec_sr(meta),
@ -251,7 +252,7 @@ impl KclValue {
KclValue::Bool { value: _, meta } => meta.clone(), KclValue::Bool { value: _, meta } => meta.clone(),
KclValue::Number { meta, .. } => meta.clone(), KclValue::Number { meta, .. } => meta.clone(),
KclValue::String { value: _, meta } => meta.clone(), KclValue::String { value: _, meta } => meta.clone(),
KclValue::Array { value: _, meta } => meta.clone(), KclValue::MixedArray { value: _, meta } => meta.clone(),
KclValue::Object { value: _, meta } => meta.clone(), KclValue::Object { value: _, meta } => meta.clone(),
KclValue::TagIdentifier(x) => x.meta.clone(), KclValue::TagIdentifier(x) => x.meta.clone(),
KclValue::TagDeclarator(x) => vec![x.metadata()], KclValue::TagDeclarator(x) => vec![x.metadata()],
@ -288,7 +289,7 @@ impl KclValue {
match self { match self {
KclValue::Solid { value } => Ok(SolidSet::Solid(value.clone())), KclValue::Solid { value } => Ok(SolidSet::Solid(value.clone())),
KclValue::Solids { value } => Ok(SolidSet::Solids(value.clone())), KclValue::Solids { value } => Ok(SolidSet::Solids(value.clone())),
KclValue::Array { value, .. } => { KclValue::MixedArray { value, .. } => {
let solids: Vec<_> = value let solids: Vec<_> = value
.iter() .iter()
.enumerate() .enumerate()
@ -334,7 +335,7 @@ impl KclValue {
KclValue::Bool { .. } => "boolean (true/false value)", KclValue::Bool { .. } => "boolean (true/false value)",
KclValue::Number { .. } => "number", KclValue::Number { .. } => "number",
KclValue::String { .. } => "string (text)", KclValue::String { .. } => "string (text)",
KclValue::Array { .. } => "array (list)", KclValue::MixedArray { .. } => "array (list)",
KclValue::Object { .. } => "object", KclValue::Object { .. } => "object",
KclValue::Module { .. } => "module", KclValue::Module { .. } => "module",
KclValue::Type { .. } => "type", KclValue::Type { .. } => "type",
@ -395,7 +396,7 @@ impl KclValue {
/// Put the point into a KCL value. /// Put the point into a KCL value.
pub fn from_point2d(p: [f64; 2], ty: NumericType, meta: Vec<Metadata>) -> Self { pub fn from_point2d(p: [f64; 2], ty: NumericType, meta: Vec<Metadata>) -> Self {
Self::Array { Self::MixedArray {
value: vec![ value: vec![
Self::Number { Self::Number {
value: p[0], value: p[0],
@ -451,7 +452,7 @@ impl KclValue {
} }
pub fn as_array(&self) -> Option<&[KclValue]> { pub fn as_array(&self) -> Option<&[KclValue]> {
if let KclValue::Array { value, meta: _ } = &self { if let KclValue::MixedArray { value, meta: _ } = &self {
Some(value) Some(value)
} else { } else {
None None
@ -610,7 +611,7 @@ impl KclValue {
KclValue::Sketches { .. } => Some(RuntimeType::Array(PrimitiveType::Sketch)), KclValue::Sketches { .. } => Some(RuntimeType::Array(PrimitiveType::Sketch)),
KclValue::Solid { .. } => Some(RuntimeType::Primitive(PrimitiveType::Solid)), KclValue::Solid { .. } => Some(RuntimeType::Primitive(PrimitiveType::Solid)),
KclValue::Solids { .. } => Some(RuntimeType::Array(PrimitiveType::Solid)), KclValue::Solids { .. } => Some(RuntimeType::Array(PrimitiveType::Solid)),
KclValue::Array { value, .. } => Some(RuntimeType::Tuple( KclValue::MixedArray { value, .. } => Some(RuntimeType::Tuple(
value value
.iter() .iter()
.map(|v| v.principal_type().and_then(RuntimeType::primitive)) .map(|v| v.principal_type().and_then(RuntimeType::primitive))
@ -665,7 +666,7 @@ impl KclValue {
result result
} }
KclValue::Function { KclValue::Function {
value: FunctionSource::User { ast, memory }, value: FunctionSource::User { ast, memory, .. },
.. ..
} => crate::execution::exec_ast::call_user_defined_function(args, *memory, ast, exec_state, &ctx).await, } => crate::execution::exec_ast::call_user_defined_function(args, *memory, ast, exec_state, &ctx).await,
_ => Err(KclError::Semantic(KclErrorDetails { _ => Err(KclError::Semantic(KclErrorDetails {
@ -701,7 +702,7 @@ impl KclValue {
todo!("Implement KCL stdlib fns with keyword args"); todo!("Implement KCL stdlib fns with keyword args");
} }
KclValue::Function { KclValue::Function {
value: FunctionSource::User { ast, memory }, value: FunctionSource::User { ast, memory, .. },
.. ..
} => { } => {
crate::execution::exec_ast::call_user_defined_function_kw(args.kw_args, *memory, ast, exec_state, &ctx) crate::execution::exec_ast::call_user_defined_function_kw(args.kw_args, *memory, ast, exec_state, &ctx)
@ -723,7 +724,7 @@ impl KclValue {
KclValue::TagDeclarator(tag) => Some(format!("${}", tag.name)), KclValue::TagDeclarator(tag) => Some(format!("${}", tag.name)),
KclValue::TagIdentifier(tag) => Some(format!("${}", tag.value)), KclValue::TagIdentifier(tag) => Some(format!("${}", tag.value)),
// TODO better Array and Object stringification // TODO better Array and Object stringification
KclValue::Array { .. } => Some("[...]".to_owned()), KclValue::MixedArray { .. } => Some("[...]".to_owned()),
KclValue::Object { .. } => Some("{ ... }".to_owned()), KclValue::Object { .. } => Some("{ ... }".to_owned()),
KclValue::Module { .. } KclValue::Module { .. }
| KclValue::Solid { .. } | KclValue::Solid { .. }

View File

@ -687,14 +687,6 @@ impl Stack {
.insert_or_update(key, value, self.id); .insert_or_update(key, value, self.id);
} }
/// Delete an item from memory.
///
/// Item will be preserved in any snapshots.
pub fn clear(&mut self, key: String) {
self.memory.stats.mutation_count.fetch_add(1, Ordering::Relaxed);
self.memory.get_env(self.current_env.index()).clear(key, self.id);
}
/// Get a value from the program memory. /// Get a value from the program memory.
/// Return Err if not found. /// Return Err if not found.
pub fn get(&self, var: &str, source_range: SourceRange) -> Result<&KclValue, KclError> { pub fn get(&self, var: &str, source_range: SourceRange) -> Result<&KclValue, KclError> {
@ -1167,19 +1159,6 @@ mod env {
self.get_mut_bindings(owner).insert(key, value); self.get_mut_bindings(owner).insert(key, value);
} }
/// Delete a key/value.
///
/// We want to preserve the snapshot, so we can't just remove the element. We copy the deleted
/// value to the snapshot and replace the current value with a tombstone.
pub(super) fn clear(&self, key: String, owner: usize) {
if self.get_bindings().contains_key(&key) {
let old = self.get_mut_bindings(owner).insert(key.clone(), tombstone()).unwrap();
if let Some(s) = self.cur_snapshot(owner) {
s.data.insert(key, old);
}
}
}
/// Was the key contained in this environment at the specified point in time. /// Was the key contained in this environment at the specified point in time.
fn snapshot_contains_key(&self, key: &str, snapshot: SnapshotRef) -> bool { fn snapshot_contains_key(&self, key: &str, snapshot: SnapshotRef) -> bool {
for i in snapshot.index()..self.snapshots_len() { for i in snapshot.index()..self.snapshots_len() {
@ -1573,61 +1552,6 @@ mod test {
); );
} }
#[test]
fn snap_env_clear() {
let mem = &mut Stack::new_for_tests();
mem.add("a".to_owned(), val(1), sr()).unwrap();
mem.add("b".to_owned(), val(3), sr()).unwrap();
let sn = mem.snapshot();
mem.push_new_env_for_call(sn);
mem.snapshot();
mem.add("b".to_owned(), val(4), sr()).unwrap();
mem.snapshot();
mem.clear("b".to_owned());
mem.clear("a".to_owned());
assert_get(mem, "b", 3);
assert_get(mem, "a", 1);
mem.pop_env();
assert_get(mem, "b", 3);
assert_get(mem, "a", 1);
}
#[test]
fn snap_env_clear2() {
let mem = &mut Stack::new_for_tests();
mem.add("a".to_owned(), val(1), sr()).unwrap();
mem.add("b".to_owned(), val(3), sr()).unwrap();
let sn1 = mem.snapshot();
mem.clear("b".to_owned());
mem.clear("a".to_owned());
mem.get("b", SourceRange::default()).unwrap_err();
mem.get("a", SourceRange::default()).unwrap_err();
let sn = mem.snapshot();
mem.push_new_env_for_call(sn);
mem.add("b".to_owned(), val(4), sr()).unwrap();
let sn2 = mem.snapshot();
mem.clear("b".to_owned());
mem.clear("a".to_owned());
mem.get("b", SourceRange::default()).unwrap_err();
mem.get("a", SourceRange::default()).unwrap_err();
mem.pop_env();
mem.get("b", SourceRange::default()).unwrap_err();
mem.get("a", SourceRange::default()).unwrap_err();
assert_get_from(mem, "a", 1, sn1);
assert_get_from(mem, "b", 3, sn1);
mem.memory
.get_from_unchecked("a", sn2, SourceRange::default())
.unwrap_err();
assert_get_from(mem, "b", 4, sn2);
}
#[test] #[test]
fn squash_env() { fn squash_env() {
let mem = &mut Stack::new_for_tests(); let mem = &mut Stack::new_for_tests();
@ -1641,6 +1565,7 @@ mod test {
KclValue::Function { KclValue::Function {
value: FunctionSource::User { value: FunctionSource::User {
ast: crate::parsing::ast::types::FunctionExpression::dummy(), ast: crate::parsing::ast::types::FunctionExpression::dummy(),
settings: crate::MetaSettings::default(),
memory: sn2, memory: sn2,
}, },
meta: Vec::new(), meta: Vec::new(),

View File

@ -55,7 +55,7 @@ mod memory;
mod state; mod state;
/// Outcome of executing a program. This is used in TS. /// Outcome of executing a program. This is used in TS.
#[derive(Debug, Clone, Deserialize, Serialize, ts_rs::TS)] #[derive(Debug, Clone, Serialize, ts_rs::TS)]
#[ts(export)] #[ts(export)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct ExecOutcome { pub struct ExecOutcome {
@ -517,7 +517,6 @@ impl ExecutorContext {
&self, &self,
program: crate::Program, program: crate::Program,
use_prev_memory: bool, use_prev_memory: bool,
variables: IndexMap<String, KclValue>,
) -> Result<ExecOutcome, KclErrorWithOutputs> { ) -> Result<ExecOutcome, KclErrorWithOutputs> {
assert!(self.is_mock()); assert!(self.is_mock());
@ -531,22 +530,9 @@ impl ExecutorContext {
self.prepare_mem(&mut exec_state).await? self.prepare_mem(&mut exec_state).await?
}; };
let mut to_restore = Vec::new(); // Push a scope so that old variables can be overwritten (since we might be re-executing some
{ // part of the scene).
let mem = exec_state.mut_stack(); exec_state.mut_stack().push_new_env_for_scope();
// Push a scope so that old variables can be overwritten (since we might be re-executing some
// part of the scene).
mem.push_new_env_for_scope();
// Add any extra variables to memory (we want to remove these variables after execution, but
// can't do this using scopes because we want to keep the results of computation in other cases).
for (k, v) in variables {
to_restore.push((k.clone(), mem.get(&k, SourceRange::default()).ok().cloned()));
mem.add(k, v, SourceRange::synthetic())
.map_err(KclErrorWithOutputs::no_outputs)?;
}
}
let result = self.inner_run(&program, &mut exec_state, true).await?; let result = self.inner_run(&program, &mut exec_state, true).await?;
@ -558,12 +544,6 @@ impl ExecutorContext {
let outcome = exec_state.to_mock_wasm_outcome(result.0); let outcome = exec_state.to_mock_wasm_outcome(result.0);
mem.squash_env(result.0); mem.squash_env(result.0);
for (k, v) in to_restore {
match v {
Some(v) => mem.insert_or_update(k, v),
None => mem.clear(k),
}
}
cache::write_old_memory(mem).await; cache::write_old_memory(mem).await;
Ok(outcome) Ok(outcome)
@ -1885,33 +1865,6 @@ let w = f() + f()
assert_eq!(settings_state, ctx.settings); assert_eq!(settings_state, ctx.settings);
} }
#[tokio::test(flavor = "multi_thread")]
async fn mock_variables() {
let ctx = ExecutorContext::new_mock().await;
let program = crate::Program::parse_no_errs("x = y").unwrap();
let mut vars = IndexMap::new();
vars.insert(
"y".to_owned(),
KclValue::Number {
value: 2.0,
ty: kcl_value::NumericType::Unknown,
meta: Vec::new(),
},
);
let result = ctx.run_mock(program, true, vars).await.unwrap();
assert_eq!(result.variables.get("x").unwrap().as_f64().unwrap(), 2.0);
cache::read_old_memory()
.await
.unwrap()
.get("y", SourceRange::default())
.unwrap_err();
let program2 = crate::Program::parse_no_errs("z = x + 1").unwrap();
let result = ctx.run_mock(program2, true, IndexMap::new()).await.unwrap();
assert_eq!(result.variables.get("z").unwrap().as_f64().unwrap(), 3.0);
}
#[tokio::test(flavor = "multi_thread")] #[tokio::test(flavor = "multi_thread")]
async fn mock_after_not_mock() { async fn mock_after_not_mock() {
let ctx = ExecutorContext::new_with_default_client(UnitLength::Mm).await.unwrap(); let ctx = ExecutorContext::new_with_default_client(UnitLength::Mm).await.unwrap();
@ -1921,7 +1874,7 @@ let w = f() + f()
let ctx2 = ExecutorContext::new_mock().await; let ctx2 = ExecutorContext::new_mock().await;
let program2 = crate::Program::parse_no_errs("z = x + 1").unwrap(); let program2 = crate::Program::parse_no_errs("z = x + 1").unwrap();
let result = ctx2.run_mock(program2, true, IndexMap::new()).await.unwrap(); let result = ctx2.run_mock(program2, true).await.unwrap();
assert_eq!(result.variables.get("z").unwrap().as_f64().unwrap(), 3.0); assert_eq!(result.variables.get("z").unwrap().as_f64().unwrap(), 3.0);
} }
} }

View File

@ -76,7 +76,7 @@ pub mod std;
pub mod test_server; pub mod test_server;
mod thread; mod thread;
mod unparser; mod unparser;
pub mod walk; mod walk;
#[cfg(target_arch = "wasm32")] #[cfg(target_arch = "wasm32")]
mod wasm; mod wasm;

View File

@ -341,7 +341,7 @@ impl Args {
meta: vec![meta], meta: vec![meta],
ty: NumericType::Unknown, ty: NumericType::Unknown,
}; };
Ok(KclValue::Array { Ok(KclValue::MixedArray {
value: vec![x, y], value: vec![x, y],
meta: vec![meta], meta: vec![meta],
}) })
@ -377,7 +377,7 @@ impl Args {
ty: ty.clone(), ty: ty.clone(),
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();
Ok(KclValue::Array { Ok(KclValue::MixedArray {
value: array, value: array,
meta: vec![Metadata { meta: vec![Metadata {
source_range: self.source_range, source_range: self.source_range,
@ -631,7 +631,7 @@ impl<'a> FromArgs<'a> for Vec<KclValue> {
source_ranges: vec![args.source_range], source_ranges: vec![args.source_range],
})); }));
}; };
let KclValue::Array { value: array, meta: _ } = &arg.value else { let KclValue::MixedArray { value: array, meta: _ } = &arg.value else {
let message = format!("Expected an array but found {}", arg.value.human_friendly_type()); let message = format!("Expected an array but found {}", arg.value.human_friendly_type());
return Err(KclError::Type(KclErrorDetails { return Err(KclError::Type(KclErrorDetails {
source_ranges: arg.source_ranges(), source_ranges: arg.source_ranges(),
@ -733,7 +733,7 @@ where
impl<'a> FromKclValue<'a> for [f64; 2] { impl<'a> FromKclValue<'a> for [f64; 2] {
fn from_kcl_val(arg: &'a KclValue) -> Option<Self> { fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
let KclValue::Array { value, meta: _ } = arg else { let KclValue::MixedArray { value, meta: _ } = arg else {
return None; return None;
}; };
if value.len() != 2 { if value.len() != 2 {
@ -748,7 +748,7 @@ impl<'a> FromKclValue<'a> for [f64; 2] {
impl<'a> FromKclValue<'a> for [usize; 3] { impl<'a> FromKclValue<'a> for [usize; 3] {
fn from_kcl_val(arg: &'a KclValue) -> Option<Self> { fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
let KclValue::Array { value, meta: _ } = arg else { let KclValue::MixedArray { value, meta: _ } = arg else {
return None; return None;
}; };
if value.len() != 3 { if value.len() != 3 {
@ -764,7 +764,7 @@ impl<'a> FromKclValue<'a> for [usize; 3] {
impl<'a> FromKclValue<'a> for [f64; 3] { impl<'a> FromKclValue<'a> for [f64; 3] {
fn from_kcl_val(arg: &'a KclValue) -> Option<Self> { fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
let KclValue::Array { value, meta: _ } = arg else { let KclValue::MixedArray { value, meta: _ } = arg else {
return None; return None;
}; };
if value.len() != 3 { if value.len() != 3 {
@ -1249,7 +1249,7 @@ impl_from_kcl_for_vec!(Sketch);
impl<'a> FromKclValue<'a> for SourceRange { impl<'a> FromKclValue<'a> for SourceRange {
fn from_kcl_val(arg: &'a KclValue) -> Option<Self> { fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
let KclValue::Array { value, meta: _ } = arg else { let KclValue::MixedArray { value, meta: _ } = arg else {
return None; return None;
}; };
if value.len() != 3 { if value.len() != 3 {
@ -1517,7 +1517,7 @@ impl<'a> FromKclValue<'a> for SketchSet {
match arg { match arg {
KclValue::Sketch { value: sketch } => Some(SketchSet::from(sketch.to_owned())), KclValue::Sketch { value: sketch } => Some(SketchSet::from(sketch.to_owned())),
KclValue::Sketches { value } => Some(SketchSet::from(value.to_owned())), KclValue::Sketches { value } => Some(SketchSet::from(value.to_owned())),
KclValue::Array { .. } => { KclValue::MixedArray { .. } => {
let v: Option<Vec<Sketch>> = FromKclValue::from_kcl_val(arg); let v: Option<Vec<Sketch>> = FromKclValue::from_kcl_val(arg);
Some(SketchSet::Sketches(v?.iter().cloned().map(Box::new).collect())) Some(SketchSet::Sketches(v?.iter().cloned().map(Box::new).collect()))
} }

View File

@ -19,7 +19,7 @@ pub async fn map(exec_state: &mut ExecState, args: Args) -> Result<KclValue, Kcl
let (array, f): (Vec<KclValue>, &FunctionSource) = FromArgs::from_args(&args, 0)?; let (array, f): (Vec<KclValue>, &FunctionSource) = FromArgs::from_args(&args, 0)?;
let meta = vec![args.source_range.into()]; let meta = vec![args.source_range.into()];
let new_array = inner_map(array, f, exec_state, &args).await?; let new_array = inner_map(array, f, exec_state, &args).await?;
Ok(KclValue::Array { value: new_array, meta }) Ok(KclValue::MixedArray { value: new_array, meta })
} }
/// Apply a function to every element of a list. /// Apply a function to every element of a list.
@ -230,7 +230,7 @@ async fn call_reduce_closure(
async fn inner_push(mut array: Vec<KclValue>, elem: KclValue, args: &Args) -> Result<KclValue, KclError> { async fn inner_push(mut array: Vec<KclValue>, elem: KclValue, args: &Args) -> Result<KclValue, KclError> {
// Unwrap the KclValues to JValues for manipulation // Unwrap the KclValues to JValues for manipulation
array.push(elem); array.push(elem);
Ok(KclValue::Array { Ok(KclValue::MixedArray {
value: array, value: array,
meta: vec![args.source_range.into()], meta: vec![args.source_range.into()],
}) })
@ -241,7 +241,7 @@ pub async fn push(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
let (val, elem): (KclValue, KclValue) = FromArgs::from_args(&args, 0)?; let (val, elem): (KclValue, KclValue) = FromArgs::from_args(&args, 0)?;
let meta = vec![args.source_range]; let meta = vec![args.source_range];
let KclValue::Array { value: array, meta: _ } = val else { let KclValue::MixedArray { value: array, meta: _ } = val else {
let actual_type = val.human_friendly_type(); let actual_type = val.human_friendly_type();
return Err(KclError::Semantic(KclErrorDetails { return Err(KclError::Semantic(KclErrorDetails {
source_ranges: meta, source_ranges: meta,
@ -281,7 +281,7 @@ async fn inner_pop(array: Vec<KclValue>, args: &Args) -> Result<KclValue, KclErr
// Create a new array with all elements except the last one // Create a new array with all elements except the last one
let new_array = array[..array.len() - 1].to_vec(); let new_array = array[..array.len() - 1].to_vec();
Ok(KclValue::Array { Ok(KclValue::MixedArray {
value: new_array, value: new_array,
meta: vec![args.source_range.into()], meta: vec![args.source_range.into()],
}) })
@ -292,7 +292,7 @@ pub async fn pop(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, Kc
let val = args.get_unlabeled_kw_arg("array")?; let val = args.get_unlabeled_kw_arg("array")?;
let meta = vec![args.source_range]; let meta = vec![args.source_range];
let KclValue::Array { value: array, meta: _ } = val else { let KclValue::MixedArray { value: array, meta: _ } = val else {
let actual_type = val.human_friendly_type(); let actual_type = val.human_friendly_type();
return Err(KclError::Semantic(KclErrorDetails { return Err(KclError::Semantic(KclErrorDetails {
source_ranges: meta, source_ranges: meta,

View File

@ -441,7 +441,7 @@ async fn make_transform<T: GeometryTrait>(
})?; })?;
let transforms = match transform_fn_return { let transforms = match transform_fn_return {
KclValue::Object { value, meta: _ } => vec![value], KclValue::Object { value, meta: _ } => vec![value],
KclValue::Array { value, meta: _ } => { KclValue::MixedArray { value, meta: _ } => {
let transforms: Vec<_> = value let transforms: Vec<_> = value
.into_iter() .into_iter()
.map(|val| { .map(|val| {
@ -540,7 +540,7 @@ fn transform_from_obj_fields<T: GeometryTrait>(
} }
fn array_to_point3d(val: &KclValue, source_ranges: Vec<SourceRange>) -> Result<Point3d, KclError> { fn array_to_point3d(val: &KclValue, source_ranges: Vec<SourceRange>) -> Result<Point3d, KclError> {
let KclValue::Array { value: arr, meta } = val else { let KclValue::MixedArray { value: arr, meta } = val else {
return Err(KclError::Semantic(KclErrorDetails { return Err(KclError::Semantic(KclErrorDetails {
message: "Expected an array of 3 numbers (i.e. a 3D point)".to_string(), message: "Expected an array of 3 numbers (i.e. a 3D point)".to_string(),
source_ranges, source_ranges,
@ -572,7 +572,7 @@ fn array_to_point3d(val: &KclValue, source_ranges: Vec<SourceRange>) -> Result<P
} }
fn array_to_point2d(val: &KclValue, source_ranges: Vec<SourceRange>) -> Result<Point2d, KclError> { fn array_to_point2d(val: &KclValue, source_ranges: Vec<SourceRange>) -> Result<Point2d, KclError> {
let KclValue::Array { value: arr, meta } = val else { let KclValue::MixedArray { value: arr, meta } = val else {
return Err(KclError::Semantic(KclErrorDetails { return Err(KclError::Semantic(KclErrorDetails {
message: "Expected an array of 2 numbers (i.e. a 2D point)".to_string(), message: "Expected an array of 2 numbers (i.e. a 2D point)".to_string(),
source_ranges, source_ranges,
@ -662,7 +662,7 @@ mod tests {
#[test] #[test]
fn test_array_to_point3d() { fn test_array_to_point3d() {
let input = KclValue::Array { let input = KclValue::MixedArray {
value: vec![ value: vec![
KclValue::Number { KclValue::Number {
value: 1.1, value: 1.1,

View File

@ -1,9 +1,10 @@
#![allow(dead_code)]
mod ast_node; mod ast_node;
mod ast_visitor; mod ast_visitor;
mod ast_walk; mod ast_walk;
mod import_graph; mod import_graph;
pub use ast_node::Node; pub use ast_node::Node;
pub use ast_visitor::{Visitable, Visitor}; pub use ast_visitor::Visitable;
pub use ast_walk::walk; pub use ast_walk::walk;
pub use import_graph::import_graph;

View File

@ -1,10 +1,10 @@
--- ---
source: kcl/src/simulation_tests.rs source: kcl-lib/src/simulation_tests.rs
description: Variables in memory after executing array_elem_pop.kcl description: Variables in memory after executing array_elem_pop.kcl
--- ---
{ {
"arr": { "arr": {
"type": "Array", "type": "MixedArray",
"value": [ "value": [
{ {
"type": "Number", "type": "Number",
@ -84,7 +84,7 @@ description: Variables in memory after executing array_elem_pop.kcl
] ]
}, },
"new_arr1": { "new_arr1": {
"type": "Array", "type": "MixedArray",
"value": [ "value": [
{ {
"type": "Number", "type": "Number",
@ -142,7 +142,7 @@ description: Variables in memory after executing array_elem_pop.kcl
] ]
}, },
"new_arr2": { "new_arr2": {
"type": "Array", "type": "MixedArray",
"value": [ "value": [
{ {
"type": "Number", "type": "Number",
@ -178,7 +178,7 @@ description: Variables in memory after executing array_elem_pop.kcl
] ]
}, },
"new_arr3": { "new_arr3": {
"type": "Array", "type": "MixedArray",
"value": [], "value": [],
"__meta": [ "__meta": [
{ {

View File

@ -1,10 +1,10 @@
--- ---
source: kcl/src/simulation_tests.rs source: kcl-lib/src/simulation_tests.rs
description: Variables in memory after executing array_elem_push.kcl description: Variables in memory after executing array_elem_push.kcl
--- ---
{ {
"arr": { "arr": {
"type": "Array", "type": "MixedArray",
"value": [ "value": [
{ {
"type": "Number", "type": "Number",
@ -84,7 +84,7 @@ description: Variables in memory after executing array_elem_push.kcl
] ]
}, },
"new_arr1": { "new_arr1": {
"type": "Array", "type": "MixedArray",
"value": [ "value": [
{ {
"type": "Number", "type": "Number",
@ -186,7 +186,7 @@ description: Variables in memory after executing array_elem_push.kcl
] ]
}, },
"new_arr2": { "new_arr2": {
"type": "Array", "type": "MixedArray",
"value": [ "value": [
{ {
"type": "Number", "type": "Number",

View File

@ -1,5 +1,5 @@
--- ---
source: kcl/src/simulation_tests.rs source: kcl-lib/src/simulation_tests.rs
description: Variables in memory after executing array_range_expr.kcl description: Variables in memory after executing array_range_expr.kcl
--- ---
{ {
@ -48,7 +48,7 @@ description: Variables in memory after executing array_range_expr.kcl
] ]
}, },
"r1": { "r1": {
"type": "Array", "type": "MixedArray",
"value": [ "value": [
{ {
"type": "Number", "type": "Number",
@ -147,7 +147,7 @@ description: Variables in memory after executing array_range_expr.kcl
] ]
}, },
"r2": { "r2": {
"type": "Array", "type": "MixedArray",
"value": [ "value": [
{ {
"type": "Number", "type": "Number",
@ -246,7 +246,7 @@ description: Variables in memory after executing array_range_expr.kcl
] ]
}, },
"r3": { "r3": {
"type": "Array", "type": "MixedArray",
"value": [ "value": [
{ {
"type": "Number", "type": "Number",
@ -362,7 +362,7 @@ description: Variables in memory after executing array_range_expr.kcl
] ]
}, },
"r4": { "r4": {
"type": "Array", "type": "MixedArray",
"value": [ "value": [
{ {
"type": "Number", "type": "Number",

View File

@ -1,10 +1,10 @@
--- ---
source: kcl/src/simulation_tests.rs source: kcl-lib/src/simulation_tests.rs
description: Variables in memory after executing array_range_negative_expr.kcl description: Variables in memory after executing array_range_negative_expr.kcl
--- ---
{ {
"xs": { "xs": {
"type": "Array", "type": "MixedArray",
"value": [ "value": [
{ {
"type": "Number", "type": "Number",

View File

@ -1,10 +1,10 @@
--- ---
source: kcl/src/simulation_tests.rs source: kcl-lib/src/simulation_tests.rs
description: Variables in memory after executing computed_var.kcl description: Variables in memory after executing computed_var.kcl
--- ---
{ {
"arr": { "arr": {
"type": "Array", "type": "MixedArray",
"value": [ "value": [
{ {
"type": "Number", "type": "Number",

View File

@ -1,5 +1,5 @@
--- ---
source: kcl/src/simulation_tests.rs source: kcl-lib/src/simulation_tests.rs
description: Variables in memory after executing double_map_fn.kcl description: Variables in memory after executing double_map_fn.kcl
--- ---
{ {
@ -16,7 +16,7 @@ description: Variables in memory after executing double_map_fn.kcl
] ]
}, },
"xs": { "xs": {
"type": "Array", "type": "MixedArray",
"value": [ "value": [
{ {
"type": "Number", "type": "Number",
@ -81,7 +81,7 @@ description: Variables in memory after executing double_map_fn.kcl
] ]
}, },
"ys": { "ys": {
"type": "Array", "type": "MixedArray",
"value": [ "value": [
{ {
"type": "Number", "type": "Number",

View File

@ -736,7 +736,7 @@ description: Variables in memory after executing i_shape.kcl
] ]
}, },
"d_wrist_circumference": { "d_wrist_circumference": {
"type": "Array", "type": "MixedArray",
"value": [ "value": [
{ {
"type": "Number", "type": "Number",

View File

@ -1,10 +1,10 @@
--- ---
source: kcl/src/simulation_tests.rs source: kcl-lib/src/simulation_tests.rs
description: Variables in memory after executing index_of_array.kcl description: Variables in memory after executing index_of_array.kcl
--- ---
{ {
"arr": { "arr": {
"type": "Array", "type": "MixedArray",
"value": [ "value": [
{ {
"type": "Number", "type": "Number",

View File

@ -1,5 +1,5 @@
--- ---
source: kcl/src/simulation_tests.rs source: kcl-lib/src/simulation_tests.rs
description: Variables in memory after executing dodecahedron.kcl description: Variables in memory after executing dodecahedron.kcl
--- ---
{ {
@ -2419,7 +2419,7 @@ description: Variables in memory after executing dodecahedron.kcl
"type": "Object", "type": "Object",
"value": { "value": {
"origin": { "origin": {
"type": "Array", "type": "MixedArray",
"value": [ "value": [
{ {
"type": "Number", "type": "Number",
@ -2536,7 +2536,7 @@ description: Variables in memory after executing dodecahedron.kcl
] ]
}, },
"xAxis": { "xAxis": {
"type": "Array", "type": "MixedArray",
"value": [ "value": [
{ {
"type": "Number", "type": "Number",
@ -2606,7 +2606,7 @@ description: Variables in memory after executing dodecahedron.kcl
] ]
}, },
"yAxis": { "yAxis": {
"type": "Array", "type": "MixedArray",
"value": [ "value": [
{ {
"type": "Number", "type": "Number",
@ -2686,7 +2686,7 @@ description: Variables in memory after executing dodecahedron.kcl
] ]
}, },
"zAxis": { "zAxis": {
"type": "Array", "type": "MixedArray",
"value": [ "value": [
{ {
"type": "Number", "type": "Number",

View File

@ -1,5 +1,5 @@
--- ---
source: kcl/src/simulation_tests.rs source: kcl-lib/src/simulation_tests.rs
description: Variables in memory after executing food-service-spatula.kcl description: Variables in memory after executing food-service-spatula.kcl
--- ---
{ {
@ -3461,7 +3461,7 @@ description: Variables in memory after executing food-service-spatula.kcl
"type": "Object", "type": "Object",
"value": { "value": {
"origin": { "origin": {
"type": "Array", "type": "MixedArray",
"value": [ "value": [
{ {
"type": "Number", "type": "Number",
@ -3541,7 +3541,7 @@ description: Variables in memory after executing food-service-spatula.kcl
] ]
}, },
"xAxis": { "xAxis": {
"type": "Array", "type": "MixedArray",
"value": [ "value": [
{ {
"type": "Number", "type": "Number",
@ -3621,7 +3621,7 @@ description: Variables in memory after executing food-service-spatula.kcl
] ]
}, },
"yAxis": { "yAxis": {
"type": "Array", "type": "MixedArray",
"value": [ "value": [
{ {
"type": "Number", "type": "Number",
@ -3701,7 +3701,7 @@ description: Variables in memory after executing food-service-spatula.kcl
] ]
}, },
"zAxis": { "zAxis": {
"type": "Array", "type": "MixedArray",
"value": [ "value": [
{ {
"type": "Number", "type": "Number",

View File

@ -1,5 +1,5 @@
--- ---
source: kcl/src/simulation_tests.rs source: kcl-lib/src/simulation_tests.rs
description: Variables in memory after executing french-press.kcl description: Variables in memory after executing french-press.kcl
--- ---
{ {
@ -5839,7 +5839,7 @@ description: Variables in memory after executing french-press.kcl
"type": "Object", "type": "Object",
"value": { "value": {
"origin": { "origin": {
"type": "Array", "type": "MixedArray",
"value": [ "value": [
{ {
"type": "Number", "type": "Number",
@ -5919,7 +5919,7 @@ description: Variables in memory after executing french-press.kcl
] ]
}, },
"xAxis": { "xAxis": {
"type": "Array", "type": "MixedArray",
"value": [ "value": [
{ {
"type": "Number", "type": "Number",
@ -5999,7 +5999,7 @@ description: Variables in memory after executing french-press.kcl
] ]
}, },
"yAxis": { "yAxis": {
"type": "Array", "type": "MixedArray",
"value": [ "value": [
{ {
"type": "Number", "type": "Number",
@ -6079,7 +6079,7 @@ description: Variables in memory after executing french-press.kcl
] ]
}, },
"zAxis": { "zAxis": {
"type": "Array", "type": "MixedArray",
"value": [ "value": [
{ {
"type": "Number", "type": "Number",

View File

@ -1,5 +1,5 @@
--- ---
source: kcl/src/simulation_tests.rs source: kcl-lib/src/simulation_tests.rs
description: Variables in memory after executing gear.kcl description: Variables in memory after executing gear.kcl
--- ---
{ {
@ -26,7 +26,7 @@ description: Variables in memory after executing gear.kcl
] ]
}, },
"angles": { "angles": {
"type": "Array", "type": "MixedArray",
"value": [ "value": [
{ {
"type": "Number", "type": "Number",
@ -1950,7 +1950,7 @@ description: Variables in memory after executing gear.kcl
] ]
}, },
"invas": { "invas": {
"type": "Array", "type": "MixedArray",
"value": [ "value": [
{ {
"type": "Number", "type": "Number",
@ -4896,7 +4896,7 @@ description: Variables in memory after executing gear.kcl
] ]
}, },
"rs": { "rs": {
"type": "Array", "type": "MixedArray",
"value": [ "value": [
{ {
"type": "Number", "type": "Number",
@ -116597,7 +116597,7 @@ description: Variables in memory after executing gear.kcl
] ]
}, },
"xs": { "xs": {
"type": "Array", "type": "MixedArray",
"value": [ "value": [
{ {
"type": "Number", "type": "Number",
@ -128239,7 +128239,7 @@ description: Variables in memory after executing gear.kcl
] ]
}, },
"ys": { "ys": {
"type": "Array", "type": "MixedArray",
"value": [ "value": [
{ {
"type": "Number", "type": "Number",

View File

@ -1,5 +1,5 @@
--- ---
source: kcl/src/simulation_tests.rs source: kcl-lib/src/simulation_tests.rs
description: Variables in memory after executing gridfinity-baseplate-magnets.kcl description: Variables in memory after executing gridfinity-baseplate-magnets.kcl
--- ---
{ {
@ -10,7 +10,7 @@ description: Variables in memory after executing gridfinity-baseplate-magnets.kc
"type": "Object", "type": "Object",
"value": { "value": {
"axis": { "axis": {
"type": "Array", "type": "MixedArray",
"value": [ "value": [
{ {
"type": "Number", "type": "Number",
@ -68,7 +68,7 @@ description: Variables in memory after executing gridfinity-baseplate-magnets.kc
] ]
}, },
"origin": { "origin": {
"type": "Array", "type": "MixedArray",
"value": [ "value": [
{ {
"type": "Number", "type": "Number",

View File

@ -1,5 +1,5 @@
--- ---
source: kcl/src/simulation_tests.rs source: kcl-lib/src/simulation_tests.rs
description: Variables in memory after executing gridfinity-baseplate.kcl description: Variables in memory after executing gridfinity-baseplate.kcl
--- ---
{ {
@ -10,7 +10,7 @@ description: Variables in memory after executing gridfinity-baseplate.kcl
"type": "Object", "type": "Object",
"value": { "value": {
"axis": { "axis": {
"type": "Array", "type": "MixedArray",
"value": [ "value": [
{ {
"type": "Number", "type": "Number",
@ -68,7 +68,7 @@ description: Variables in memory after executing gridfinity-baseplate.kcl
] ]
}, },
"origin": { "origin": {
"type": "Array", "type": "MixedArray",
"value": [ "value": [
{ {
"type": "Number", "type": "Number",

View File

@ -1,5 +1,5 @@
--- ---
source: kcl/src/simulation_tests.rs source: kcl-lib/src/simulation_tests.rs
description: Variables in memory after executing gridfinity-bins-stacking-lip.kcl description: Variables in memory after executing gridfinity-bins-stacking-lip.kcl
--- ---
{ {
@ -79,7 +79,7 @@ description: Variables in memory after executing gridfinity-bins-stacking-lip.kc
"type": "Object", "type": "Object",
"value": { "value": {
"axis": { "axis": {
"type": "Array", "type": "MixedArray",
"value": [ "value": [
{ {
"type": "Number", "type": "Number",
@ -137,7 +137,7 @@ description: Variables in memory after executing gridfinity-bins-stacking-lip.kc
] ]
}, },
"origin": { "origin": {
"type": "Array", "type": "MixedArray",
"value": [ "value": [
{ {
"type": "Number", "type": "Number",
@ -237,7 +237,7 @@ description: Variables in memory after executing gridfinity-bins-stacking-lip.kc
"type": "Object", "type": "Object",
"value": { "value": {
"axis": { "axis": {
"type": "Array", "type": "MixedArray",
"value": [ "value": [
{ {
"type": "Number", "type": "Number",
@ -295,7 +295,7 @@ description: Variables in memory after executing gridfinity-bins-stacking-lip.kc
] ]
}, },
"origin": { "origin": {
"type": "Array", "type": "MixedArray",
"value": [ "value": [
{ {
"type": "Number", "type": "Number",
@ -30147,7 +30147,7 @@ description: Variables in memory after executing gridfinity-bins-stacking-lip.kc
"type": "Object", "type": "Object",
"value": { "value": {
"origin": { "origin": {
"type": "Array", "type": "MixedArray",
"value": [ "value": [
{ {
"type": "Number", "type": "Number",
@ -30249,7 +30249,7 @@ description: Variables in memory after executing gridfinity-bins-stacking-lip.kc
] ]
}, },
"xAxis": { "xAxis": {
"type": "Array", "type": "MixedArray",
"value": [ "value": [
{ {
"type": "Number", "type": "Number",
@ -30329,7 +30329,7 @@ description: Variables in memory after executing gridfinity-bins-stacking-lip.kc
] ]
}, },
"yAxis": { "yAxis": {
"type": "Array", "type": "MixedArray",
"value": [ "value": [
{ {
"type": "Number", "type": "Number",
@ -30409,7 +30409,7 @@ description: Variables in memory after executing gridfinity-bins-stacking-lip.kc
] ]
}, },
"zAxis": { "zAxis": {
"type": "Array", "type": "MixedArray",
"value": [ "value": [
{ {
"type": "Number", "type": "Number",
@ -30517,7 +30517,7 @@ description: Variables in memory after executing gridfinity-bins-stacking-lip.kc
"type": "Object", "type": "Object",
"value": { "value": {
"origin": { "origin": {
"type": "Array", "type": "MixedArray",
"value": [ "value": [
{ {
"type": "Number", "type": "Number",
@ -30619,7 +30619,7 @@ description: Variables in memory after executing gridfinity-bins-stacking-lip.kc
] ]
}, },
"xAxis": { "xAxis": {
"type": "Array", "type": "MixedArray",
"value": [ "value": [
{ {
"type": "Number", "type": "Number",
@ -30699,7 +30699,7 @@ description: Variables in memory after executing gridfinity-bins-stacking-lip.kc
] ]
}, },
"yAxis": { "yAxis": {
"type": "Array", "type": "MixedArray",
"value": [ "value": [
{ {
"type": "Number", "type": "Number",
@ -30779,7 +30779,7 @@ description: Variables in memory after executing gridfinity-bins-stacking-lip.kc
] ]
}, },
"zAxis": { "zAxis": {
"type": "Array", "type": "MixedArray",
"value": [ "value": [
{ {
"type": "Number", "type": "Number",
@ -30887,7 +30887,7 @@ description: Variables in memory after executing gridfinity-bins-stacking-lip.kc
"type": "Object", "type": "Object",
"value": { "value": {
"origin": { "origin": {
"type": "Array", "type": "MixedArray",
"value": [ "value": [
{ {
"type": "Number", "type": "Number",
@ -31011,7 +31011,7 @@ description: Variables in memory after executing gridfinity-bins-stacking-lip.kc
] ]
}, },
"xAxis": { "xAxis": {
"type": "Array", "type": "MixedArray",
"value": [ "value": [
{ {
"type": "Number", "type": "Number",
@ -31091,7 +31091,7 @@ description: Variables in memory after executing gridfinity-bins-stacking-lip.kc
] ]
}, },
"yAxis": { "yAxis": {
"type": "Array", "type": "MixedArray",
"value": [ "value": [
{ {
"type": "Number", "type": "Number",
@ -31171,7 +31171,7 @@ description: Variables in memory after executing gridfinity-bins-stacking-lip.kc
] ]
}, },
"zAxis": { "zAxis": {
"type": "Array", "type": "MixedArray",
"value": [ "value": [
{ {
"type": "Number", "type": "Number",

View File

@ -1,5 +1,5 @@
--- ---
source: kcl/src/simulation_tests.rs source: kcl-lib/src/simulation_tests.rs
description: Variables in memory after executing gridfinity-bins.kcl description: Variables in memory after executing gridfinity-bins.kcl
--- ---
{ {
@ -10,7 +10,7 @@ description: Variables in memory after executing gridfinity-bins.kcl
"type": "Object", "type": "Object",
"value": { "value": {
"axis": { "axis": {
"type": "Array", "type": "MixedArray",
"value": [ "value": [
{ {
"type": "Number", "type": "Number",
@ -68,7 +68,7 @@ description: Variables in memory after executing gridfinity-bins.kcl
] ]
}, },
"origin": { "origin": {
"type": "Array", "type": "MixedArray",
"value": [ "value": [
{ {
"type": "Number", "type": "Number",

View File

@ -1,5 +1,5 @@
--- ---
source: kcl/src/simulation_tests.rs source: kcl-lib/src/simulation_tests.rs
description: Variables in memory after executing pipe-flange-assembly.kcl description: Variables in memory after executing pipe-flange-assembly.kcl
--- ---
{ {
@ -3475,7 +3475,7 @@ description: Variables in memory after executing pipe-flange-assembly.kcl
] ]
}, },
"screwStart": { "screwStart": {
"type": "Array", "type": "MixedArray",
"value": [ "value": [
{ {
"type": "Number", "type": "Number",

View File

@ -68,13 +68,11 @@ pub async fn execute_mock(
path: Option<String>, path: Option<String>,
settings: &str, settings: &str,
use_prev_memory: bool, use_prev_memory: bool,
variables: &str,
fs_manager: kcl_lib::wasm_engine::FileSystemManager, fs_manager: kcl_lib::wasm_engine::FileSystemManager,
) -> Result<JsValue, String> { ) -> Result<JsValue, String> {
console_error_panic_hook::set_once(); console_error_panic_hook::set_once();
let program: Program = serde_json::from_str(program_ast_json).map_err(|e| e.to_string())?; let program: Program = serde_json::from_str(program_ast_json).map_err(|e| e.to_string())?;
let variables = serde_json::from_str(variables).map_err(|e| e.to_string())?;
let config: kcl_lib::Configuration = serde_json::from_str(settings).map_err(|e| e.to_string())?; let config: kcl_lib::Configuration = serde_json::from_str(settings).map_err(|e| e.to_string())?;
let mut settings: kcl_lib::ExecutorSettings = config.into(); let mut settings: kcl_lib::ExecutorSettings = config.into();
if let Some(path) = path { if let Some(path) = path {
@ -82,7 +80,7 @@ pub async fn execute_mock(
} }
let ctx = kcl_lib::ExecutorContext::new_mock(fs_manager, settings.into()).await?; let ctx = kcl_lib::ExecutorContext::new_mock(fs_manager, settings.into()).await?;
match ctx.run_mock(program, use_prev_memory, variables).await { match ctx.run_mock(program, use_prev_memory).await {
// The serde-wasm-bindgen does not work here because of weird HashMap issues. // The serde-wasm-bindgen does not work here because of weird HashMap issues.
// DO NOT USE serde_wasm_bindgen::to_value it will break the frontend. // DO NOT USE serde_wasm_bindgen::to_value it will break the frontend.
Ok(outcome) => JsValue::from_serde(&outcome).map_err(|e| e.to_string()), Ok(outcome) => JsValue::from_serde(&outcome).map_err(|e| e.to_string()),

View File

@ -1,17 +1,10 @@
import { useEffect, useState, useRef } from 'react' import { BinaryPart } from '../lang/wasm'
import { parse, BinaryPart, Expr, resultIsOk, VariableMap } from '../lang/wasm'
import { import {
createIdentifier, createIdentifier,
createLiteral, createLiteral,
createUnaryExpression, createUnaryExpression,
findUniqueName,
} from '../lang/modifyAst' } from '../lang/modifyAst'
import { findAllPreviousVariables, PrevVariable } from '../lang/queryAst' import { PrevVariable } from '../lang/queryAst'
import { engineCommandManager, kclManager } from 'lib/singletons'
import { useKclContext } from 'lang/KclProvider'
import { useModelingContext } from 'hooks/useModelingContext'
import { executeAst } from 'lang/langHelpers'
import { trap } from 'lib/trap'
export const AvailableVars = ({ export const AvailableVars = ({
onVarClick, onVarClick,
@ -77,119 +70,6 @@ function stringSplice(str: string, index: number, count: number, add: string) {
return str.slice(0, index) + (add || '') + str.slice(index + count) return str.slice(0, index) + (add || '') + str.slice(index + count)
} }
// what a terriable name
export function useCalc({
value,
initialVariableName: valueName = '',
}: {
value: string
initialVariableName?: string
}): {
inputRef: React.RefObject<HTMLInputElement>
valueNode: Expr | null
calcResult: string
prevVariables: PrevVariable<unknown>[]
newVariableName: string
isNewVariableNameUnique: boolean
newVariableInsertIndex: number
setNewVariableName: (a: string) => void
} {
const { variables } = useKclContext()
const { context } = useModelingContext()
const selectionRange =
context.selectionRanges?.graphSelections[0]?.codeRef?.range
const inputRef = useRef<HTMLInputElement>(null)
const [availableVarInfo, setAvailableVarInfo] = useState<
ReturnType<typeof findAllPreviousVariables>
>({
variables: [],
insertIndex: 0,
bodyPath: [],
})
const [valueNode, setValueNode] = useState<Expr | null>(null)
const [calcResult, setCalcResult] = useState('NAN')
const [newVariableName, setNewVariableName] = useState('')
const [isNewVariableNameUnique, setIsNewVariableNameUnique] = useState(true)
useEffect(() => {
setTimeout(() => {
inputRef.current && inputRef.current.focus()
inputRef.current &&
inputRef.current.setSelectionRange(0, String(value).length)
}, 100)
setNewVariableName(findUniqueName(kclManager.ast, valueName))
}, [])
useEffect(() => {
if (variables[newVariableName]) {
setIsNewVariableNameUnique(false)
} else {
setIsNewVariableNameUnique(true)
}
}, [newVariableName])
useEffect(() => {
if (!variables || !selectionRange) return
const varInfo = findAllPreviousVariables(
kclManager.ast,
kclManager.variables,
selectionRange
)
setAvailableVarInfo(varInfo)
}, [kclManager.ast, kclManager.variables, selectionRange])
useEffect(() => {
try {
const code = `const __result__ = ${value}`
const pResult = parse(code)
if (trap(pResult) || !resultIsOk(pResult)) return
const ast = pResult.program
const _variables: VariableMap = {}
for (const { key, value } of availableVarInfo.variables) {
const error = (_variables[key] = {
type: 'String',
value,
__meta: [],
})
if (trap(error)) return
}
// eslint-disable-next-line @typescript-eslint/no-floating-promises
executeAst({
ast,
engineCommandManager,
isMock: true,
variables,
}).then(({ execState }) => {
const resultDeclaration = ast.body.find(
(a) =>
a.type === 'VariableDeclaration' &&
a.declaration.id?.name === '__result__'
)
const init =
resultDeclaration?.type === 'VariableDeclaration' &&
resultDeclaration?.declaration.init
const result = execState.variables['__result__']?.value
setCalcResult(typeof result === 'number' ? String(result) : 'NAN')
init && setValueNode(init)
})
} catch (e) {
setCalcResult('NAN')
setValueNode(null)
}
}, [value, availableVarInfo])
return {
valueNode,
calcResult,
prevVariables: availableVarInfo.variables,
newVariableInsertIndex: availableVarInfo.insertIndex,
newVariableName,
isNewVariableNameUnique,
setNewVariableName,
inputRef,
}
}
export const CalcResult = ({ calcResult }: { calcResult: string }) => { export const CalcResult = ({ calcResult }: { calcResult: string }) => {
return ( return (
<div className="font-[monospace] pl-4 text-gray-600"> <div className="font-[monospace] pl-4 text-gray-600">

View File

@ -254,7 +254,7 @@ const newVar = myVar + 1`
], ],
}) })
expect(mem['yo']).toEqual({ expect(mem['yo']).toEqual({
type: 'Array', type: 'MixedArray',
value: [ value: [
{ {
type: 'Number', type: 'Number',
@ -520,9 +520,9 @@ const theExtrude = startSketchOn('XY')
// helpers // helpers
async function exe(code: string, variables: VariableMap = {}) { async function exe(code: string) {
const ast = assertParse(code) const ast = assertParse(code)
const execState = await enginelessExecutor(ast, true, undefined, variables) const execState = await enginelessExecutor(ast, true, undefined)
return execState.variables return execState.variables
} }

View File

@ -52,14 +52,12 @@ export async function executeAst({
engineCommandManager, engineCommandManager,
isMock, isMock,
usePrevMemory, usePrevMemory,
variables,
}: { }: {
ast: Node<Program> ast: Node<Program>
path?: string path?: string
engineCommandManager: EngineCommandManager engineCommandManager: EngineCommandManager
isMock: boolean isMock: boolean
usePrevMemory?: boolean usePrevMemory?: boolean
variables?: VariableMap
isInterrupted?: boolean isInterrupted?: boolean
}): Promise<{ }): Promise<{
logs: string[] logs: string[]
@ -69,7 +67,7 @@ export async function executeAst({
}> { }> {
try { try {
const execState = await (isMock const execState = await (isMock
? executeMock(ast, usePrevMemory, path, variables) ? executeMock(ast, usePrevMemory, path)
: executeWithEngine(ast, engineCommandManager, path)) : executeWithEngine(ast, engineCommandManager, path))
await engineCommandManager.waitForAllCommands() await engineCommandManager.waitForAllCommands()

View File

@ -418,13 +418,9 @@ export function sketchFromKclValue(
export const executeMock = async ( export const executeMock = async (
node: Node<Program>, node: Node<Program>,
usePrevMemory?: boolean, usePrevMemory?: boolean,
path?: string, path?: string
variables?: { [key in string]?: KclValue }
): Promise<ExecState> => { ): Promise<ExecState> => {
try { try {
if (!variables) {
variables = {}
}
if (usePrevMemory === undefined) { if (usePrevMemory === undefined) {
usePrevMemory = true usePrevMemory = true
} }
@ -433,7 +429,6 @@ export const executeMock = async (
path, path,
JSON.stringify({ settings: await jsAppSettings() }), JSON.stringify({ settings: await jsAppSettings() }),
usePrevMemory, usePrevMemory,
JSON.stringify(variables),
fileSystemManager fileSystemManager
) )
return mockExecStateFromRust(execOutcome) return mockExecStateFromRust(execOutcome)

View File

@ -3,58 +3,16 @@ import { getCalculatedKclExpressionValue } from './kclHelpers'
describe('KCL expression calculations', () => { describe('KCL expression calculations', () => {
it('calculates a simple expression', async () => { it('calculates a simple expression', async () => {
const actual = await getCalculatedKclExpressionValue('1 + 2', {}) const actual = await getCalculatedKclExpressionValue('1 + 2')
const coercedActual = actual as Exclude<typeof actual, Error | ParseResult> const coercedActual = actual as Exclude<typeof actual, Error | ParseResult>
expect(coercedActual).not.toHaveProperty('errors') expect(coercedActual).not.toHaveProperty('errors')
expect(coercedActual.valueAsString).toEqual('3') expect(coercedActual.valueAsString).toEqual('3')
expect(coercedActual?.astNode).toBeDefined() expect(coercedActual?.astNode).toBeDefined()
}) })
it('calculates a simple expression with a variable', async () => {
const variables: VariableMap = {}
variables['x'] = {
type: 'Number',
value: 2,
ty: { type: 'Any' },
__meta: [],
}
const actual = await getCalculatedKclExpressionValue('1 + x', variables)
const coercedActual = actual as Exclude<typeof actual, Error | ParseResult>
expect(coercedActual.valueAsString).toEqual('3')
expect(coercedActual.astNode).toBeDefined()
})
it('returns NAN for an invalid expression', async () => { it('returns NAN for an invalid expression', async () => {
const actual = await getCalculatedKclExpressionValue('1 + x', {}) const actual = await getCalculatedKclExpressionValue('1 + x')
const coercedActual = actual as Exclude<typeof actual, Error | ParseResult> const coercedActual = actual as Exclude<typeof actual, Error | ParseResult>
expect(coercedActual.valueAsString).toEqual('NAN') expect(coercedActual.valueAsString).toEqual('NAN')
expect(coercedActual.astNode).toBeDefined() expect(coercedActual.astNode).toBeDefined()
}) })
it('returns NAN for an expression with an invalid variable', async () => {
const variables: VariableMap = {}
variables['y'] = {
type: 'Number',
value: 2,
ty: { type: 'Any' },
__meta: [],
}
const actual = await getCalculatedKclExpressionValue('1 + x', variables)
const coercedActual = actual as Exclude<typeof actual, Error | ParseResult>
expect(coercedActual.valueAsString).toEqual('NAN')
expect(coercedActual.astNode).toBeDefined()
})
it('calculates a more complex expression with a variable', async () => {
const variables: VariableMap = {}
variables['x'] = {
type: 'Number',
value: 2,
ty: { type: 'Any' },
__meta: [],
}
const actual = await getCalculatedKclExpressionValue(
'(1 + x * x) * 2',
variables
)
const coercedActual = actual as Exclude<typeof actual, Error | ParseResult>
expect(coercedActual.valueAsString).toEqual('10')
expect(coercedActual.astNode).toBeDefined()
})
}) })

View File

@ -9,12 +9,9 @@ const DUMMY_VARIABLE_NAME = '__result__'
/** /**
* Calculate the value of the KCL expression, * Calculate the value of the KCL expression,
* given the value and the variables that are available * given the value and the variables that are available in memory.
*/ */
export async function getCalculatedKclExpressionValue( export async function getCalculatedKclExpressionValue(value: string) {
value: string,
variables: VariableMap
) {
// Create a one-line program that assigns the value to a variable // Create a one-line program that assigns the value to a variable
const dummyProgramCode = `const ${DUMMY_VARIABLE_NAME} = ${value}` const dummyProgramCode = `const ${DUMMY_VARIABLE_NAME} = ${value}`
const pResult = parse(dummyProgramCode) const pResult = parse(dummyProgramCode)
@ -26,7 +23,6 @@ export async function getCalculatedKclExpressionValue(
ast, ast,
engineCommandManager, engineCommandManager,
isMock: true, isMock: true,
variables,
}) })
// Find the variable declaration for the result // Find the variable declaration for the result
@ -47,14 +43,8 @@ export async function getCalculatedKclExpressionValue(
} }
} }
export async function stringToKclExpression( export async function stringToKclExpression(value: string) {
value: string, const calculatedResult = await getCalculatedKclExpressionValue(value)
variables: VariableMap
) {
const calculatedResult = await getCalculatedKclExpressionValue(
value,
variables
)
if (err(calculatedResult) || 'errors' in calculatedResult) { if (err(calculatedResult) || 'errors' in calculatedResult) {
return calculatedResult return calculatedResult
} else if (!calculatedResult.astNode) { } else if (!calculatedResult.astNode) {

View File

@ -85,8 +85,7 @@ const prepareToEditExtrude: PrepareToEditCallback =
codeManager.code.slice( codeManager.code.slice(
operation.labeledArgs?.['length']?.sourceRange[0], operation.labeledArgs?.['length']?.sourceRange[0],
operation.labeledArgs?.['length']?.sourceRange[1] operation.labeledArgs?.['length']?.sourceRange[1]
), )
{}
) )
if (err(distanceResult) || 'errors' in distanceResult) { if (err(distanceResult) || 'errors' in distanceResult) {
return baseCommand return baseCommand
@ -165,8 +164,7 @@ const prepareToEditOffsetPlane: PrepareToEditCallback = async ({
codeManager.code.slice( codeManager.code.slice(
operation.labeledArgs.offset.sourceRange[0], operation.labeledArgs.offset.sourceRange[0],
operation.labeledArgs.offset.sourceRange[1] operation.labeledArgs.offset.sourceRange[1]
), )
{}
) )
if (err(distanceResult) || 'errors' in distanceResult) { if (err(distanceResult) || 'errors' in distanceResult) {
@ -211,8 +209,7 @@ const prepareToEditHelix: PrepareToEditCallback = async ({ operation }) => {
codeManager.code.slice( codeManager.code.slice(
operation.labeledArgs.revolutions.sourceRange[0], operation.labeledArgs.revolutions.sourceRange[0],
operation.labeledArgs.revolutions.sourceRange[1] operation.labeledArgs.revolutions.sourceRange[1]
), )
{}
) )
if (err(revolutions) || 'errors' in revolutions) return baseCommand if (err(revolutions) || 'errors' in revolutions) return baseCommand
@ -226,8 +223,7 @@ const prepareToEditHelix: PrepareToEditCallback = async ({ operation }) => {
codeManager.code.slice( codeManager.code.slice(
operation.labeledArgs.angleStart.sourceRange[0], operation.labeledArgs.angleStart.sourceRange[0],
operation.labeledArgs.angleStart.sourceRange[1] operation.labeledArgs.angleStart.sourceRange[1]
), )
{}
) )
if (err(angleStart) || 'errors' in angleStart) return baseCommand if (err(angleStart) || 'errors' in angleStart) return baseCommand
@ -250,8 +246,7 @@ const prepareToEditHelix: PrepareToEditCallback = async ({ operation }) => {
codeManager.code.slice( codeManager.code.slice(
operation.labeledArgs.radius.sourceRange[0], operation.labeledArgs.radius.sourceRange[0],
operation.labeledArgs.radius.sourceRange[1] operation.labeledArgs.radius.sourceRange[1]
), )
{}
) )
if (err(radius) || 'errors' in radius) return baseCommand if (err(radius) || 'errors' in radius) return baseCommand
@ -272,8 +267,7 @@ const prepareToEditHelix: PrepareToEditCallback = async ({ operation }) => {
codeManager.code.slice( codeManager.code.slice(
operation.labeledArgs.length.sourceRange[0], operation.labeledArgs.length.sourceRange[0],
operation.labeledArgs.length.sourceRange[1] operation.labeledArgs.length.sourceRange[1]
), )
{}
) )
if (err(length) || 'errors' in length) return baseCommand if (err(length) || 'errors' in length) return baseCommand

View File

@ -81,8 +81,7 @@ class MockEngineCommandManager {
export async function enginelessExecutor( export async function enginelessExecutor(
ast: Node<Program>, ast: Node<Program>,
usePrevMemory?: boolean, usePrevMemory?: boolean,
path?: string, path?: string
variables?: VariableMap
): Promise<ExecState> { ): Promise<ExecState> {
return await executeMock(ast, usePrevMemory, path, variables) return await executeMock(ast, usePrevMemory, path)
} }

View File

@ -100,7 +100,7 @@ export function useCalculateKclExpression({
useEffect(() => { useEffect(() => {
const execAstAndSetResult = async () => { const execAstAndSetResult = async () => {
const result = await getCalculatedKclExpressionValue(value, {}) const result = await getCalculatedKclExpressionValue(value)
if (result instanceof Error || 'errors' in result) { if (result instanceof Error || 'errors' in result) {
setCalcResult('NAN') setCalcResult('NAN')
setValueNode(null) setValueNode(null)