Make memory accessible from multiple threads/tasks (#5530)
Signed-off-by: Nick Cameron <nrc@ncameron.org>
This commit is contained in:
@ -5,7 +5,7 @@ version = "0.2.45"
|
|||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
repository = "https://github.com/KittyCAD/modeling-app"
|
repository = "https://github.com/KittyCAD/modeling-app"
|
||||||
rust-version = "1.73"
|
rust-version = "1.83"
|
||||||
authors = ["Jess Frazelle", "Adam Chalmers", "KittyCAD, Inc"]
|
authors = ["Jess Frazelle", "Adam Chalmers", "KittyCAD, Inc"]
|
||||||
keywords = ["kcl", "KittyCAD", "CAD"]
|
keywords = ["kcl", "KittyCAD", "CAD"]
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
@ -6,7 +6,7 @@ use itertools::{EitherOrBoth, Itertools};
|
|||||||
use tokio::sync::RwLock;
|
use tokio::sync::RwLock;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
execution::{annotations, memory::ProgramMemory, EnvironmentRef, ExecState, ExecutorSettings},
|
execution::{annotations, memory::Stack, EnvironmentRef, ExecState, ExecutorSettings},
|
||||||
parsing::ast::types::{Annotation, Node, Program},
|
parsing::ast::types::{Annotation, Node, Program},
|
||||||
walk::Node as WalkNode,
|
walk::Node as WalkNode,
|
||||||
};
|
};
|
||||||
@ -15,7 +15,7 @@ lazy_static::lazy_static! {
|
|||||||
/// A static mutable lock for updating the last successful execution state for the cache.
|
/// A static mutable lock for updating the last successful execution state for the cache.
|
||||||
static ref OLD_AST: Arc<RwLock<Option<OldAstState>>> = Default::default();
|
static ref OLD_AST: Arc<RwLock<Option<OldAstState>>> = Default::default();
|
||||||
// The last successful run's memory. Not cleared after an unssuccessful run.
|
// The last successful run's memory. Not cleared after an unssuccessful run.
|
||||||
static ref PREV_MEMORY: Arc<RwLock<Option<ProgramMemory>>> = Default::default();
|
static ref PREV_MEMORY: Arc<RwLock<Option<Stack>>> = Default::default();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Read the old ast memory from the lock.
|
/// Read the old ast memory from the lock.
|
||||||
@ -29,12 +29,12 @@ pub(super) async fn write_old_ast(old_state: OldAstState) {
|
|||||||
*old_ast = Some(old_state);
|
*old_ast = Some(old_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async fn read_old_memory() -> Option<ProgramMemory> {
|
pub(crate) async fn read_old_memory() -> Option<Stack> {
|
||||||
let old_mem = PREV_MEMORY.read().await;
|
let old_mem = PREV_MEMORY.read().await;
|
||||||
old_mem.clone()
|
old_mem.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) async fn write_old_memory(mem: ProgramMemory) {
|
pub(super) async fn write_old_memory(mem: Stack) {
|
||||||
let mut old_mem = PREV_MEMORY.write().await;
|
let mut old_mem = PREV_MEMORY.write().await;
|
||||||
*old_mem = Some(mem);
|
*old_mem = Some(mem);
|
||||||
}
|
}
|
||||||
|
@ -96,19 +96,22 @@ impl ExecutorContext {
|
|||||||
preserve_mem: bool,
|
preserve_mem: bool,
|
||||||
path: &ModulePath,
|
path: &ModulePath,
|
||||||
) -> Result<(Option<KclValue>, EnvironmentRef, Vec<String>), KclError> {
|
) -> Result<(Option<KclValue>, EnvironmentRef, Vec<String>), KclError> {
|
||||||
crate::log::log(format!("enter module {path}"));
|
crate::log::log(format!("enter module {path} {}", exec_state.stack()));
|
||||||
|
|
||||||
let old_units = exec_state.length_unit();
|
let old_units = exec_state.length_unit();
|
||||||
let original_execution = self.engine.replace_execution_kind(exec_kind).await;
|
let original_execution = self.engine.replace_execution_kind(exec_kind).await;
|
||||||
let mut local_state = ModuleState::new(&self.settings, path.std_path());
|
|
||||||
|
let mut local_state = ModuleState::new(&self.settings, path.std_path(), exec_state.stack().memory.clone());
|
||||||
|
if !preserve_mem {
|
||||||
std::mem::swap(&mut exec_state.mod_local, &mut local_state);
|
std::mem::swap(&mut exec_state.mod_local, &mut local_state);
|
||||||
|
}
|
||||||
|
|
||||||
let no_prelude = self
|
let no_prelude = self
|
||||||
.handle_annotations(program.inner_attrs.iter(), crate::execution::BodyType::Root, exec_state)
|
.handle_annotations(program.inner_attrs.iter(), crate::execution::BodyType::Root, exec_state)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
if !preserve_mem {
|
if !preserve_mem {
|
||||||
exec_state.mut_memory().push_new_root_env(!no_prelude);
|
exec_state.mut_stack().push_new_root_env(!no_prelude);
|
||||||
}
|
}
|
||||||
|
|
||||||
let result = self
|
let result = self
|
||||||
@ -117,11 +120,13 @@ impl ExecutorContext {
|
|||||||
|
|
||||||
let new_units = exec_state.length_unit();
|
let new_units = exec_state.length_unit();
|
||||||
let env_ref = if preserve_mem {
|
let env_ref = if preserve_mem {
|
||||||
exec_state.mut_memory().pop_and_preserve_env()
|
exec_state.mut_stack().pop_and_preserve_env()
|
||||||
} else {
|
} else {
|
||||||
exec_state.mut_memory().pop_env()
|
exec_state.mut_stack().pop_env()
|
||||||
};
|
};
|
||||||
|
if !preserve_mem {
|
||||||
std::mem::swap(&mut exec_state.mod_local, &mut local_state);
|
std::mem::swap(&mut exec_state.mod_local, &mut local_state);
|
||||||
|
}
|
||||||
|
|
||||||
// We only need to reset the units if we are not on the Main path.
|
// We only need to reset the units if we are not on the Main path.
|
||||||
// If we reset at the end of the main path, then we just add on an extra
|
// If we reset at the end of the main path, then we just add on an extra
|
||||||
@ -171,8 +176,9 @@ impl ExecutorContext {
|
|||||||
for import_item in items {
|
for import_item in items {
|
||||||
// Extract the item from the module.
|
// Extract the item from the module.
|
||||||
let item = exec_state
|
let item = exec_state
|
||||||
.memory()
|
.stack()
|
||||||
.get_from(&import_item.name.name, env_ref, import_item.into())
|
.memory
|
||||||
|
.get_from(&import_item.name.name, env_ref, import_item.into(), 0)
|
||||||
.map_err(|_err| {
|
.map_err(|_err| {
|
||||||
KclError::UndefinedValue(KclErrorDetails {
|
KclError::UndefinedValue(KclErrorDetails {
|
||||||
message: format!("{} is not defined in module", import_item.name.name),
|
message: format!("{} is not defined in module", import_item.name.name),
|
||||||
@ -192,7 +198,7 @@ impl ExecutorContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add the item to the current module.
|
// Add the item to the current module.
|
||||||
exec_state.mut_memory().add(
|
exec_state.mut_stack().add(
|
||||||
import_item.identifier().to_owned(),
|
import_item.identifier().to_owned(),
|
||||||
item,
|
item,
|
||||||
SourceRange::from(&import_item.name),
|
SourceRange::from(&import_item.name),
|
||||||
@ -212,8 +218,9 @@ impl ExecutorContext {
|
|||||||
.await?;
|
.await?;
|
||||||
for name in module_exports.iter() {
|
for name in module_exports.iter() {
|
||||||
let item = exec_state
|
let item = exec_state
|
||||||
.memory()
|
.stack()
|
||||||
.get_from(name, env_ref, source_range)
|
.memory
|
||||||
|
.get_from(name, env_ref, source_range, 0)
|
||||||
.map_err(|_err| {
|
.map_err(|_err| {
|
||||||
KclError::Internal(KclErrorDetails {
|
KclError::Internal(KclErrorDetails {
|
||||||
message: format!("{} is not defined in module (but was exported?)", name),
|
message: format!("{} is not defined in module (but was exported?)", name),
|
||||||
@ -221,7 +228,7 @@ impl ExecutorContext {
|
|||||||
})
|
})
|
||||||
})?
|
})?
|
||||||
.clone();
|
.clone();
|
||||||
exec_state.mut_memory().add(name.to_owned(), item, source_range)?;
|
exec_state.mut_stack().add(name.to_owned(), item, source_range)?;
|
||||||
|
|
||||||
if let ItemVisibility::Export = import_stmt.visibility {
|
if let ItemVisibility::Export = import_stmt.visibility {
|
||||||
exec_state.mod_local.module_exports.push(name.clone());
|
exec_state.mod_local.module_exports.push(name.clone());
|
||||||
@ -234,7 +241,7 @@ impl ExecutorContext {
|
|||||||
value: module_id,
|
value: module_id,
|
||||||
meta: vec![source_range.into()],
|
meta: vec![source_range.into()],
|
||||||
};
|
};
|
||||||
exec_state.mut_memory().add(name, item, source_range)?;
|
exec_state.mut_stack().add(name, item, source_range)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
last_expr = None;
|
last_expr = None;
|
||||||
@ -269,7 +276,7 @@ impl ExecutorContext {
|
|||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
exec_state
|
exec_state
|
||||||
.mut_memory()
|
.mut_stack()
|
||||||
.add(var_name.clone(), memory_item, source_range)?;
|
.add(var_name.clone(), memory_item, source_range)?;
|
||||||
|
|
||||||
// Track exports.
|
// Track exports.
|
||||||
@ -298,7 +305,7 @@ impl ExecutorContext {
|
|||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
exec_state
|
exec_state
|
||||||
.mut_memory()
|
.mut_stack()
|
||||||
.add(memory::RETURN_NAME.to_owned(), value, metadata.source_range)
|
.add(memory::RETURN_NAME.to_owned(), value, metadata.source_range)
|
||||||
.map_err(|_| {
|
.map_err(|_| {
|
||||||
KclError::Semantic(KclErrorDetails {
|
KclError::Semantic(KclErrorDetails {
|
||||||
@ -488,7 +495,7 @@ impl ExecutorContext {
|
|||||||
Expr::Literal(literal) => KclValue::from_literal((**literal).clone(), &exec_state.mod_local.settings),
|
Expr::Literal(literal) => KclValue::from_literal((**literal).clone(), &exec_state.mod_local.settings),
|
||||||
Expr::TagDeclarator(tag) => tag.execute(exec_state).await?,
|
Expr::TagDeclarator(tag) => tag.execute(exec_state).await?,
|
||||||
Expr::Identifier(identifier) => {
|
Expr::Identifier(identifier) => {
|
||||||
let value = exec_state.memory().get(&identifier.name, identifier.into())?.clone();
|
let value = exec_state.stack().get(&identifier.name, identifier.into())?.clone();
|
||||||
if let KclValue::Module { value: module_id, meta } = value {
|
if let KclValue::Module { value: module_id, meta } = value {
|
||||||
self.exec_module_for_result(module_id, exec_state, ExecutionKind::Normal, metadata.source_range)
|
self.exec_module_for_result(module_id, exec_state, ExecutionKind::Normal, metadata.source_range)
|
||||||
.await?
|
.await?
|
||||||
@ -549,7 +556,7 @@ impl ExecutorContext {
|
|||||||
KclValue::Function {
|
KclValue::Function {
|
||||||
value: FunctionSource::User {
|
value: FunctionSource::User {
|
||||||
ast: function_expression.clone(),
|
ast: function_expression.clone(),
|
||||||
memory: exec_state.mut_memory().snapshot(),
|
memory: exec_state.mut_stack().snapshot(),
|
||||||
},
|
},
|
||||||
meta: vec![metadata.to_owned()],
|
meta: vec![metadata.to_owned()],
|
||||||
}
|
}
|
||||||
@ -590,7 +597,7 @@ impl ExecutorContext {
|
|||||||
.execute_expr(&expr.expr, exec_state, metadata, &[], statement_kind)
|
.execute_expr(&expr.expr, exec_state, metadata, &[], statement_kind)
|
||||||
.await?;
|
.await?;
|
||||||
exec_state
|
exec_state
|
||||||
.mut_memory()
|
.mut_stack()
|
||||||
.add(expr.label.name.clone(), result.clone(), init.into())?;
|
.add(expr.label.name.clone(), result.clone(), init.into())?;
|
||||||
// TODO this lets us use the label as a variable name, but not as a tag in most cases
|
// TODO this lets us use the label as a variable name, but not as a tag in most cases
|
||||||
result
|
result
|
||||||
@ -687,7 +694,7 @@ impl BinaryPart {
|
|||||||
&exec_state.mod_local.settings,
|
&exec_state.mod_local.settings,
|
||||||
)),
|
)),
|
||||||
BinaryPart::Identifier(identifier) => {
|
BinaryPart::Identifier(identifier) => {
|
||||||
let value = exec_state.memory().get(&identifier.name, identifier.into())?;
|
let value = exec_state.stack().get(&identifier.name, identifier.into())?;
|
||||||
Ok(value.clone())
|
Ok(value.clone())
|
||||||
}
|
}
|
||||||
BinaryPart::BinaryExpression(binary_expression) => binary_expression.get_result(exec_state, ctx).await,
|
BinaryPart::BinaryExpression(binary_expression) => binary_expression.get_result(exec_state, ctx).await,
|
||||||
@ -705,7 +712,7 @@ impl Node<MemberExpression> {
|
|||||||
let array = match &self.object {
|
let array = match &self.object {
|
||||||
MemberObject::MemberExpression(member_expr) => member_expr.get_result(exec_state)?,
|
MemberObject::MemberExpression(member_expr) => member_expr.get_result(exec_state)?,
|
||||||
MemberObject::Identifier(identifier) => {
|
MemberObject::Identifier(identifier) => {
|
||||||
let value = exec_state.memory().get(&identifier.name, identifier.into())?;
|
let value = exec_state.stack().get(&identifier.name, identifier.into())?;
|
||||||
value.clone()
|
value.clone()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -733,7 +740,7 @@ impl Node<MemberExpression> {
|
|||||||
// TODO: Don't use recursion here, use a loop.
|
// TODO: Don't use recursion here, use a loop.
|
||||||
MemberObject::MemberExpression(member_expr) => member_expr.get_result(exec_state)?,
|
MemberObject::MemberExpression(member_expr) => member_expr.get_result(exec_state)?,
|
||||||
MemberObject::Identifier(identifier) => {
|
MemberObject::Identifier(identifier) => {
|
||||||
let value = exec_state.memory().get(&identifier.name, identifier.into())?;
|
let value = exec_state.stack().get(&identifier.name, identifier.into())?;
|
||||||
value.clone()
|
value.clone()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -1145,7 +1152,7 @@ impl Node<CallExpressionKw> {
|
|||||||
let source_range = SourceRange::from(self);
|
let source_range = SourceRange::from(self);
|
||||||
// Clone the function so that we can use a mutable reference to
|
// Clone the function so that we can use a mutable reference to
|
||||||
// exec_state.
|
// exec_state.
|
||||||
let func = exec_state.memory().get(fn_name, source_range)?.clone();
|
let func = exec_state.stack().get(fn_name, source_range)?.clone();
|
||||||
|
|
||||||
// Track call operation.
|
// Track call operation.
|
||||||
let op_labeled_args = args
|
let op_labeled_args = args
|
||||||
@ -1256,9 +1263,9 @@ impl Node<CallExpression> {
|
|||||||
);
|
);
|
||||||
let mut return_value = {
|
let mut return_value = {
|
||||||
// Don't early-return in this block.
|
// Don't early-return in this block.
|
||||||
exec_state.mut_memory().push_new_env_for_rust_call();
|
exec_state.mut_stack().push_new_env_for_rust_call();
|
||||||
let result = func.std_lib_fn()(exec_state, args).await;
|
let result = func.std_lib_fn()(exec_state, args).await;
|
||||||
exec_state.mut_memory().pop_env();
|
exec_state.mut_stack().pop_env();
|
||||||
|
|
||||||
if let Some(mut op) = op {
|
if let Some(mut op) = op {
|
||||||
op.set_std_lib_call_is_error(result.is_err());
|
op.set_std_lib_call_is_error(result.is_err());
|
||||||
@ -1280,7 +1287,7 @@ impl Node<CallExpression> {
|
|||||||
let source_range = SourceRange::from(self);
|
let source_range = SourceRange::from(self);
|
||||||
// Clone the function so that we can use a mutable reference to
|
// Clone the function so that we can use a mutable reference to
|
||||||
// exec_state.
|
// exec_state.
|
||||||
let func = exec_state.memory().get(fn_name, source_range)?.clone();
|
let func = exec_state.stack().get(fn_name, source_range)?.clone();
|
||||||
|
|
||||||
// Track call operation.
|
// Track call operation.
|
||||||
exec_state.global.operations.push(Operation::UserDefinedFunctionCall {
|
exec_state.global.operations.push(Operation::UserDefinedFunctionCall {
|
||||||
@ -1331,7 +1338,7 @@ fn update_memory_for_tags_of_geometry(result: &mut KclValue, exec_state: &mut Ex
|
|||||||
KclValue::Sketch { value: ref mut sketch } => {
|
KclValue::Sketch { value: ref mut sketch } => {
|
||||||
for (_, tag) in sketch.tags.iter() {
|
for (_, tag) in sketch.tags.iter() {
|
||||||
exec_state
|
exec_state
|
||||||
.mut_memory()
|
.mut_stack()
|
||||||
.insert_or_update(tag.value.clone(), KclValue::TagIdentifier(Box::new(tag.clone())));
|
.insert_or_update(tag.value.clone(), KclValue::TagIdentifier(Box::new(tag.clone())));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1371,7 +1378,7 @@ fn update_memory_for_tags_of_geometry(result: &mut KclValue, exec_state: &mut Ex
|
|||||||
};
|
};
|
||||||
|
|
||||||
exec_state
|
exec_state
|
||||||
.mut_memory()
|
.mut_stack()
|
||||||
.insert_or_update(tag.name.clone(), KclValue::TagIdentifier(Box::new(tag_id.clone())));
|
.insert_or_update(tag.name.clone(), KclValue::TagIdentifier(Box::new(tag_id.clone())));
|
||||||
|
|
||||||
// update the sketch tags.
|
// update the sketch tags.
|
||||||
@ -1382,7 +1389,7 @@ fn update_memory_for_tags_of_geometry(result: &mut KclValue, exec_state: &mut Ex
|
|||||||
// Find the stale sketch in memory and update it.
|
// Find the stale sketch in memory and update it.
|
||||||
if !value.sketch.tags.is_empty() {
|
if !value.sketch.tags.is_empty() {
|
||||||
let updates: Vec<_> = exec_state
|
let updates: Vec<_> = exec_state
|
||||||
.memory()
|
.stack()
|
||||||
.find_all_in_current_env(|v| match v {
|
.find_all_in_current_env(|v| match v {
|
||||||
KclValue::Sketch { value: sk } => sk.artifact_id == value.sketch.artifact_id,
|
KclValue::Sketch { value: sk } => sk.artifact_id == value.sketch.artifact_id,
|
||||||
_ => false,
|
_ => false,
|
||||||
@ -1403,7 +1410,7 @@ fn update_memory_for_tags_of_geometry(result: &mut KclValue, exec_state: &mut Ex
|
|||||||
|
|
||||||
updates
|
updates
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.for_each(|(k, v)| exec_state.mut_memory().insert_or_update(k, v))
|
.for_each(|(k, v)| exec_state.mut_stack().insert_or_update(k, v))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
@ -1422,7 +1429,7 @@ impl Node<TagDeclarator> {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
exec_state
|
exec_state
|
||||||
.mut_memory()
|
.mut_stack()
|
||||||
.add(self.name.clone(), memory_item.clone(), self.into())?;
|
.add(self.name.clone(), memory_item.clone(), self.into())?;
|
||||||
|
|
||||||
Ok(self.into())
|
Ok(self.into())
|
||||||
@ -1628,7 +1635,7 @@ impl Property {
|
|||||||
Ok(Property::String(name.to_string()))
|
Ok(Property::String(name.to_string()))
|
||||||
} else {
|
} else {
|
||||||
// Actually evaluate memory to compute the property.
|
// Actually evaluate memory to compute the property.
|
||||||
let prop = exec_state.memory().get(name, property_src)?;
|
let prop = exec_state.stack().get(name, property_src)?;
|
||||||
jvalue_to_prop(prop, property_sr, name)
|
jvalue_to_prop(prop, property_sr, name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1725,7 +1732,7 @@ fn assign_args_to_params(
|
|||||||
return Err(err_wrong_number_args);
|
return Err(err_wrong_number_args);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mem = &mut exec_state.global.memory;
|
let mem = &mut exec_state.mod_local.stack;
|
||||||
let settings = &exec_state.mod_local.settings;
|
let settings = &exec_state.mod_local.settings;
|
||||||
|
|
||||||
// Add the arguments to the memory. A new call frame should have already
|
// Add the arguments to the memory. A new call frame should have already
|
||||||
@ -1766,7 +1773,7 @@ fn assign_args_to_params_kw(
|
|||||||
// Add the arguments to the memory. A new call frame should have already
|
// Add the arguments to the memory. A new call frame should have already
|
||||||
// been created.
|
// been created.
|
||||||
let source_ranges = vec![function_expression.into()];
|
let source_ranges = vec![function_expression.into()];
|
||||||
let mem = &mut exec_state.global.memory;
|
let mem = &mut exec_state.mod_local.stack;
|
||||||
let settings = &exec_state.mod_local.settings;
|
let settings = &exec_state.mod_local.settings;
|
||||||
|
|
||||||
for param in function_expression.params.iter() {
|
for param in function_expression.params.iter() {
|
||||||
@ -1824,9 +1831,9 @@ pub(crate) async fn call_user_defined_function(
|
|||||||
// Create a new environment to execute the function body in so that local
|
// Create a new environment to execute the function body in so that local
|
||||||
// variables shadow variables in the parent scope. The new environment's
|
// variables shadow variables in the parent scope. The new environment's
|
||||||
// parent should be the environment of the closure.
|
// parent should be the environment of the closure.
|
||||||
exec_state.mut_memory().push_new_env_for_call(memory);
|
exec_state.mut_stack().push_new_env_for_call(memory);
|
||||||
if let Err(e) = assign_args_to_params(function_expression, args, exec_state) {
|
if let Err(e) = assign_args_to_params(function_expression, args, exec_state) {
|
||||||
exec_state.mut_memory().pop_env();
|
exec_state.mut_stack().pop_env();
|
||||||
return Err(e);
|
return Err(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1836,13 +1843,13 @@ pub(crate) async fn call_user_defined_function(
|
|||||||
.await;
|
.await;
|
||||||
let result = result.map(|_| {
|
let result = result.map(|_| {
|
||||||
exec_state
|
exec_state
|
||||||
.memory()
|
.stack()
|
||||||
.get(memory::RETURN_NAME, function_expression.as_source_range())
|
.get(memory::RETURN_NAME, function_expression.as_source_range())
|
||||||
.ok()
|
.ok()
|
||||||
.cloned()
|
.cloned()
|
||||||
});
|
});
|
||||||
// Restore the previous memory.
|
// Restore the previous memory.
|
||||||
exec_state.mut_memory().pop_env();
|
exec_state.mut_stack().pop_env();
|
||||||
|
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
@ -1857,9 +1864,9 @@ pub(crate) async fn call_user_defined_function_kw(
|
|||||||
// Create a new environment to execute the function body in so that local
|
// Create a new environment to execute the function body in so that local
|
||||||
// variables shadow variables in the parent scope. The new environment's
|
// variables shadow variables in the parent scope. The new environment's
|
||||||
// parent should be the environment of the closure.
|
// parent should be the environment of the closure.
|
||||||
exec_state.mut_memory().push_new_env_for_call(memory);
|
exec_state.mut_stack().push_new_env_for_call(memory);
|
||||||
if let Err(e) = assign_args_to_params_kw(function_expression, args, exec_state) {
|
if let Err(e) = assign_args_to_params_kw(function_expression, args, exec_state) {
|
||||||
exec_state.mut_memory().pop_env();
|
exec_state.mut_stack().pop_env();
|
||||||
return Err(e);
|
return Err(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1869,13 +1876,13 @@ pub(crate) async fn call_user_defined_function_kw(
|
|||||||
.await;
|
.await;
|
||||||
let result = result.map(|_| {
|
let result = result.map(|_| {
|
||||||
exec_state
|
exec_state
|
||||||
.memory()
|
.stack()
|
||||||
.get(memory::RETURN_NAME, function_expression.as_source_range())
|
.get(memory::RETURN_NAME, function_expression.as_source_range())
|
||||||
.ok()
|
.ok()
|
||||||
.cloned()
|
.cloned()
|
||||||
});
|
});
|
||||||
// Restore the previous memory.
|
// Restore the previous memory.
|
||||||
exec_state.mut_memory().pop_env();
|
exec_state.mut_stack().pop_env();
|
||||||
|
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
@ -1920,7 +1927,7 @@ impl FunctionSource {
|
|||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::{
|
use crate::{
|
||||||
execution::{memory::ProgramMemory, parse_execute},
|
execution::{memory::Stack, parse_execute},
|
||||||
parsing::ast::types::{DefaultParamVal, Identifier, Parameter},
|
parsing::ast::types::{DefaultParamVal, Identifier, Parameter},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1958,9 +1965,8 @@ mod test {
|
|||||||
digest: None,
|
digest: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn additional_program_memory(items: &[(String, KclValue)]) -> ProgramMemory {
|
fn additional_program_memory(items: &[(String, KclValue)]) -> Stack {
|
||||||
let mut program_memory = ProgramMemory::new();
|
let mut program_memory = Stack::new_for_tests();
|
||||||
program_memory.init_for_tests();
|
|
||||||
for (name, item) in items {
|
for (name, item) in items {
|
||||||
program_memory
|
program_memory
|
||||||
.add(name.clone(), item.clone(), SourceRange::default())
|
.add(name.clone(), item.clone(), SourceRange::default())
|
||||||
@ -2038,8 +2044,8 @@ mod test {
|
|||||||
});
|
});
|
||||||
let args = args.into_iter().map(Arg::synthetic).collect();
|
let args = args.into_iter().map(Arg::synthetic).collect();
|
||||||
let mut exec_state = ExecState::new(&Default::default());
|
let mut exec_state = ExecState::new(&Default::default());
|
||||||
exec_state.mut_memory().init_for_tests();
|
exec_state.mod_local.stack = Stack::new_for_tests();
|
||||||
let actual = assign_args_to_params(func_expr, args, &mut exec_state).map(|_| exec_state.global.memory);
|
let actual = assign_args_to_params(func_expr, args, &mut exec_state).map(|_| exec_state.mod_local.stack);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
actual, expected,
|
actual, expected,
|
||||||
"failed test '{test_name}':\ngot {actual:?}\nbut expected\n{expected:?}"
|
"failed test '{test_name}':\ngot {actual:?}\nbut expected\n{expected:?}"
|
||||||
@ -2061,9 +2067,9 @@ p = {
|
|||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = parse_execute(program).await.unwrap();
|
let result = parse_execute(program).await.unwrap();
|
||||||
let mem = result.3.memory();
|
let mem = result.3.stack();
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
mem.get_from("p", result.1, SourceRange::default()).unwrap(),
|
mem.memory.get_from("p", result.1, SourceRange::default(), 0).unwrap(),
|
||||||
KclValue::Plane { .. }
|
KclValue::Plane { .. }
|
||||||
));
|
));
|
||||||
|
|
||||||
@ -2099,8 +2105,8 @@ p2 = -p
|
|||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = parse_execute(program).await.unwrap();
|
let result = parse_execute(program).await.unwrap();
|
||||||
let mem = result.3.memory();
|
let mem = result.3.stack();
|
||||||
match mem.get_from("p2", result.1, SourceRange::default()).unwrap() {
|
match mem.memory.get_from("p2", result.1, SourceRange::default(), 0).unwrap() {
|
||||||
KclValue::Plane { value } => assert_eq!(value.z_axis.z, -1.0),
|
KclValue::Plane { value } => assert_eq!(value.z_axis.z, -1.0),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
|
@ -631,7 +631,7 @@ impl KclValue {
|
|||||||
),
|
),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
exec_state.mut_memory().push_new_env_for_rust_call();
|
exec_state.mut_stack().push_new_env_for_rust_call();
|
||||||
let args = crate::std::Args::new(
|
let args = crate::std::Args::new(
|
||||||
args,
|
args,
|
||||||
source_range,
|
source_range,
|
||||||
@ -639,7 +639,7 @@ impl KclValue {
|
|||||||
exec_state.mod_local.pipe_value.clone().map(Arg::synthetic),
|
exec_state.mod_local.pipe_value.clone().map(Arg::synthetic),
|
||||||
);
|
);
|
||||||
let result = func(exec_state, args).await.map(Some);
|
let result = func(exec_state, args).await.map(Some);
|
||||||
exec_state.mut_memory().pop_env();
|
exec_state.mut_stack().pop_env();
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
KclValue::Function {
|
KclValue::Function {
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -509,7 +509,7 @@ impl ExecutorContext {
|
|||||||
self.eval_prelude(exec_state, SourceRange::synthetic())
|
self.eval_prelude(exec_state, SourceRange::synthetic())
|
||||||
.await
|
.await
|
||||||
.map_err(KclErrorWithOutputs::no_outputs)?;
|
.map_err(KclErrorWithOutputs::no_outputs)?;
|
||||||
exec_state.mut_memory().push_new_root_env(true);
|
exec_state.mut_stack().push_new_root_env(true);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -524,7 +524,7 @@ impl ExecutorContext {
|
|||||||
let mut exec_state = ExecState::new(&self.settings);
|
let mut exec_state = ExecState::new(&self.settings);
|
||||||
if use_prev_memory {
|
if use_prev_memory {
|
||||||
match cache::read_old_memory().await {
|
match cache::read_old_memory().await {
|
||||||
Some(mem) => *exec_state.mut_memory() = mem,
|
Some(mem) => *exec_state.mut_stack() = mem,
|
||||||
None => self.prepare_mem(&mut exec_state).await?,
|
None => self.prepare_mem(&mut exec_state).await?,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -533,7 +533,7 @@ impl ExecutorContext {
|
|||||||
|
|
||||||
let mut to_restore = Vec::new();
|
let mut to_restore = Vec::new();
|
||||||
{
|
{
|
||||||
let mem = exec_state.mut_memory();
|
let mem = exec_state.mut_stack();
|
||||||
|
|
||||||
// Push a scope so that old variables can be overwritten (since we might be re-executing some
|
// Push a scope so that old variables can be overwritten (since we might be re-executing some
|
||||||
// part of the scene).
|
// part of the scene).
|
||||||
@ -553,7 +553,9 @@ impl ExecutorContext {
|
|||||||
// Restore any temporary variables, then save any newly created variables back to
|
// Restore any temporary variables, then save any newly created variables back to
|
||||||
// memory in case another run wants to use them. Note this is just saved to the preserved
|
// memory in case another run wants to use them. Note this is just saved to the preserved
|
||||||
// memory, not to the exec_state which is not cached for mock execution.
|
// memory, not to the exec_state which is not cached for mock execution.
|
||||||
let mut mem = exec_state.memory().clone();
|
|
||||||
|
let mut mem = exec_state.stack().clone();
|
||||||
|
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 {
|
for (k, v) in to_restore {
|
||||||
@ -564,7 +566,6 @@ impl ExecutorContext {
|
|||||||
}
|
}
|
||||||
cache::write_old_memory(mem).await;
|
cache::write_old_memory(mem).await;
|
||||||
|
|
||||||
let outcome = exec_state.to_mock_wasm_outcome(result.0);
|
|
||||||
Ok(outcome)
|
Ok(outcome)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -628,11 +629,15 @@ impl ExecutorContext {
|
|||||||
})
|
})
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
return Ok(old_state.to_wasm_outcome(result_env));
|
let outcome = old_state.to_wasm_outcome(result_env);
|
||||||
|
return Ok(outcome);
|
||||||
}
|
}
|
||||||
(true, program)
|
(true, program)
|
||||||
}
|
}
|
||||||
CacheResult::NoAction(false) => return Ok(old_state.to_wasm_outcome(result_env)),
|
CacheResult::NoAction(false) => {
|
||||||
|
let outcome = old_state.to_wasm_outcome(result_env);
|
||||||
|
return Ok(outcome);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let (exec_state, preserve_mem) = if clear_scene {
|
let (exec_state, preserve_mem) = if clear_scene {
|
||||||
@ -650,7 +655,7 @@ impl ExecutorContext {
|
|||||||
|
|
||||||
(exec_state, false)
|
(exec_state, false)
|
||||||
} else {
|
} else {
|
||||||
old_state.mut_memory().restore_env(result_env);
|
old_state.mut_stack().restore_env(result_env);
|
||||||
old_state.add_root_module_contents(&program);
|
old_state.add_root_module_contents(&program);
|
||||||
|
|
||||||
(old_state, true)
|
(old_state, true)
|
||||||
@ -684,7 +689,8 @@ impl ExecutorContext {
|
|||||||
})
|
})
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
Ok(exec_state.to_wasm_outcome(result.0))
|
let outcome = exec_state.to_wasm_outcome(result.0);
|
||||||
|
Ok(outcome)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Perform the execution of a program.
|
/// Perform the execution of a program.
|
||||||
@ -759,16 +765,16 @@ impl ExecutorContext {
|
|||||||
)
|
)
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
|
crate::log::log(format!(
|
||||||
|
"Post interpretation KCL memory stats: {:#?}",
|
||||||
|
exec_state.stack().memory.stats
|
||||||
|
));
|
||||||
|
|
||||||
if !self.is_mock() {
|
if !self.is_mock() {
|
||||||
let mut mem = exec_state.memory().clone();
|
let mut mem = exec_state.stack().deep_clone();
|
||||||
mem.restore_env(env_ref);
|
mem.restore_env(env_ref);
|
||||||
cache::write_old_memory(mem).await;
|
cache::write_old_memory(mem).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
crate::log::log(format!(
|
|
||||||
"Post interpretation KCL memory stats: {:#?}",
|
|
||||||
exec_state.memory().stats
|
|
||||||
));
|
|
||||||
let session_data = self.engine.get_session_data().await;
|
let session_data = self.engine.get_session_data().await;
|
||||||
Ok((env_ref, session_data))
|
Ok((env_ref, session_data))
|
||||||
}
|
}
|
||||||
@ -826,8 +832,10 @@ impl ExecutorContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// 'Import' std::prelude as the outermost scope.
|
/// 'Import' std::prelude as the outermost scope.
|
||||||
|
///
|
||||||
|
/// SAFETY: the current thread must have sole access to the memory referenced in exec_state.
|
||||||
async fn eval_prelude(&self, exec_state: &mut ExecState, source_range: SourceRange) -> Result<(), KclError> {
|
async fn eval_prelude(&self, exec_state: &mut ExecState, source_range: SourceRange) -> Result<(), KclError> {
|
||||||
if exec_state.memory().requires_std() {
|
if exec_state.stack().memory.requires_std() {
|
||||||
let id = self
|
let id = self
|
||||||
.open_module(
|
.open_module(
|
||||||
&ImportPath::Std {
|
&ImportPath::Std {
|
||||||
@ -843,7 +851,7 @@ impl ExecutorContext {
|
|||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
exec_state.mut_memory().set_std(module_memory);
|
exec_state.mut_stack().memory.set_std(module_memory);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -930,12 +938,16 @@ mod tests {
|
|||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::{errors::KclErrorDetails, execution::memory::ProgramMemory, ModuleId};
|
use crate::{errors::KclErrorDetails, execution::memory::Stack, ModuleId};
|
||||||
|
|
||||||
/// Convenience function to get a JSON value from memory and unwrap.
|
/// Convenience function to get a JSON value from memory and unwrap.
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn mem_get_json(memory: &ProgramMemory, env: EnvironmentRef, name: &str) -> KclValue {
|
fn mem_get_json(memory: &Stack, env: EnvironmentRef, name: &str) -> KclValue {
|
||||||
memory.get_from(name, env, SourceRange::default()).unwrap().to_owned()
|
memory
|
||||||
|
.memory
|
||||||
|
.get_from_unchecked(name, env, SourceRange::default())
|
||||||
|
.unwrap()
|
||||||
|
.to_owned()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
@ -1400,21 +1412,21 @@ let shape = layer() |> patternTransform(instances = 10, transform = transform)
|
|||||||
async fn test_math_execute_with_functions() {
|
async fn test_math_execute_with_functions() {
|
||||||
let ast = r#"const myVar = 2 + min(100, -1 + legLen(5, 3))"#;
|
let ast = r#"const myVar = 2 + min(100, -1 + legLen(5, 3))"#;
|
||||||
let (_, env, _, exec_state) = parse_execute(ast).await.unwrap();
|
let (_, env, _, exec_state) = parse_execute(ast).await.unwrap();
|
||||||
assert_eq!(5.0, mem_get_json(exec_state.memory(), env, "myVar").as_f64().unwrap());
|
assert_eq!(5.0, mem_get_json(exec_state.stack(), env, "myVar").as_f64().unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
async fn test_math_execute() {
|
async fn test_math_execute() {
|
||||||
let ast = r#"const myVar = 1 + 2 * (3 - 4) / -5 + 6"#;
|
let ast = r#"const myVar = 1 + 2 * (3 - 4) / -5 + 6"#;
|
||||||
let (_, env, _, exec_state) = parse_execute(ast).await.unwrap();
|
let (_, env, _, exec_state) = parse_execute(ast).await.unwrap();
|
||||||
assert_eq!(7.4, mem_get_json(exec_state.memory(), env, "myVar").as_f64().unwrap());
|
assert_eq!(7.4, mem_get_json(exec_state.stack(), env, "myVar").as_f64().unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
async fn test_math_execute_start_negative() {
|
async fn test_math_execute_start_negative() {
|
||||||
let ast = r#"const myVar = -5 + 6"#;
|
let ast = r#"const myVar = -5 + 6"#;
|
||||||
let (_, env, _, exec_state) = parse_execute(ast).await.unwrap();
|
let (_, env, _, exec_state) = parse_execute(ast).await.unwrap();
|
||||||
assert_eq!(1.0, mem_get_json(exec_state.memory(), env, "myVar").as_f64().unwrap());
|
assert_eq!(1.0, mem_get_json(exec_state.stack(), env, "myVar").as_f64().unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
@ -1423,7 +1435,7 @@ let shape = layer() |> patternTransform(instances = 10, transform = transform)
|
|||||||
let (_, env, _, exec_state) = parse_execute(ast).await.unwrap();
|
let (_, env, _, exec_state) = parse_execute(ast).await.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
std::f64::consts::TAU,
|
std::f64::consts::TAU,
|
||||||
mem_get_json(exec_state.memory(), env, "myVar").as_f64().unwrap()
|
mem_get_json(exec_state.stack(), env, "myVar").as_f64().unwrap()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1431,7 +1443,7 @@ let shape = layer() |> patternTransform(instances = 10, transform = transform)
|
|||||||
async fn test_math_define_decimal_without_leading_zero() {
|
async fn test_math_define_decimal_without_leading_zero() {
|
||||||
let ast = r#"let thing = .4 + 7"#;
|
let ast = r#"let thing = .4 + 7"#;
|
||||||
let (_, env, _, exec_state) = parse_execute(ast).await.unwrap();
|
let (_, env, _, exec_state) = parse_execute(ast).await.unwrap();
|
||||||
assert_eq!(7.4, mem_get_json(exec_state.memory(), env, "thing").as_f64().unwrap());
|
assert_eq!(7.4, mem_get_json(exec_state.stack(), env, "thing").as_f64().unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
@ -1439,10 +1451,10 @@ let shape = layer() |> patternTransform(instances = 10, transform = transform)
|
|||||||
let ast = r#"const inMm = 25.4 * mm()
|
let ast = r#"const inMm = 25.4 * mm()
|
||||||
const inInches = 1.0 * inch()"#;
|
const inInches = 1.0 * inch()"#;
|
||||||
let (_, env, _, exec_state) = parse_execute(ast).await.unwrap();
|
let (_, env, _, exec_state) = parse_execute(ast).await.unwrap();
|
||||||
assert_eq!(25.4, mem_get_json(exec_state.memory(), env, "inMm").as_f64().unwrap());
|
assert_eq!(25.4, mem_get_json(exec_state.stack(), env, "inMm").as_f64().unwrap());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
25.4,
|
25.4,
|
||||||
mem_get_json(exec_state.memory(), env, "inInches").as_f64().unwrap()
|
mem_get_json(exec_state.stack(), env, "inInches").as_f64().unwrap()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1454,12 +1466,9 @@ const inInches = 1.0 * inch()"#;
|
|||||||
let (_, env, _, exec_state) = parse_execute(ast).await.unwrap();
|
let (_, env, _, exec_state) = parse_execute(ast).await.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
1.0,
|
1.0,
|
||||||
mem_get_json(exec_state.memory(), env, "inMm").as_f64().unwrap().round()
|
mem_get_json(exec_state.stack(), env, "inMm").as_f64().unwrap().round()
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
1.0,
|
|
||||||
mem_get_json(exec_state.memory(), env, "inInches").as_f64().unwrap()
|
|
||||||
);
|
);
|
||||||
|
assert_eq!(1.0, mem_get_json(exec_state.stack(), env, "inInches").as_f64().unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
@ -1470,12 +1479,9 @@ const inInches = 2.0 * inch()"#;
|
|||||||
let (_, env, _, exec_state) = parse_execute(ast).await.unwrap();
|
let (_, env, _, exec_state) = parse_execute(ast).await.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
1.0,
|
1.0,
|
||||||
mem_get_json(exec_state.memory(), env, "inMm").as_f64().unwrap().round()
|
mem_get_json(exec_state.stack(), env, "inMm").as_f64().unwrap().round()
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
2.0,
|
|
||||||
mem_get_json(exec_state.memory(), env, "inInches").as_f64().unwrap()
|
|
||||||
);
|
);
|
||||||
|
assert_eq!(2.0, mem_get_json(exec_state.stack(), env, "inInches").as_f64().unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
@ -1517,14 +1523,14 @@ check(false)
|
|||||||
let (_, env, _, exec_state) = parse_execute(ast).await.unwrap();
|
let (_, env, _, exec_state) = parse_execute(ast).await.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
false,
|
false,
|
||||||
mem_get_json(exec_state.memory(), env, "notTrue").as_bool().unwrap()
|
mem_get_json(exec_state.stack(), env, "notTrue").as_bool().unwrap()
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
true,
|
true,
|
||||||
mem_get_json(exec_state.memory(), env, "notFalse").as_bool().unwrap()
|
mem_get_json(exec_state.stack(), env, "notFalse").as_bool().unwrap()
|
||||||
);
|
);
|
||||||
assert_eq!(true, mem_get_json(exec_state.memory(), env, "c").as_bool().unwrap());
|
assert_eq!(true, mem_get_json(exec_state.stack(), env, "c").as_bool().unwrap());
|
||||||
assert_eq!(false, mem_get_json(exec_state.memory(), env, "d").as_bool().unwrap());
|
assert_eq!(false, mem_get_json(exec_state.stack(), env, "d").as_bool().unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
use kittycad_modeling_cmds::websocket::WebSocketResponse;
|
use kittycad_modeling_cmds::websocket::WebSocketResponse;
|
||||||
@ -5,12 +7,11 @@ use schemars::JsonSchema;
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
use super::EnvironmentRef;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
errors::{KclError, KclErrorDetails, Severity},
|
errors::{KclError, KclErrorDetails, Severity},
|
||||||
execution::{
|
execution::{
|
||||||
annotations, kcl_value, memory::ProgramMemory, Artifact, ArtifactCommand, ArtifactGraph, ArtifactId,
|
annotations, kcl_value, memory::ProgramMemory, memory::Stack, Artifact, ArtifactCommand, ArtifactGraph,
|
||||||
ExecOutcome, ExecutorSettings, KclValue, Operation, UnitAngle, UnitLen,
|
ArtifactId, EnvironmentRef, ExecOutcome, ExecutorSettings, KclValue, Operation, UnitAngle, UnitLen,
|
||||||
},
|
},
|
||||||
modules::{ModuleId, ModuleInfo, ModuleLoader, ModulePath, ModuleRepr, ModuleSource},
|
modules::{ModuleId, ModuleInfo, ModuleLoader, ModulePath, ModuleRepr, ModuleSource},
|
||||||
parsing::ast::types::Annotation,
|
parsing::ast::types::Annotation,
|
||||||
@ -27,8 +28,6 @@ pub struct ExecState {
|
|||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub(super) struct GlobalState {
|
pub(super) struct GlobalState {
|
||||||
/// Program variable bindings.
|
|
||||||
pub memory: ProgramMemory,
|
|
||||||
/// The stable artifact ID generator.
|
/// The stable artifact ID generator.
|
||||||
pub id_generator: IdGenerator,
|
pub id_generator: IdGenerator,
|
||||||
/// Map from source file absolute path to module ID.
|
/// Map from source file absolute path to module ID.
|
||||||
@ -61,6 +60,7 @@ pub(super) struct GlobalState {
|
|||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub(super) struct ModuleState {
|
pub(super) struct ModuleState {
|
||||||
|
pub stack: Stack,
|
||||||
/// The current value of the pipe operator returned from the previous
|
/// The current value of the pipe operator returned from the previous
|
||||||
/// expression. If we're not currently in a pipeline, this will be None.
|
/// expression. If we're not currently in a pipeline, this will be None.
|
||||||
pub pipe_value: Option<KclValue>,
|
pub pipe_value: Option<KclValue>,
|
||||||
@ -74,7 +74,7 @@ impl ExecState {
|
|||||||
pub fn new(exec_settings: &ExecutorSettings) -> Self {
|
pub fn new(exec_settings: &ExecutorSettings) -> Self {
|
||||||
ExecState {
|
ExecState {
|
||||||
global: GlobalState::new(exec_settings),
|
global: GlobalState::new(exec_settings),
|
||||||
mod_local: ModuleState::new(exec_settings, None),
|
mod_local: ModuleState::new(exec_settings, None, ProgramMemory::new()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,7 +89,7 @@ impl ExecState {
|
|||||||
|
|
||||||
*self = ExecState {
|
*self = ExecState {
|
||||||
global,
|
global,
|
||||||
mod_local: ModuleState::new(exec_settings, None),
|
mod_local: ModuleState::new(exec_settings, None, ProgramMemory::new()),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -116,7 +116,7 @@ impl ExecState {
|
|||||||
// state when we add more to ExecState.
|
// state when we add more to ExecState.
|
||||||
ExecOutcome {
|
ExecOutcome {
|
||||||
variables: self
|
variables: self
|
||||||
.memory()
|
.stack()
|
||||||
.find_all_in_env(main_ref, |_| true)
|
.find_all_in_env(main_ref, |_| true)
|
||||||
.map(|(k, v)| (k.clone(), v.clone()))
|
.map(|(k, v)| (k.clone(), v.clone()))
|
||||||
.collect(),
|
.collect(),
|
||||||
@ -139,7 +139,7 @@ impl ExecState {
|
|||||||
// state when we add more to ExecState.
|
// state when we add more to ExecState.
|
||||||
ExecOutcome {
|
ExecOutcome {
|
||||||
variables: self
|
variables: self
|
||||||
.memory()
|
.stack()
|
||||||
.find_all_in_env(main_ref, |_| true)
|
.find_all_in_env(main_ref, |_| true)
|
||||||
.map(|(k, v)| (k.clone(), v.clone()))
|
.map(|(k, v)| (k.clone(), v.clone()))
|
||||||
.collect(),
|
.collect(),
|
||||||
@ -152,12 +152,12 @@ impl ExecState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn memory(&self) -> &ProgramMemory {
|
pub(crate) fn stack(&self) -> &Stack {
|
||||||
&self.global.memory
|
&self.mod_local.stack
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn mut_memory(&mut self) -> &mut ProgramMemory {
|
pub(crate) fn mut_stack(&mut self) -> &mut Stack {
|
||||||
&mut self.global.memory
|
&mut self.mod_local.stack
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn next_uuid(&mut self) -> Uuid {
|
pub(crate) fn next_uuid(&mut self) -> Uuid {
|
||||||
@ -241,7 +241,6 @@ impl ExecState {
|
|||||||
impl GlobalState {
|
impl GlobalState {
|
||||||
fn new(settings: &ExecutorSettings) -> Self {
|
fn new(settings: &ExecutorSettings) -> Self {
|
||||||
let mut global = GlobalState {
|
let mut global = GlobalState {
|
||||||
memory: ProgramMemory::new(),
|
|
||||||
id_generator: Default::default(),
|
id_generator: Default::default(),
|
||||||
path_to_source_id: Default::default(),
|
path_to_source_id: Default::default(),
|
||||||
module_infos: Default::default(),
|
module_infos: Default::default(),
|
||||||
@ -275,8 +274,9 @@ impl GlobalState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ModuleState {
|
impl ModuleState {
|
||||||
pub(super) fn new(exec_settings: &ExecutorSettings, std_path: Option<String>) -> Self {
|
pub(super) fn new(exec_settings: &ExecutorSettings, std_path: Option<String>, memory: Arc<ProgramMemory>) -> Self {
|
||||||
ModuleState {
|
ModuleState {
|
||||||
|
stack: memory.new_stack(),
|
||||||
pipe_value: Default::default(),
|
pipe_value: Default::default(),
|
||||||
module_exports: Default::default(),
|
module_exports: Default::default(),
|
||||||
settings: MetaSettings {
|
settings: MetaSettings {
|
||||||
|
@ -1606,9 +1606,8 @@ fn position_to_char_index(position: Position, code: &str) -> usize {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn with_cached_var<T>(name: &str, f: impl Fn(&KclValue) -> T) -> Option<T> {
|
async fn with_cached_var<T>(name: &str, f: impl Fn(&KclValue) -> T) -> Option<T> {
|
||||||
let result_env = cache::read_old_ast().await?.result_env;
|
|
||||||
let mem = cache::read_old_memory().await?;
|
let mem = cache::read_old_memory().await?;
|
||||||
let value = mem.get_from(name, result_env, SourceRange::default()).ok()?;
|
let value = mem.get(name, SourceRange::default()).ok()?;
|
||||||
|
|
||||||
Some(f(value))
|
Some(f(value))
|
||||||
}
|
}
|
||||||
|
@ -223,7 +223,7 @@ impl Args {
|
|||||||
exec_state: &'e mut ExecState,
|
exec_state: &'e mut ExecState,
|
||||||
tag: &'a TagIdentifier,
|
tag: &'a TagIdentifier,
|
||||||
) -> Result<&'e crate::execution::TagEngineInfo, KclError> {
|
) -> Result<&'e crate::execution::TagEngineInfo, KclError> {
|
||||||
if let KclValue::TagIdentifier(t) = exec_state.memory().get_from_call_stack(&tag.value, self.source_range)? {
|
if let KclValue::TagIdentifier(t) = exec_state.stack().get_from_call_stack(&tag.value, self.source_range)? {
|
||||||
Ok(t.info.as_ref().ok_or_else(|| {
|
Ok(t.info.as_ref().ok_or_else(|| {
|
||||||
KclError::Type(KclErrorDetails {
|
KclError::Type(KclErrorDetails {
|
||||||
message: format!("Tag `{}` does not have engine info", tag.value),
|
message: format!("Tag `{}` does not have engine info", tag.value),
|
||||||
@ -289,7 +289,7 @@ impl Args {
|
|||||||
// Find all the solids on the same shared sketch.
|
// Find all the solids on the same shared sketch.
|
||||||
ids.extend(
|
ids.extend(
|
||||||
exec_state
|
exec_state
|
||||||
.memory()
|
.stack()
|
||||||
.walk_call_stack()
|
.walk_call_stack()
|
||||||
.filter(|v| matches!(v, KclValue::Solid { value } if value.sketch.id == sketch_id))
|
.filter(|v| matches!(v, KclValue::Solid { value } if value.sketch.id == sketch_id))
|
||||||
.flat_map(|v| match v {
|
.flat_map(|v| match v {
|
||||||
|
Reference in New Issue
Block a user