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

View File

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

View File

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

View File

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

View File

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

View File

@ -687,14 +687,6 @@ impl Stack {
.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.
/// Return Err if not found.
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);
}
/// 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.
fn snapshot_contains_key(&self, key: &str, snapshot: SnapshotRef) -> bool {
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]
fn squash_env() {
let mem = &mut Stack::new_for_tests();
@ -1641,6 +1565,7 @@ mod test {
KclValue::Function {
value: FunctionSource::User {
ast: crate::parsing::ast::types::FunctionExpression::dummy(),
settings: crate::MetaSettings::default(),
memory: sn2,
},
meta: Vec::new(),

View File

@ -55,7 +55,7 @@ mod memory;
mod state;
/// 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)]
#[serde(rename_all = "camelCase")]
pub struct ExecOutcome {
@ -517,7 +517,6 @@ impl ExecutorContext {
&self,
program: crate::Program,
use_prev_memory: bool,
variables: IndexMap<String, KclValue>,
) -> Result<ExecOutcome, KclErrorWithOutputs> {
assert!(self.is_mock());
@ -531,22 +530,9 @@ impl ExecutorContext {
self.prepare_mem(&mut exec_state).await?
};
let mut to_restore = Vec::new();
{
let mem = exec_state.mut_stack();
// 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)?;
}
}
exec_state.mut_stack().push_new_env_for_scope();
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);
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;
Ok(outcome)
@ -1885,33 +1865,6 @@ let w = f() + f()
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")]
async fn mock_after_not_mock() {
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 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);
}
}

View File

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

View File

@ -341,7 +341,7 @@ impl Args {
meta: vec![meta],
ty: NumericType::Unknown,
};
Ok(KclValue::Array {
Ok(KclValue::MixedArray {
value: vec![x, y],
meta: vec![meta],
})
@ -377,7 +377,7 @@ impl Args {
ty: ty.clone(),
})
.collect::<Vec<_>>();
Ok(KclValue::Array {
Ok(KclValue::MixedArray {
value: array,
meta: vec![Metadata {
source_range: self.source_range,
@ -631,7 +631,7 @@ impl<'a> FromArgs<'a> for Vec<KclValue> {
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());
return Err(KclError::Type(KclErrorDetails {
source_ranges: arg.source_ranges(),
@ -733,7 +733,7 @@ where
impl<'a> FromKclValue<'a> for [f64; 2] {
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;
};
if value.len() != 2 {
@ -748,7 +748,7 @@ impl<'a> FromKclValue<'a> for [f64; 2] {
impl<'a> FromKclValue<'a> for [usize; 3] {
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;
};
if value.len() != 3 {
@ -764,7 +764,7 @@ impl<'a> FromKclValue<'a> for [usize; 3] {
impl<'a> FromKclValue<'a> for [f64; 3] {
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;
};
if value.len() != 3 {
@ -1249,7 +1249,7 @@ impl_from_kcl_for_vec!(Sketch);
impl<'a> FromKclValue<'a> for SourceRange {
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;
};
if value.len() != 3 {
@ -1517,7 +1517,7 @@ impl<'a> FromKclValue<'a> for SketchSet {
match arg {
KclValue::Sketch { value: sketch } => Some(SketchSet::from(sketch.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);
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 meta = vec![args.source_range.into()];
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.
@ -230,7 +230,7 @@ async fn call_reduce_closure(
async fn inner_push(mut array: Vec<KclValue>, elem: KclValue, args: &Args) -> Result<KclValue, KclError> {
// Unwrap the KclValues to JValues for manipulation
array.push(elem);
Ok(KclValue::Array {
Ok(KclValue::MixedArray {
value: array,
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 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();
return Err(KclError::Semantic(KclErrorDetails {
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
let new_array = array[..array.len() - 1].to_vec();
Ok(KclValue::Array {
Ok(KclValue::MixedArray {
value: new_array,
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 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();
return Err(KclError::Semantic(KclErrorDetails {
source_ranges: meta,

View File

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

View File

@ -1,9 +1,10 @@
#![allow(dead_code)]
mod ast_node;
mod ast_visitor;
mod ast_walk;
mod import_graph;
pub use ast_node::Node;
pub use ast_visitor::{Visitable, Visitor};
pub use ast_visitor::Visitable;
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
---
{
"arr": {
"type": "Array",
"type": "MixedArray",
"value": [
{
"type": "Number",
@ -84,7 +84,7 @@ description: Variables in memory after executing array_elem_pop.kcl
]
},
"new_arr1": {
"type": "Array",
"type": "MixedArray",
"value": [
{
"type": "Number",
@ -142,7 +142,7 @@ description: Variables in memory after executing array_elem_pop.kcl
]
},
"new_arr2": {
"type": "Array",
"type": "MixedArray",
"value": [
{
"type": "Number",
@ -178,7 +178,7 @@ description: Variables in memory after executing array_elem_pop.kcl
]
},
"new_arr3": {
"type": "Array",
"type": "MixedArray",
"value": [],
"__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
---
{
"arr": {
"type": "Array",
"type": "MixedArray",
"value": [
{
"type": "Number",
@ -84,7 +84,7 @@ description: Variables in memory after executing array_elem_push.kcl
]
},
"new_arr1": {
"type": "Array",
"type": "MixedArray",
"value": [
{
"type": "Number",
@ -186,7 +186,7 @@ description: Variables in memory after executing array_elem_push.kcl
]
},
"new_arr2": {
"type": "Array",
"type": "MixedArray",
"value": [
{
"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
---
{
@ -48,7 +48,7 @@ description: Variables in memory after executing array_range_expr.kcl
]
},
"r1": {
"type": "Array",
"type": "MixedArray",
"value": [
{
"type": "Number",
@ -147,7 +147,7 @@ description: Variables in memory after executing array_range_expr.kcl
]
},
"r2": {
"type": "Array",
"type": "MixedArray",
"value": [
{
"type": "Number",
@ -246,7 +246,7 @@ description: Variables in memory after executing array_range_expr.kcl
]
},
"r3": {
"type": "Array",
"type": "MixedArray",
"value": [
{
"type": "Number",
@ -362,7 +362,7 @@ description: Variables in memory after executing array_range_expr.kcl
]
},
"r4": {
"type": "Array",
"type": "MixedArray",
"value": [
{
"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
---
{
"xs": {
"type": "Array",
"type": "MixedArray",
"value": [
{
"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
---
{
"arr": {
"type": "Array",
"type": "MixedArray",
"value": [
{
"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
---
{
@ -16,7 +16,7 @@ description: Variables in memory after executing double_map_fn.kcl
]
},
"xs": {
"type": "Array",
"type": "MixedArray",
"value": [
{
"type": "Number",
@ -81,7 +81,7 @@ description: Variables in memory after executing double_map_fn.kcl
]
},
"ys": {
"type": "Array",
"type": "MixedArray",
"value": [
{
"type": "Number",

View File

@ -736,7 +736,7 @@ description: Variables in memory after executing i_shape.kcl
]
},
"d_wrist_circumference": {
"type": "Array",
"type": "MixedArray",
"value": [
{
"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
---
{
"arr": {
"type": "Array",
"type": "MixedArray",
"value": [
{
"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
---
{
@ -2419,7 +2419,7 @@ description: Variables in memory after executing dodecahedron.kcl
"type": "Object",
"value": {
"origin": {
"type": "Array",
"type": "MixedArray",
"value": [
{
"type": "Number",
@ -2536,7 +2536,7 @@ description: Variables in memory after executing dodecahedron.kcl
]
},
"xAxis": {
"type": "Array",
"type": "MixedArray",
"value": [
{
"type": "Number",
@ -2606,7 +2606,7 @@ description: Variables in memory after executing dodecahedron.kcl
]
},
"yAxis": {
"type": "Array",
"type": "MixedArray",
"value": [
{
"type": "Number",
@ -2686,7 +2686,7 @@ description: Variables in memory after executing dodecahedron.kcl
]
},
"zAxis": {
"type": "Array",
"type": "MixedArray",
"value": [
{
"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
---
{
@ -3461,7 +3461,7 @@ description: Variables in memory after executing food-service-spatula.kcl
"type": "Object",
"value": {
"origin": {
"type": "Array",
"type": "MixedArray",
"value": [
{
"type": "Number",
@ -3541,7 +3541,7 @@ description: Variables in memory after executing food-service-spatula.kcl
]
},
"xAxis": {
"type": "Array",
"type": "MixedArray",
"value": [
{
"type": "Number",
@ -3621,7 +3621,7 @@ description: Variables in memory after executing food-service-spatula.kcl
]
},
"yAxis": {
"type": "Array",
"type": "MixedArray",
"value": [
{
"type": "Number",
@ -3701,7 +3701,7 @@ description: Variables in memory after executing food-service-spatula.kcl
]
},
"zAxis": {
"type": "Array",
"type": "MixedArray",
"value": [
{
"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
---
{
@ -5839,7 +5839,7 @@ description: Variables in memory after executing french-press.kcl
"type": "Object",
"value": {
"origin": {
"type": "Array",
"type": "MixedArray",
"value": [
{
"type": "Number",
@ -5919,7 +5919,7 @@ description: Variables in memory after executing french-press.kcl
]
},
"xAxis": {
"type": "Array",
"type": "MixedArray",
"value": [
{
"type": "Number",
@ -5999,7 +5999,7 @@ description: Variables in memory after executing french-press.kcl
]
},
"yAxis": {
"type": "Array",
"type": "MixedArray",
"value": [
{
"type": "Number",
@ -6079,7 +6079,7 @@ description: Variables in memory after executing french-press.kcl
]
},
"zAxis": {
"type": "Array",
"type": "MixedArray",
"value": [
{
"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
---
{
@ -26,7 +26,7 @@ description: Variables in memory after executing gear.kcl
]
},
"angles": {
"type": "Array",
"type": "MixedArray",
"value": [
{
"type": "Number",
@ -1950,7 +1950,7 @@ description: Variables in memory after executing gear.kcl
]
},
"invas": {
"type": "Array",
"type": "MixedArray",
"value": [
{
"type": "Number",
@ -4896,7 +4896,7 @@ description: Variables in memory after executing gear.kcl
]
},
"rs": {
"type": "Array",
"type": "MixedArray",
"value": [
{
"type": "Number",
@ -116597,7 +116597,7 @@ description: Variables in memory after executing gear.kcl
]
},
"xs": {
"type": "Array",
"type": "MixedArray",
"value": [
{
"type": "Number",
@ -128239,7 +128239,7 @@ description: Variables in memory after executing gear.kcl
]
},
"ys": {
"type": "Array",
"type": "MixedArray",
"value": [
{
"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
---
{
@ -10,7 +10,7 @@ description: Variables in memory after executing gridfinity-baseplate-magnets.kc
"type": "Object",
"value": {
"axis": {
"type": "Array",
"type": "MixedArray",
"value": [
{
"type": "Number",
@ -68,7 +68,7 @@ description: Variables in memory after executing gridfinity-baseplate-magnets.kc
]
},
"origin": {
"type": "Array",
"type": "MixedArray",
"value": [
{
"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
---
{
@ -10,7 +10,7 @@ description: Variables in memory after executing gridfinity-baseplate.kcl
"type": "Object",
"value": {
"axis": {
"type": "Array",
"type": "MixedArray",
"value": [
{
"type": "Number",
@ -68,7 +68,7 @@ description: Variables in memory after executing gridfinity-baseplate.kcl
]
},
"origin": {
"type": "Array",
"type": "MixedArray",
"value": [
{
"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
---
{
@ -79,7 +79,7 @@ description: Variables in memory after executing gridfinity-bins-stacking-lip.kc
"type": "Object",
"value": {
"axis": {
"type": "Array",
"type": "MixedArray",
"value": [
{
"type": "Number",
@ -137,7 +137,7 @@ description: Variables in memory after executing gridfinity-bins-stacking-lip.kc
]
},
"origin": {
"type": "Array",
"type": "MixedArray",
"value": [
{
"type": "Number",
@ -237,7 +237,7 @@ description: Variables in memory after executing gridfinity-bins-stacking-lip.kc
"type": "Object",
"value": {
"axis": {
"type": "Array",
"type": "MixedArray",
"value": [
{
"type": "Number",
@ -295,7 +295,7 @@ description: Variables in memory after executing gridfinity-bins-stacking-lip.kc
]
},
"origin": {
"type": "Array",
"type": "MixedArray",
"value": [
{
"type": "Number",
@ -30147,7 +30147,7 @@ description: Variables in memory after executing gridfinity-bins-stacking-lip.kc
"type": "Object",
"value": {
"origin": {
"type": "Array",
"type": "MixedArray",
"value": [
{
"type": "Number",
@ -30249,7 +30249,7 @@ description: Variables in memory after executing gridfinity-bins-stacking-lip.kc
]
},
"xAxis": {
"type": "Array",
"type": "MixedArray",
"value": [
{
"type": "Number",
@ -30329,7 +30329,7 @@ description: Variables in memory after executing gridfinity-bins-stacking-lip.kc
]
},
"yAxis": {
"type": "Array",
"type": "MixedArray",
"value": [
{
"type": "Number",
@ -30409,7 +30409,7 @@ description: Variables in memory after executing gridfinity-bins-stacking-lip.kc
]
},
"zAxis": {
"type": "Array",
"type": "MixedArray",
"value": [
{
"type": "Number",
@ -30517,7 +30517,7 @@ description: Variables in memory after executing gridfinity-bins-stacking-lip.kc
"type": "Object",
"value": {
"origin": {
"type": "Array",
"type": "MixedArray",
"value": [
{
"type": "Number",
@ -30619,7 +30619,7 @@ description: Variables in memory after executing gridfinity-bins-stacking-lip.kc
]
},
"xAxis": {
"type": "Array",
"type": "MixedArray",
"value": [
{
"type": "Number",
@ -30699,7 +30699,7 @@ description: Variables in memory after executing gridfinity-bins-stacking-lip.kc
]
},
"yAxis": {
"type": "Array",
"type": "MixedArray",
"value": [
{
"type": "Number",
@ -30779,7 +30779,7 @@ description: Variables in memory after executing gridfinity-bins-stacking-lip.kc
]
},
"zAxis": {
"type": "Array",
"type": "MixedArray",
"value": [
{
"type": "Number",
@ -30887,7 +30887,7 @@ description: Variables in memory after executing gridfinity-bins-stacking-lip.kc
"type": "Object",
"value": {
"origin": {
"type": "Array",
"type": "MixedArray",
"value": [
{
"type": "Number",
@ -31011,7 +31011,7 @@ description: Variables in memory after executing gridfinity-bins-stacking-lip.kc
]
},
"xAxis": {
"type": "Array",
"type": "MixedArray",
"value": [
{
"type": "Number",
@ -31091,7 +31091,7 @@ description: Variables in memory after executing gridfinity-bins-stacking-lip.kc
]
},
"yAxis": {
"type": "Array",
"type": "MixedArray",
"value": [
{
"type": "Number",
@ -31171,7 +31171,7 @@ description: Variables in memory after executing gridfinity-bins-stacking-lip.kc
]
},
"zAxis": {
"type": "Array",
"type": "MixedArray",
"value": [
{
"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
---
{
@ -10,7 +10,7 @@ description: Variables in memory after executing gridfinity-bins.kcl
"type": "Object",
"value": {
"axis": {
"type": "Array",
"type": "MixedArray",
"value": [
{
"type": "Number",
@ -68,7 +68,7 @@ description: Variables in memory after executing gridfinity-bins.kcl
]
},
"origin": {
"type": "Array",
"type": "MixedArray",
"value": [
{
"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
---
{
@ -3475,7 +3475,7 @@ description: Variables in memory after executing pipe-flange-assembly.kcl
]
},
"screwStart": {
"type": "Array",
"type": "MixedArray",
"value": [
{
"type": "Number",

View File

@ -68,13 +68,11 @@ pub async fn execute_mock(
path: Option<String>,
settings: &str,
use_prev_memory: bool,
variables: &str,
fs_manager: kcl_lib::wasm_engine::FileSystemManager,
) -> Result<JsValue, String> {
console_error_panic_hook::set_once();
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 mut settings: kcl_lib::ExecutorSettings = config.into();
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?;
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.
// 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()),

View File

@ -1,17 +1,10 @@
import { useEffect, useState, useRef } from 'react'
import { parse, BinaryPart, Expr, resultIsOk, VariableMap } from '../lang/wasm'
import { BinaryPart } from '../lang/wasm'
import {
createIdentifier,
createLiteral,
createUnaryExpression,
findUniqueName,
} from '../lang/modifyAst'
import { findAllPreviousVariables, 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'
import { PrevVariable } from '../lang/queryAst'
export const AvailableVars = ({
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)
}
// 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 }) => {
return (
<div className="font-[monospace] pl-4 text-gray-600">

View File

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

View File

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

View File

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

View File

@ -3,58 +3,16 @@ import { getCalculatedKclExpressionValue } from './kclHelpers'
describe('KCL expression calculations', () => {
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>
expect(coercedActual).not.toHaveProperty('errors')
expect(coercedActual.valueAsString).toEqual('3')
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 () => {
const actual = await getCalculatedKclExpressionValue('1 + x', {})
const actual = await getCalculatedKclExpressionValue('1 + x')
const coercedActual = actual as Exclude<typeof actual, Error | ParseResult>
expect(coercedActual.valueAsString).toEqual('NAN')
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,
* given the value and the variables that are available
* given the value and the variables that are available in memory.
*/
export async function getCalculatedKclExpressionValue(
value: string,
variables: VariableMap
) {
export async function getCalculatedKclExpressionValue(value: string) {
// Create a one-line program that assigns the value to a variable
const dummyProgramCode = `const ${DUMMY_VARIABLE_NAME} = ${value}`
const pResult = parse(dummyProgramCode)
@ -26,7 +23,6 @@ export async function getCalculatedKclExpressionValue(
ast,
engineCommandManager,
isMock: true,
variables,
})
// Find the variable declaration for the result
@ -47,14 +43,8 @@ export async function getCalculatedKclExpressionValue(
}
}
export async function stringToKclExpression(
value: string,
variables: VariableMap
) {
const calculatedResult = await getCalculatedKclExpressionValue(
value,
variables
)
export async function stringToKclExpression(value: string) {
const calculatedResult = await getCalculatedKclExpressionValue(value)
if (err(calculatedResult) || 'errors' in calculatedResult) {
return calculatedResult
} else if (!calculatedResult.astNode) {

View File

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

View File

@ -81,8 +81,7 @@ class MockEngineCommandManager {
export async function enginelessExecutor(
ast: Node<Program>,
usePrevMemory?: boolean,
path?: string,
variables?: VariableMap
path?: string
): 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(() => {
const execAstAndSetResult = async () => {
const result = await getCalculatedKclExpressionValue(value, {})
const result = await getCalculatedKclExpressionValue(value)
if (result instanceof Error || 'errors' in result) {
setCalcResult('NAN')
setValueNode(null)