Execution refactoring (#7376)
* Move import graph to execution Signed-off-by: Nick Cameron <nrc@ncameron.org> * Refactor artifact handling Signed-off-by: Nick Cameron <nrc@ncameron.org> * Refactor caching to separate global state from per-module state Signed-off-by: Nick Cameron <nrc@ncameron.org> --------- Signed-off-by: Nick Cameron <nrc@ncameron.org>
This commit is contained in:
@ -676,6 +676,7 @@ impl EdgeCut {
|
|||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct ArtifactGraph {
|
pub struct ArtifactGraph {
|
||||||
map: IndexMap<ArtifactId, Artifact>,
|
map: IndexMap<ArtifactId, Artifact>,
|
||||||
|
item_count: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ArtifactGraph {
|
impl ArtifactGraph {
|
||||||
@ -711,10 +712,10 @@ pub(super) fn build_artifact_graph(
|
|||||||
artifact_commands: &[ArtifactCommand],
|
artifact_commands: &[ArtifactCommand],
|
||||||
responses: &IndexMap<Uuid, WebSocketResponse>,
|
responses: &IndexMap<Uuid, WebSocketResponse>,
|
||||||
ast: &Node<Program>,
|
ast: &Node<Program>,
|
||||||
cached_body_items: usize,
|
|
||||||
exec_artifacts: &mut IndexMap<ArtifactId, Artifact>,
|
exec_artifacts: &mut IndexMap<ArtifactId, Artifact>,
|
||||||
initial_graph: ArtifactGraph,
|
initial_graph: ArtifactGraph,
|
||||||
) -> Result<ArtifactGraph, KclError> {
|
) -> Result<ArtifactGraph, KclError> {
|
||||||
|
let item_count = initial_graph.item_count;
|
||||||
let mut map = initial_graph.into_map();
|
let mut map = initial_graph.into_map();
|
||||||
|
|
||||||
let mut path_to_plane_id_map = FnvHashMap::default();
|
let mut path_to_plane_id_map = FnvHashMap::default();
|
||||||
@ -725,7 +726,7 @@ pub(super) fn build_artifact_graph(
|
|||||||
for exec_artifact in exec_artifacts.values_mut() {
|
for exec_artifact in exec_artifacts.values_mut() {
|
||||||
// Note: We only have access to the new AST. So if these artifacts
|
// Note: We only have access to the new AST. So if these artifacts
|
||||||
// somehow came from cached AST, this won't fill in anything.
|
// somehow came from cached AST, this won't fill in anything.
|
||||||
fill_in_node_paths(exec_artifact, ast, cached_body_items);
|
fill_in_node_paths(exec_artifact, ast, item_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
for artifact_command in artifact_commands {
|
for artifact_command in artifact_commands {
|
||||||
@ -752,7 +753,7 @@ pub(super) fn build_artifact_graph(
|
|||||||
&flattened_responses,
|
&flattened_responses,
|
||||||
&path_to_plane_id_map,
|
&path_to_plane_id_map,
|
||||||
ast,
|
ast,
|
||||||
cached_body_items,
|
item_count,
|
||||||
exec_artifacts,
|
exec_artifacts,
|
||||||
)?;
|
)?;
|
||||||
for artifact in artifact_updates {
|
for artifact in artifact_updates {
|
||||||
@ -765,7 +766,10 @@ pub(super) fn build_artifact_graph(
|
|||||||
merge_artifact_into_map(&mut map, exec_artifact.clone());
|
merge_artifact_into_map(&mut map, exec_artifact.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(ArtifactGraph { map })
|
Ok(ArtifactGraph {
|
||||||
|
map,
|
||||||
|
item_count: item_count + ast.body.len(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// These may have been created with placeholder `CodeRef`s because we didn't
|
/// These may have been created with placeholder `CodeRef`s because we didn't
|
||||||
|
@ -6,25 +6,31 @@ use itertools::{EitherOrBoth, Itertools};
|
|||||||
use tokio::sync::RwLock;
|
use tokio::sync::RwLock;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
execution::{annotations, memory::Stack, state::ModuleInfoMap, EnvironmentRef, ExecState, ExecutorSettings},
|
execution::{
|
||||||
|
annotations,
|
||||||
|
memory::Stack,
|
||||||
|
state::{self as exec_state, ModuleInfoMap},
|
||||||
|
EnvironmentRef, ExecutorSettings,
|
||||||
|
},
|
||||||
parsing::ast::types::{Annotation, Node, Program},
|
parsing::ast::types::{Annotation, Node, Program},
|
||||||
walk::Node as WalkNode,
|
walk::Node as WalkNode,
|
||||||
|
ExecOutcome, ExecutorContext,
|
||||||
};
|
};
|
||||||
|
|
||||||
lazy_static::lazy_static! {
|
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<GlobalState>>> = 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<(Stack, ModuleInfoMap)>>> = Default::default();
|
static ref PREV_MEMORY: Arc<RwLock<Option<(Stack, ModuleInfoMap)>>> = Default::default();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Read the old ast memory from the lock.
|
/// Read the old ast memory from the lock.
|
||||||
pub(crate) async fn read_old_ast() -> Option<OldAstState> {
|
pub(super) async fn read_old_ast() -> Option<GlobalState> {
|
||||||
let old_ast = OLD_AST.read().await;
|
let old_ast = OLD_AST.read().await;
|
||||||
old_ast.clone()
|
old_ast.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) async fn write_old_ast(old_state: OldAstState) {
|
pub(super) async fn write_old_ast(old_state: GlobalState) {
|
||||||
let mut old_ast = OLD_AST.write().await;
|
let mut old_ast = OLD_AST.write().await;
|
||||||
*old_ast = Some(old_state);
|
*old_ast = Some(old_state);
|
||||||
}
|
}
|
||||||
@ -34,7 +40,7 @@ pub(crate) async fn read_old_memory() -> Option<(Stack, ModuleInfoMap)> {
|
|||||||
old_mem.clone()
|
old_mem.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) async fn write_old_memory(mem: (Stack, ModuleInfoMap)) {
|
pub(crate) async fn write_old_memory(mem: (Stack, ModuleInfoMap)) {
|
||||||
let mut old_mem = PREV_MEMORY.write().await;
|
let mut old_mem = PREV_MEMORY.write().await;
|
||||||
*old_mem = Some(mem);
|
*old_mem = Some(mem);
|
||||||
}
|
}
|
||||||
@ -56,16 +62,73 @@ pub struct CacheInformation<'a> {
|
|||||||
pub settings: &'a ExecutorSettings,
|
pub settings: &'a ExecutorSettings,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The old ast and program memory.
|
/// The cached state of the whole program.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct OldAstState {
|
pub(super) struct GlobalState {
|
||||||
/// The ast.
|
pub(super) main: ModuleState,
|
||||||
pub ast: Node<Program>,
|
|
||||||
/// The exec state.
|
/// The exec state.
|
||||||
pub exec_state: ExecState,
|
pub(super) exec_state: exec_state::GlobalState,
|
||||||
/// The last settings used for execution.
|
/// The last settings used for execution.
|
||||||
pub settings: crate::execution::ExecutorSettings,
|
pub(super) settings: ExecutorSettings,
|
||||||
pub result_env: EnvironmentRef,
|
}
|
||||||
|
|
||||||
|
impl GlobalState {
|
||||||
|
pub fn new(
|
||||||
|
state: exec_state::ExecState,
|
||||||
|
settings: ExecutorSettings,
|
||||||
|
ast: Node<Program>,
|
||||||
|
result_env: EnvironmentRef,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
main: ModuleState {
|
||||||
|
ast,
|
||||||
|
exec_state: state.mod_local,
|
||||||
|
result_env,
|
||||||
|
},
|
||||||
|
exec_state: state.global,
|
||||||
|
settings,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_settings(mut self, settings: ExecutorSettings) -> GlobalState {
|
||||||
|
self.settings = settings;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn reconstitute_exec_state(&self) -> exec_state::ExecState {
|
||||||
|
exec_state::ExecState {
|
||||||
|
global: self.exec_state.clone(),
|
||||||
|
mod_local: self.main.exec_state.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn into_exec_outcome(self, ctx: &ExecutorContext) -> ExecOutcome {
|
||||||
|
// Fields are opt-in so that we don't accidentally leak private internal
|
||||||
|
// state when we add more to ExecState.
|
||||||
|
ExecOutcome {
|
||||||
|
variables: self.main.exec_state.variables(self.main.result_env),
|
||||||
|
filenames: self.exec_state.filenames(),
|
||||||
|
#[cfg(feature = "artifact-graph")]
|
||||||
|
operations: self.exec_state.artifacts.operations,
|
||||||
|
#[cfg(feature = "artifact-graph")]
|
||||||
|
artifact_commands: self.exec_state.artifacts.commands,
|
||||||
|
#[cfg(feature = "artifact-graph")]
|
||||||
|
artifact_graph: self.exec_state.artifacts.graph,
|
||||||
|
errors: self.exec_state.errors,
|
||||||
|
default_planes: ctx.engine.get_default_planes().read().await.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Per-module cached state
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub(super) struct ModuleState {
|
||||||
|
/// The AST of the module.
|
||||||
|
pub(super) ast: Node<Program>,
|
||||||
|
/// The ExecState of the module.
|
||||||
|
pub(super) exec_state: exec_state::ModuleState,
|
||||||
|
/// The memory env for the module.
|
||||||
|
pub(super) result_env: EnvironmentRef,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The result of a cache check.
|
/// The result of a cache check.
|
||||||
@ -79,9 +142,6 @@ pub(super) enum CacheResult {
|
|||||||
reapply_settings: bool,
|
reapply_settings: bool,
|
||||||
/// The program that needs to be executed.
|
/// The program that needs to be executed.
|
||||||
program: Node<Program>,
|
program: Node<Program>,
|
||||||
/// The number of body items that were cached and omitted from the
|
|
||||||
/// program that needs to be executed. Used to compute [`crate::NodePath`].
|
|
||||||
cached_body_items: usize,
|
|
||||||
},
|
},
|
||||||
/// Check only the imports, and not the main program.
|
/// Check only the imports, and not the main program.
|
||||||
/// Before sending this we already checked the main program and it is the same.
|
/// Before sending this we already checked the main program and it is the same.
|
||||||
@ -146,7 +206,6 @@ pub(super) async fn get_changed_program(old: CacheInformation<'_>, new: CacheInf
|
|||||||
// We know they have the same imports because the ast is the same.
|
// We know they have the same imports because the ast is the same.
|
||||||
// If we have no imports, we can skip this.
|
// If we have no imports, we can skip this.
|
||||||
if !old.ast.has_import_statements() {
|
if !old.ast.has_import_statements() {
|
||||||
println!("No imports, no need to check.");
|
|
||||||
return CacheResult::NoAction(reapply_settings);
|
return CacheResult::NoAction(reapply_settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -194,7 +253,6 @@ pub(super) async fn get_changed_program(old: CacheInformation<'_>, new: CacheInf
|
|||||||
clear_scene: true,
|
clear_scene: true,
|
||||||
reapply_settings: true,
|
reapply_settings: true,
|
||||||
program: new.ast.clone(),
|
program: new.ast.clone(),
|
||||||
cached_body_items: 0,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -223,7 +281,6 @@ fn generate_changed_program(old_ast: Node<Program>, mut new_ast: Node<Program>,
|
|||||||
clear_scene: true,
|
clear_scene: true,
|
||||||
reapply_settings,
|
reapply_settings,
|
||||||
program: new_ast,
|
program: new_ast,
|
||||||
cached_body_items: 0,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -244,7 +301,6 @@ fn generate_changed_program(old_ast: Node<Program>, mut new_ast: Node<Program>,
|
|||||||
clear_scene: true,
|
clear_scene: true,
|
||||||
reapply_settings,
|
reapply_settings,
|
||||||
program: new_ast,
|
program: new_ast,
|
||||||
cached_body_items: 0,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
std::cmp::Ordering::Greater => {
|
std::cmp::Ordering::Greater => {
|
||||||
@ -261,7 +317,6 @@ fn generate_changed_program(old_ast: Node<Program>, mut new_ast: Node<Program>,
|
|||||||
clear_scene: false,
|
clear_scene: false,
|
||||||
reapply_settings,
|
reapply_settings,
|
||||||
program: new_ast,
|
program: new_ast,
|
||||||
cached_body_items: old_ast.body.len(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
std::cmp::Ordering::Equal => {
|
std::cmp::Ordering::Equal => {
|
||||||
@ -600,7 +655,6 @@ startSketchOn(XY)
|
|||||||
clear_scene: true,
|
clear_scene: true,
|
||||||
reapply_settings: true,
|
reapply_settings: true,
|
||||||
program: new_program.ast,
|
program: new_program.ast,
|
||||||
cached_body_items: 0,
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -639,7 +693,6 @@ startSketchOn(XY)
|
|||||||
clear_scene: true,
|
clear_scene: true,
|
||||||
reapply_settings: true,
|
reapply_settings: true,
|
||||||
program: new_program.ast,
|
program: new_program.ast,
|
||||||
cached_body_items: 0,
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,7 @@ pub(crate) type Universe = HashMap<String, DependencyInfo>;
|
|||||||
/// run concurrently. Each "stage" is blocking in this model, which will
|
/// run concurrently. Each "stage" is blocking in this model, which will
|
||||||
/// change in the future. Don't use this function widely, yet.
|
/// change in the future. Don't use this function widely, yet.
|
||||||
#[allow(clippy::iter_over_hash_type)]
|
#[allow(clippy::iter_over_hash_type)]
|
||||||
pub fn import_graph(progs: &Universe, ctx: &ExecutorContext) -> Result<Vec<Vec<String>>, KclError> {
|
pub(crate) fn import_graph(progs: &Universe, ctx: &ExecutorContext) -> Result<Vec<Vec<String>>, KclError> {
|
||||||
let mut graph = Graph::new();
|
let mut graph = Graph::new();
|
||||||
|
|
||||||
for (name, (_, _, path, repr)) in progs.iter() {
|
for (name, (_, _, path, repr)) in progs.iter() {
|
||||||
@ -120,7 +120,7 @@ fn topsort(all_modules: &[&str], graph: Graph) -> Result<Vec<Vec<String>>, KclEr
|
|||||||
|
|
||||||
type ImportDependencies = Vec<(String, AstNode<ImportStatement>, ModulePath)>;
|
type ImportDependencies = Vec<(String, AstNode<ImportStatement>, ModulePath)>;
|
||||||
|
|
||||||
pub(crate) fn import_dependencies(
|
fn import_dependencies(
|
||||||
path: &ModulePath,
|
path: &ModulePath,
|
||||||
repr: &ModuleRepr,
|
repr: &ModuleRepr,
|
||||||
ctx: &ExecutorContext,
|
ctx: &ExecutorContext,
|
@ -5,9 +5,8 @@ use std::sync::Arc;
|
|||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
#[cfg(feature = "artifact-graph")]
|
#[cfg(feature = "artifact-graph")]
|
||||||
pub use artifact::{Artifact, ArtifactCommand, ArtifactGraph, CodeRef, StartSketchOnFace, StartSketchOnPlane};
|
pub use artifact::{Artifact, ArtifactCommand, ArtifactGraph, CodeRef, StartSketchOnFace, StartSketchOnPlane};
|
||||||
use cache::OldAstState;
|
use cache::GlobalState;
|
||||||
pub use cache::{bust_cache, clear_mem_cache};
|
pub use cache::{bust_cache, clear_mem_cache};
|
||||||
#[cfg(feature = "artifact-graph")]
|
|
||||||
pub use cad_op::{Group, Operation};
|
pub use cad_op::{Group, Operation};
|
||||||
pub use geometry::*;
|
pub use geometry::*;
|
||||||
pub use id_generator::IdGenerator;
|
pub use id_generator::IdGenerator;
|
||||||
@ -27,13 +26,12 @@ use serde::{Deserialize, Serialize};
|
|||||||
pub use state::{ExecState, MetaSettings};
|
pub use state::{ExecState, MetaSettings};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
#[cfg(feature = "artifact-graph")]
|
|
||||||
use crate::execution::artifact::build_artifact_graph;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
engine::EngineManager,
|
engine::EngineManager,
|
||||||
errors::{KclError, KclErrorDetails},
|
errors::{KclError, KclErrorDetails},
|
||||||
execution::{
|
execution::{
|
||||||
cache::{CacheInformation, CacheResult},
|
cache::{CacheInformation, CacheResult},
|
||||||
|
import_graph::{Universe, UniverseMap},
|
||||||
typed_path::TypedPath,
|
typed_path::TypedPath,
|
||||||
types::{UnitAngle, UnitLen},
|
types::{UnitAngle, UnitLen},
|
||||||
},
|
},
|
||||||
@ -41,7 +39,6 @@ use crate::{
|
|||||||
modules::{ModuleId, ModulePath, ModuleRepr},
|
modules::{ModuleId, ModulePath, ModuleRepr},
|
||||||
parsing::ast::types::{Expr, ImportPath, NodeRef},
|
parsing::ast::types::{Expr, ImportPath, NodeRef},
|
||||||
source_range::SourceRange,
|
source_range::SourceRange,
|
||||||
walk::{Universe, UniverseMap},
|
|
||||||
CompilationError, ExecError, KclErrorWithOutputs,
|
CompilationError, ExecError, KclErrorWithOutputs,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -55,6 +52,7 @@ pub mod fn_call;
|
|||||||
mod geometry;
|
mod geometry;
|
||||||
mod id_generator;
|
mod id_generator;
|
||||||
mod import;
|
mod import;
|
||||||
|
mod import_graph;
|
||||||
pub(crate) mod kcl_value;
|
pub(crate) mod kcl_value;
|
||||||
mod memory;
|
mod memory;
|
||||||
mod state;
|
mod state;
|
||||||
@ -568,7 +566,7 @@ impl ExecutorContext {
|
|||||||
// part of the scene).
|
// part of the scene).
|
||||||
exec_state.mut_stack().push_new_env_for_scope();
|
exec_state.mut_stack().push_new_env_for_scope();
|
||||||
|
|
||||||
let result = self.inner_run(&program, 0, &mut exec_state, true).await?;
|
let result = self.inner_run(&program, &mut exec_state, true).await?;
|
||||||
|
|
||||||
// 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
|
||||||
@ -576,7 +574,7 @@ impl ExecutorContext {
|
|||||||
|
|
||||||
let mut mem = exec_state.stack().clone();
|
let mut mem = exec_state.stack().clone();
|
||||||
let module_infos = exec_state.global.module_infos.clone();
|
let module_infos = exec_state.global.module_infos.clone();
|
||||||
let outcome = exec_state.to_mock_exec_outcome(result.0).await;
|
let outcome = exec_state.to_mock_exec_outcome(result.0, self).await;
|
||||||
|
|
||||||
mem.squash_env(result.0);
|
mem.squash_env(result.0);
|
||||||
cache::write_old_memory((mem, module_infos)).await;
|
cache::write_old_memory((mem, module_infos)).await;
|
||||||
@ -587,17 +585,11 @@ impl ExecutorContext {
|
|||||||
pub async fn run_with_caching(&self, program: crate::Program) -> Result<ExecOutcome, KclErrorWithOutputs> {
|
pub async fn run_with_caching(&self, program: crate::Program) -> Result<ExecOutcome, KclErrorWithOutputs> {
|
||||||
assert!(!self.is_mock());
|
assert!(!self.is_mock());
|
||||||
|
|
||||||
let (program, mut exec_state, preserve_mem, cached_body_items, imports_info) = if let Some(OldAstState {
|
let (program, exec_state, result) = match cache::read_old_ast().await {
|
||||||
ast: old_ast,
|
Some(mut cached_state) => {
|
||||||
exec_state: mut old_state,
|
|
||||||
settings: old_settings,
|
|
||||||
result_env,
|
|
||||||
}) =
|
|
||||||
cache::read_old_ast().await
|
|
||||||
{
|
|
||||||
let old = CacheInformation {
|
let old = CacheInformation {
|
||||||
ast: &old_ast,
|
ast: &cached_state.main.ast,
|
||||||
settings: &old_settings,
|
settings: &cached_state.settings,
|
||||||
};
|
};
|
||||||
let new = CacheInformation {
|
let new = CacheInformation {
|
||||||
ast: &program.ast,
|
ast: &program.ast,
|
||||||
@ -605,22 +597,24 @@ impl ExecutorContext {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Get the program that actually changed from the old and new information.
|
// Get the program that actually changed from the old and new information.
|
||||||
let (clear_scene, program, body_items, import_check_info) = match cache::get_changed_program(old, new).await
|
let (clear_scene, program, import_check_info) = match cache::get_changed_program(old, new).await {
|
||||||
{
|
|
||||||
CacheResult::ReExecute {
|
CacheResult::ReExecute {
|
||||||
clear_scene,
|
clear_scene,
|
||||||
reapply_settings,
|
reapply_settings,
|
||||||
program: changed_program,
|
program: changed_program,
|
||||||
cached_body_items,
|
|
||||||
} => {
|
} => {
|
||||||
if reapply_settings
|
if reapply_settings
|
||||||
&& self
|
&& self
|
||||||
.engine
|
.engine
|
||||||
.reapply_settings(&self.settings, Default::default(), old_state.id_generator())
|
.reapply_settings(
|
||||||
|
&self.settings,
|
||||||
|
Default::default(),
|
||||||
|
&mut cached_state.main.exec_state.id_generator,
|
||||||
|
)
|
||||||
.await
|
.await
|
||||||
.is_err()
|
.is_err()
|
||||||
{
|
{
|
||||||
(true, program, cached_body_items, None)
|
(true, program, None)
|
||||||
} else {
|
} else {
|
||||||
(
|
(
|
||||||
clear_scene,
|
clear_scene,
|
||||||
@ -628,7 +622,6 @@ impl ExecutorContext {
|
|||||||
ast: changed_program,
|
ast: changed_program,
|
||||||
original_file_contents: program.original_file_contents,
|
original_file_contents: program.original_file_contents,
|
||||||
},
|
},
|
||||||
cached_body_items,
|
|
||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -640,116 +633,128 @@ impl ExecutorContext {
|
|||||||
if reapply_settings
|
if reapply_settings
|
||||||
&& self
|
&& self
|
||||||
.engine
|
.engine
|
||||||
.reapply_settings(&self.settings, Default::default(), old_state.id_generator())
|
.reapply_settings(
|
||||||
|
&self.settings,
|
||||||
|
Default::default(),
|
||||||
|
&mut cached_state.main.exec_state.id_generator,
|
||||||
|
)
|
||||||
.await
|
.await
|
||||||
.is_err()
|
.is_err()
|
||||||
{
|
{
|
||||||
(true, program, old_ast.body.len(), None)
|
(true, program, None)
|
||||||
} else {
|
} else {
|
||||||
// We need to check our imports to see if they changed.
|
// We need to check our imports to see if they changed.
|
||||||
let mut new_exec_state = ExecState::new(self);
|
let mut new_exec_state = ExecState::new(self);
|
||||||
let (new_universe, new_universe_map) = self.get_universe(&program, &mut new_exec_state).await?;
|
let (new_universe, new_universe_map) =
|
||||||
let mut clear_scene = false;
|
self.get_universe(&program, &mut new_exec_state).await?;
|
||||||
|
|
||||||
let mut keys = new_universe.keys().clone().collect::<Vec<_>>();
|
let clear_scene = new_universe.keys().any(|key| {
|
||||||
keys.sort();
|
let id = new_universe[key].1;
|
||||||
for key in keys {
|
match (
|
||||||
let (_, id, _, _) = &new_universe[key];
|
cached_state.exec_state.get_source(id),
|
||||||
if let (Some(source0), Some(source1)) =
|
new_exec_state.global.get_source(id),
|
||||||
(old_state.get_source(*id), new_exec_state.get_source(*id))
|
) {
|
||||||
{
|
(Some(s0), Some(s1)) => s0.source != s1.source,
|
||||||
if source0.source != source1.source {
|
_ => false,
|
||||||
clear_scene = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
if !clear_scene {
|
if !clear_scene {
|
||||||
// Return early we don't need to clear the scene.
|
// Return early we don't need to clear the scene.
|
||||||
let outcome = old_state.to_exec_outcome(result_env).await;
|
return Ok(cached_state.into_exec_outcome(self).await);
|
||||||
return Ok(outcome);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
(
|
(
|
||||||
clear_scene,
|
true,
|
||||||
crate::Program {
|
crate::Program {
|
||||||
ast: changed_program,
|
ast: changed_program,
|
||||||
original_file_contents: program.original_file_contents,
|
original_file_contents: program.original_file_contents,
|
||||||
},
|
},
|
||||||
old_ast.body.len(),
|
Some((new_universe, new_universe_map, new_exec_state)),
|
||||||
// We only care about this if we are clearing the scene.
|
|
||||||
if clear_scene {
|
|
||||||
Some((new_universe, new_universe_map, new_exec_state))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CacheResult::NoAction(true) => {
|
CacheResult::NoAction(true) => {
|
||||||
if self
|
if self
|
||||||
.engine
|
.engine
|
||||||
.reapply_settings(&self.settings, Default::default(), old_state.id_generator())
|
.reapply_settings(
|
||||||
|
&self.settings,
|
||||||
|
Default::default(),
|
||||||
|
&mut cached_state.main.exec_state.id_generator,
|
||||||
|
)
|
||||||
.await
|
.await
|
||||||
.is_ok()
|
.is_ok()
|
||||||
{
|
{
|
||||||
// We need to update the old ast state with the new settings!!
|
// We need to update the old ast state with the new settings!!
|
||||||
cache::write_old_ast(OldAstState {
|
cache::write_old_ast(GlobalState::with_settings(
|
||||||
ast: old_ast,
|
cached_state.clone(),
|
||||||
exec_state: old_state.clone(),
|
self.settings.clone(),
|
||||||
settings: self.settings.clone(),
|
))
|
||||||
result_env,
|
|
||||||
})
|
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
let outcome = old_state.to_exec_outcome(result_env).await;
|
return Ok(cached_state.into_exec_outcome(self).await);
|
||||||
return Ok(outcome);
|
|
||||||
}
|
}
|
||||||
(true, program, old_ast.body.len(), None)
|
(true, program, None)
|
||||||
}
|
}
|
||||||
CacheResult::NoAction(false) => {
|
CacheResult::NoAction(false) => {
|
||||||
let outcome = old_state.to_exec_outcome(result_env).await;
|
return Ok(cached_state.into_exec_outcome(self).await);
|
||||||
return Ok(outcome);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let (exec_state, preserve_mem, universe_info) =
|
let (exec_state, result) = match import_check_info {
|
||||||
if let Some((new_universe, new_universe_map, mut new_exec_state)) = import_check_info {
|
Some((new_universe, new_universe_map, mut new_exec_state)) => {
|
||||||
// Clear the scene if the imports changed.
|
// Clear the scene if the imports changed.
|
||||||
self.send_clear_scene(&mut new_exec_state, Default::default())
|
self.send_clear_scene(&mut new_exec_state, Default::default())
|
||||||
.await
|
.await
|
||||||
.map_err(KclErrorWithOutputs::no_outputs)?;
|
.map_err(KclErrorWithOutputs::no_outputs)?;
|
||||||
|
|
||||||
(new_exec_state, false, Some((new_universe, new_universe_map)))
|
let result = self
|
||||||
} else if clear_scene {
|
.run_concurrent(
|
||||||
|
&program,
|
||||||
|
&mut new_exec_state,
|
||||||
|
Some((new_universe, new_universe_map)),
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
(new_exec_state, result)
|
||||||
|
}
|
||||||
|
None if clear_scene => {
|
||||||
// Pop the execution state, since we are starting fresh.
|
// Pop the execution state, since we are starting fresh.
|
||||||
let mut exec_state = old_state;
|
let mut exec_state = cached_state.reconstitute_exec_state();
|
||||||
exec_state.reset(self);
|
exec_state.reset(self);
|
||||||
|
|
||||||
self.send_clear_scene(&mut exec_state, Default::default())
|
self.send_clear_scene(&mut exec_state, Default::default())
|
||||||
.await
|
.await
|
||||||
.map_err(KclErrorWithOutputs::no_outputs)?;
|
.map_err(KclErrorWithOutputs::no_outputs)?;
|
||||||
|
|
||||||
(exec_state, false, None)
|
let result = self.run_concurrent(&program, &mut exec_state, None, false).await;
|
||||||
} else {
|
|
||||||
old_state.mut_stack().restore_env(result_env);
|
|
||||||
|
|
||||||
(old_state, true, None)
|
(exec_state, result)
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
let mut exec_state = cached_state.reconstitute_exec_state();
|
||||||
|
exec_state.mut_stack().restore_env(cached_state.main.result_env);
|
||||||
|
|
||||||
|
let result = self.run_concurrent(&program, &mut exec_state, None, true).await;
|
||||||
|
|
||||||
|
(exec_state, result)
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
(program, exec_state, preserve_mem, body_items, universe_info)
|
(program, exec_state, result)
|
||||||
} else {
|
}
|
||||||
|
None => {
|
||||||
let mut exec_state = ExecState::new(self);
|
let mut exec_state = ExecState::new(self);
|
||||||
self.send_clear_scene(&mut exec_state, Default::default())
|
self.send_clear_scene(&mut exec_state, Default::default())
|
||||||
.await
|
.await
|
||||||
.map_err(KclErrorWithOutputs::no_outputs)?;
|
.map_err(KclErrorWithOutputs::no_outputs)?;
|
||||||
(program, exec_state, false, 0, None)
|
|
||||||
};
|
|
||||||
|
|
||||||
let result = self
|
let result = self.run_concurrent(&program, &mut exec_state, None, false).await;
|
||||||
.run_concurrent(&program, cached_body_items, &mut exec_state, imports_info, preserve_mem)
|
|
||||||
.await;
|
(program, exec_state, result)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
if result.is_err() {
|
if result.is_err() {
|
||||||
cache::bust_cache().await;
|
cache::bust_cache().await;
|
||||||
@ -759,15 +764,15 @@ impl ExecutorContext {
|
|||||||
let result = result?;
|
let result = result?;
|
||||||
|
|
||||||
// Save this as the last successful execution to the cache.
|
// Save this as the last successful execution to the cache.
|
||||||
cache::write_old_ast(OldAstState {
|
cache::write_old_ast(GlobalState::new(
|
||||||
ast: program.ast,
|
exec_state.clone(),
|
||||||
exec_state: exec_state.clone(),
|
self.settings.clone(),
|
||||||
settings: self.settings.clone(),
|
program.ast,
|
||||||
result_env: result.0,
|
result.0,
|
||||||
})
|
))
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
let outcome = exec_state.to_exec_outcome(result.0).await;
|
let outcome = exec_state.to_exec_outcome(result.0, self).await;
|
||||||
Ok(outcome)
|
Ok(outcome)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -782,11 +787,11 @@ impl ExecutorContext {
|
|||||||
program: &crate::Program,
|
program: &crate::Program,
|
||||||
exec_state: &mut ExecState,
|
exec_state: &mut ExecState,
|
||||||
) -> Result<(EnvironmentRef, Option<ModelingSessionData>), KclErrorWithOutputs> {
|
) -> Result<(EnvironmentRef, Option<ModelingSessionData>), KclErrorWithOutputs> {
|
||||||
self.run_concurrent(program, 0, exec_state, None, false).await
|
self.run_concurrent(program, exec_state, None, false).await
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Perform the execution of a program using a concurrent
|
/// Perform the execution of a program using a concurrent
|
||||||
/// execution model. This has the same signature as [Self::run].
|
/// execution model.
|
||||||
///
|
///
|
||||||
/// You can optionally pass in some initialization memory for partial
|
/// You can optionally pass in some initialization memory for partial
|
||||||
/// execution.
|
/// execution.
|
||||||
@ -795,13 +800,12 @@ impl ExecutorContext {
|
|||||||
pub async fn run_concurrent(
|
pub async fn run_concurrent(
|
||||||
&self,
|
&self,
|
||||||
program: &crate::Program,
|
program: &crate::Program,
|
||||||
cached_body_items: usize,
|
|
||||||
exec_state: &mut ExecState,
|
exec_state: &mut ExecState,
|
||||||
universe_info: Option<(Universe, UniverseMap)>,
|
universe_info: Option<(Universe, UniverseMap)>,
|
||||||
preserve_mem: bool,
|
preserve_mem: bool,
|
||||||
) -> Result<(EnvironmentRef, Option<ModelingSessionData>), KclErrorWithOutputs> {
|
) -> Result<(EnvironmentRef, Option<ModelingSessionData>), KclErrorWithOutputs> {
|
||||||
// Reuse our cached universe if we have one.
|
// Reuse our cached universe if we have one.
|
||||||
#[allow(unused_variables)]
|
|
||||||
let (universe, universe_map) = if let Some((universe, universe_map)) = universe_info {
|
let (universe, universe_map) = if let Some((universe, universe_map)) = universe_info {
|
||||||
(universe, universe_map)
|
(universe, universe_map)
|
||||||
} else {
|
} else {
|
||||||
@ -815,29 +819,8 @@ impl ExecutorContext {
|
|||||||
.await
|
.await
|
||||||
.map_err(KclErrorWithOutputs::no_outputs)?;
|
.map_err(KclErrorWithOutputs::no_outputs)?;
|
||||||
|
|
||||||
for modules in crate::walk::import_graph(&universe, self)
|
for modules in import_graph::import_graph(&universe, self)
|
||||||
.map_err(|err| {
|
.map_err(|err| exec_state.error_with_outputs(err, default_planes.clone()))?
|
||||||
let module_id_to_module_path: IndexMap<ModuleId, ModulePath> = exec_state
|
|
||||||
.global
|
|
||||||
.path_to_source_id
|
|
||||||
.iter()
|
|
||||||
.map(|(k, v)| ((*v), k.clone()))
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
KclErrorWithOutputs::new(
|
|
||||||
err,
|
|
||||||
exec_state.errors().to_vec(),
|
|
||||||
#[cfg(feature = "artifact-graph")]
|
|
||||||
exec_state.global.operations.clone(),
|
|
||||||
#[cfg(feature = "artifact-graph")]
|
|
||||||
exec_state.global.artifact_commands.clone(),
|
|
||||||
#[cfg(feature = "artifact-graph")]
|
|
||||||
exec_state.global.artifact_graph.clone(),
|
|
||||||
module_id_to_module_path,
|
|
||||||
exec_state.global.id_to_source.clone(),
|
|
||||||
default_planes.clone(),
|
|
||||||
)
|
|
||||||
})?
|
|
||||||
.into_iter()
|
.into_iter()
|
||||||
{
|
{
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
@ -859,7 +842,6 @@ impl ExecutorContext {
|
|||||||
let module_path = module_path.clone();
|
let module_path = module_path.clone();
|
||||||
let source_range = SourceRange::from(import_stmt);
|
let source_range = SourceRange::from(import_stmt);
|
||||||
|
|
||||||
#[cfg(feature = "artifact-graph")]
|
|
||||||
match &module_path {
|
match &module_path {
|
||||||
ModulePath::Main => {
|
ModulePath::Main => {
|
||||||
// This should never happen.
|
// This should never happen.
|
||||||
@ -868,7 +850,7 @@ impl ExecutorContext {
|
|||||||
// We only want to display the top-level module imports in
|
// We only want to display the top-level module imports in
|
||||||
// the Feature Tree, not transitive imports.
|
// the Feature Tree, not transitive imports.
|
||||||
if universe_map.contains_key(value) {
|
if universe_map.contains_key(value) {
|
||||||
exec_state.global.operations.push(Operation::GroupBegin {
|
exec_state.push_op(Operation::GroupBegin {
|
||||||
group: Group::ModuleInstance {
|
group: Group::ModuleInstance {
|
||||||
name: value.file_name().unwrap_or_default(),
|
name: value.file_name().unwrap_or_default(),
|
||||||
module_id,
|
module_id,
|
||||||
@ -878,7 +860,7 @@ impl ExecutorContext {
|
|||||||
// Due to concurrent execution, we cannot easily
|
// Due to concurrent execution, we cannot easily
|
||||||
// group operations by module. So we leave the
|
// group operations by module. So we leave the
|
||||||
// group empty and close it immediately.
|
// group empty and close it immediately.
|
||||||
exec_state.global.operations.push(Operation::GroupEnd);
|
exec_state.push_op(Operation::GroupEnd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ModulePath::Std { .. } => {
|
ModulePath::Std { .. } => {
|
||||||
@ -923,7 +905,6 @@ impl ExecutorContext {
|
|||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
{
|
{
|
||||||
wasm_bindgen_futures::spawn_local(async move {
|
wasm_bindgen_futures::spawn_local(async move {
|
||||||
//set.spawn(async move {
|
|
||||||
let mut exec_state = exec_state;
|
let mut exec_state = exec_state;
|
||||||
let exec_ctxt = exec_ctxt;
|
let exec_ctxt = exec_ctxt;
|
||||||
|
|
||||||
@ -993,33 +974,13 @@ impl ExecutorContext {
|
|||||||
exec_state.global.module_infos[&module_id].restore_repr(repr);
|
exec_state.global.module_infos[&module_id].restore_repr(repr);
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
let module_id_to_module_path: IndexMap<ModuleId, ModulePath> = exec_state
|
return Err(exec_state.error_with_outputs(e, default_planes));
|
||||||
.global
|
|
||||||
.path_to_source_id
|
|
||||||
.iter()
|
|
||||||
.map(|(k, v)| ((*v), k.clone()))
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
return Err(KclErrorWithOutputs::new(
|
|
||||||
e,
|
|
||||||
exec_state.errors().to_vec(),
|
|
||||||
#[cfg(feature = "artifact-graph")]
|
|
||||||
exec_state.global.operations.clone(),
|
|
||||||
#[cfg(feature = "artifact-graph")]
|
|
||||||
exec_state.global.artifact_commands.clone(),
|
|
||||||
#[cfg(feature = "artifact-graph")]
|
|
||||||
exec_state.global.artifact_graph.clone(),
|
|
||||||
module_id_to_module_path,
|
|
||||||
exec_state.global.id_to_source.clone(),
|
|
||||||
default_planes,
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.inner_run(program, cached_body_items, exec_state, preserve_mem)
|
self.inner_run(program, exec_state, preserve_mem).await
|
||||||
.await
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the universe & universe map of the program.
|
/// Get the universe & universe map of the program.
|
||||||
@ -1035,7 +996,7 @@ impl ExecutorContext {
|
|||||||
|
|
||||||
let default_planes = self.engine.get_default_planes().read().await.clone();
|
let default_planes = self.engine.get_default_planes().read().await.clone();
|
||||||
|
|
||||||
let root_imports = crate::walk::import_universe(
|
let root_imports = import_graph::import_universe(
|
||||||
self,
|
self,
|
||||||
&ModulePath::Main,
|
&ModulePath::Main,
|
||||||
&ModuleRepr::Kcl(program.ast.clone(), None),
|
&ModuleRepr::Kcl(program.ast.clone(), None),
|
||||||
@ -1043,29 +1004,7 @@ impl ExecutorContext {
|
|||||||
exec_state,
|
exec_state,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.map_err(|err| {
|
.map_err(|err| exec_state.error_with_outputs(err, default_planes))?;
|
||||||
println!("Error: {err:?}");
|
|
||||||
let module_id_to_module_path: IndexMap<ModuleId, ModulePath> = exec_state
|
|
||||||
.global
|
|
||||||
.path_to_source_id
|
|
||||||
.iter()
|
|
||||||
.map(|(k, v)| ((*v), k.clone()))
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
KclErrorWithOutputs::new(
|
|
||||||
err,
|
|
||||||
exec_state.errors().to_vec(),
|
|
||||||
#[cfg(feature = "artifact-graph")]
|
|
||||||
exec_state.global.operations.clone(),
|
|
||||||
#[cfg(feature = "artifact-graph")]
|
|
||||||
exec_state.global.artifact_commands.clone(),
|
|
||||||
#[cfg(feature = "artifact-graph")]
|
|
||||||
exec_state.global.artifact_graph.clone(),
|
|
||||||
module_id_to_module_path,
|
|
||||||
exec_state.global.id_to_source.clone(),
|
|
||||||
default_planes,
|
|
||||||
)
|
|
||||||
})?;
|
|
||||||
|
|
||||||
Ok((universe, root_imports))
|
Ok((universe, root_imports))
|
||||||
}
|
}
|
||||||
@ -1075,7 +1014,6 @@ impl ExecutorContext {
|
|||||||
async fn inner_run(
|
async fn inner_run(
|
||||||
&self,
|
&self,
|
||||||
program: &crate::Program,
|
program: &crate::Program,
|
||||||
cached_body_items: usize,
|
|
||||||
exec_state: &mut ExecState,
|
exec_state: &mut ExecState,
|
||||||
preserve_mem: bool,
|
preserve_mem: bool,
|
||||||
) -> Result<(EnvironmentRef, Option<ModelingSessionData>), KclErrorWithOutputs> {
|
) -> Result<(EnvironmentRef, Option<ModelingSessionData>), KclErrorWithOutputs> {
|
||||||
@ -1089,7 +1027,7 @@ impl ExecutorContext {
|
|||||||
|
|
||||||
let default_planes = self.engine.get_default_planes().read().await.clone();
|
let default_planes = self.engine.get_default_planes().read().await.clone();
|
||||||
let result = self
|
let result = self
|
||||||
.execute_and_build_graph(&program.ast, cached_body_items, exec_state, preserve_mem)
|
.execute_and_build_graph(&program.ast, exec_state, preserve_mem)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
crate::log::log(format!(
|
crate::log::log(format!(
|
||||||
@ -1098,28 +1036,7 @@ impl ExecutorContext {
|
|||||||
));
|
));
|
||||||
crate::log::log(format!("Engine stats: {:?}", self.engine.stats()));
|
crate::log::log(format!("Engine stats: {:?}", self.engine.stats()));
|
||||||
|
|
||||||
let env_ref = result.map_err(|e| {
|
let env_ref = result.map_err(|e| exec_state.error_with_outputs(e, default_planes))?;
|
||||||
let module_id_to_module_path: IndexMap<ModuleId, ModulePath> = exec_state
|
|
||||||
.global
|
|
||||||
.path_to_source_id
|
|
||||||
.iter()
|
|
||||||
.map(|(k, v)| ((*v), k.clone()))
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
KclErrorWithOutputs::new(
|
|
||||||
e,
|
|
||||||
exec_state.errors().to_vec(),
|
|
||||||
#[cfg(feature = "artifact-graph")]
|
|
||||||
exec_state.global.operations.clone(),
|
|
||||||
#[cfg(feature = "artifact-graph")]
|
|
||||||
exec_state.global.artifact_commands.clone(),
|
|
||||||
#[cfg(feature = "artifact-graph")]
|
|
||||||
exec_state.global.artifact_graph.clone(),
|
|
||||||
module_id_to_module_path,
|
|
||||||
exec_state.global.id_to_source.clone(),
|
|
||||||
default_planes.clone(),
|
|
||||||
)
|
|
||||||
})?;
|
|
||||||
|
|
||||||
if !self.is_mock() {
|
if !self.is_mock() {
|
||||||
let mut mem = exec_state.stack().deep_clone();
|
let mut mem = exec_state.stack().deep_clone();
|
||||||
@ -1136,7 +1053,6 @@ impl ExecutorContext {
|
|||||||
async fn execute_and_build_graph(
|
async fn execute_and_build_graph(
|
||||||
&self,
|
&self,
|
||||||
program: NodeRef<'_, crate::parsing::ast::types::Program>,
|
program: NodeRef<'_, crate::parsing::ast::types::Program>,
|
||||||
#[cfg_attr(not(feature = "artifact-graph"), expect(unused))] cached_body_items: usize,
|
|
||||||
exec_state: &mut ExecState,
|
exec_state: &mut ExecState,
|
||||||
preserve_mem: bool,
|
preserve_mem: bool,
|
||||||
) -> Result<EnvironmentRef, KclError> {
|
) -> Result<EnvironmentRef, KclError> {
|
||||||
@ -1163,40 +1079,9 @@ impl ExecutorContext {
|
|||||||
// and should be dropped.
|
// and should be dropped.
|
||||||
self.engine.clear_queues().await;
|
self.engine.clear_queues().await;
|
||||||
|
|
||||||
#[cfg(feature = "artifact-graph")]
|
match exec_state.build_artifact_graph(&self.engine, program).await {
|
||||||
{
|
Ok(_) => exec_result.map(|(_, env_ref, _)| env_ref),
|
||||||
let new_commands = self.engine.take_artifact_commands().await;
|
Err(err) => exec_result.and(Err(err)),
|
||||||
let new_responses = self.engine.take_responses().await;
|
|
||||||
let initial_graph = exec_state.global.artifact_graph.clone();
|
|
||||||
|
|
||||||
// Build the artifact graph.
|
|
||||||
let graph_result = build_artifact_graph(
|
|
||||||
&new_commands,
|
|
||||||
&new_responses,
|
|
||||||
program,
|
|
||||||
cached_body_items,
|
|
||||||
&mut exec_state.global.artifacts,
|
|
||||||
initial_graph,
|
|
||||||
);
|
|
||||||
// Move the artifact commands and responses into ExecState to
|
|
||||||
// simplify cache management and error creation.
|
|
||||||
exec_state.global.artifact_commands.extend(new_commands);
|
|
||||||
exec_state.global.artifact_responses.extend(new_responses);
|
|
||||||
|
|
||||||
match graph_result {
|
|
||||||
Ok(artifact_graph) => {
|
|
||||||
exec_state.global.artifact_graph = artifact_graph;
|
|
||||||
exec_result.map(|(_, env_ref, _)| env_ref)
|
|
||||||
}
|
|
||||||
Err(err) => {
|
|
||||||
// Prefer the exec error.
|
|
||||||
exec_result.and(Err(err))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#[cfg(not(feature = "artifact-graph"))]
|
|
||||||
{
|
|
||||||
exec_result.map(|(_, env_ref, _)| env_ref)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2198,7 +2083,7 @@ w = f() + f()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get the id_generator from the first execution.
|
// Get the id_generator from the first execution.
|
||||||
let id_generator = cache::read_old_ast().await.unwrap().exec_state.mod_local.id_generator;
|
let id_generator = cache::read_old_ast().await.unwrap().main.exec_state.id_generator;
|
||||||
|
|
||||||
let code = r#"sketch001 = startSketchOn(XZ)
|
let code = r#"sketch001 = startSketchOn(XZ)
|
||||||
|> startProfile(at = [62.74, 206.13])
|
|> startProfile(at = [62.74, 206.13])
|
||||||
@ -2219,7 +2104,7 @@ w = f() + f()
|
|||||||
// Execute the program.
|
// Execute the program.
|
||||||
ctx.run_with_caching(program).await.unwrap();
|
ctx.run_with_caching(program).await.unwrap();
|
||||||
|
|
||||||
let new_id_generator = cache::read_old_ast().await.unwrap().exec_state.mod_local.id_generator;
|
let new_id_generator = cache::read_old_ast().await.unwrap().main.exec_state.id_generator;
|
||||||
|
|
||||||
assert_eq!(id_generator, new_id_generator);
|
assert_eq!(id_generator, new_id_generator);
|
||||||
}
|
}
|
||||||
|
@ -12,19 +12,19 @@ use uuid::Uuid;
|
|||||||
use crate::execution::{Artifact, ArtifactCommand, ArtifactGraph, ArtifactId};
|
use crate::execution::{Artifact, ArtifactCommand, ArtifactGraph, ArtifactId};
|
||||||
use crate::{
|
use crate::{
|
||||||
errors::{KclError, KclErrorDetails, Severity},
|
errors::{KclError, KclErrorDetails, Severity},
|
||||||
|
exec::DefaultPlanes,
|
||||||
execution::{
|
execution::{
|
||||||
annotations,
|
annotations,
|
||||||
cad_op::Operation,
|
cad_op::Operation,
|
||||||
id_generator::IdGenerator,
|
id_generator::IdGenerator,
|
||||||
memory::{ProgramMemory, Stack},
|
memory::{ProgramMemory, Stack},
|
||||||
types,
|
types::{self, NumericType},
|
||||||
types::NumericType,
|
|
||||||
EnvironmentRef, ExecOutcome, ExecutorSettings, KclValue, UnitAngle, UnitLen,
|
EnvironmentRef, ExecOutcome, ExecutorSettings, KclValue, UnitAngle, UnitLen,
|
||||||
},
|
},
|
||||||
modules::{ModuleId, ModuleInfo, ModuleLoader, ModulePath, ModuleRepr, ModuleSource},
|
modules::{ModuleId, ModuleInfo, ModuleLoader, ModulePath, ModuleRepr, ModuleSource},
|
||||||
parsing::ast::types::Annotation,
|
parsing::ast::types::{Annotation, NodeRef},
|
||||||
source_range::SourceRange,
|
source_range::SourceRange,
|
||||||
CompilationError,
|
CompilationError, EngineManager, ExecutorContext, KclErrorWithOutputs,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// State for executing a program.
|
/// State for executing a program.
|
||||||
@ -32,7 +32,6 @@ use crate::{
|
|||||||
pub struct ExecState {
|
pub struct ExecState {
|
||||||
pub(super) global: GlobalState,
|
pub(super) global: GlobalState,
|
||||||
pub(super) mod_local: ModuleState,
|
pub(super) mod_local: ModuleState,
|
||||||
pub(super) exec_context: Option<super::ExecutorContext>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type ModuleInfoMap = IndexMap<ModuleId, ModuleInfo>;
|
pub type ModuleInfoMap = IndexMap<ModuleId, ModuleInfo>;
|
||||||
@ -45,33 +44,39 @@ pub(super) struct GlobalState {
|
|||||||
pub id_to_source: IndexMap<ModuleId, ModuleSource>,
|
pub id_to_source: IndexMap<ModuleId, ModuleSource>,
|
||||||
/// Map from module ID to module info.
|
/// Map from module ID to module info.
|
||||||
pub module_infos: ModuleInfoMap,
|
pub module_infos: ModuleInfoMap,
|
||||||
/// Output map of UUIDs to artifacts.
|
|
||||||
#[cfg(feature = "artifact-graph")]
|
|
||||||
pub artifacts: IndexMap<ArtifactId, Artifact>,
|
|
||||||
/// Output commands to allow building the artifact graph by the caller.
|
|
||||||
/// These are accumulated in the [`ExecutorContext`] but moved here for
|
|
||||||
/// convenience of the execution cache.
|
|
||||||
#[cfg(feature = "artifact-graph")]
|
|
||||||
pub artifact_commands: Vec<ArtifactCommand>,
|
|
||||||
/// Responses from the engine for `artifact_commands`. We need to cache
|
|
||||||
/// this so that we can build the artifact graph. These are accumulated in
|
|
||||||
/// the [`ExecutorContext`] but moved here for convenience of the execution
|
|
||||||
/// cache.
|
|
||||||
#[cfg(feature = "artifact-graph")]
|
|
||||||
pub artifact_responses: IndexMap<Uuid, WebSocketResponse>,
|
|
||||||
/// Output artifact graph.
|
|
||||||
#[cfg(feature = "artifact-graph")]
|
|
||||||
pub artifact_graph: ArtifactGraph,
|
|
||||||
/// Operations that have been performed in execution order, for display in
|
|
||||||
/// the Feature Tree.
|
|
||||||
#[cfg(feature = "artifact-graph")]
|
|
||||||
pub operations: Vec<Operation>,
|
|
||||||
/// Module loader.
|
/// Module loader.
|
||||||
pub mod_loader: ModuleLoader,
|
pub mod_loader: ModuleLoader,
|
||||||
/// Errors and warnings.
|
/// Errors and warnings.
|
||||||
pub errors: Vec<CompilationError>,
|
pub errors: Vec<CompilationError>,
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub artifacts: ArtifactState,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "artifact-graph")]
|
||||||
|
#[derive(Debug, Clone, Default)]
|
||||||
|
pub(super) struct ArtifactState {
|
||||||
|
/// Output map of UUIDs to artifacts.
|
||||||
|
pub artifacts: IndexMap<ArtifactId, Artifact>,
|
||||||
|
/// Output commands to allow building the artifact graph by the caller.
|
||||||
|
/// These are accumulated in the [`ExecutorContext`] but moved here for
|
||||||
|
/// convenience of the execution cache.
|
||||||
|
pub commands: Vec<ArtifactCommand>,
|
||||||
|
/// Responses from the engine for `artifact_commands`. We need to cache
|
||||||
|
/// this so that we can build the artifact graph. These are accumulated in
|
||||||
|
/// the [`ExecutorContext`] but moved here for convenience of the execution
|
||||||
|
/// cache.
|
||||||
|
pub responses: IndexMap<Uuid, WebSocketResponse>,
|
||||||
|
/// Output artifact graph.
|
||||||
|
pub graph: ArtifactGraph,
|
||||||
|
/// Operations that have been performed in execution order, for display in
|
||||||
|
/// the Feature Tree.
|
||||||
|
pub operations: Vec<Operation>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "artifact-graph"))]
|
||||||
|
#[derive(Debug, Clone, Default)]
|
||||||
|
pub(super) struct ArtifactState {}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub(super) struct ModuleState {
|
pub(super) struct ModuleState {
|
||||||
/// The id generator for this module.
|
/// The id generator for this module.
|
||||||
@ -98,7 +103,6 @@ impl ExecState {
|
|||||||
ExecState {
|
ExecState {
|
||||||
global: GlobalState::new(&exec_context.settings),
|
global: GlobalState::new(&exec_context.settings),
|
||||||
mod_local: ModuleState::new(ModulePath::Main, ProgramMemory::new(), Default::default()),
|
mod_local: ModuleState::new(ModulePath::Main, ProgramMemory::new(), Default::default()),
|
||||||
exec_context: Some(exec_context.clone()),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -108,7 +112,6 @@ impl ExecState {
|
|||||||
*self = ExecState {
|
*self = ExecState {
|
||||||
global,
|
global,
|
||||||
mod_local: ModuleState::new(self.mod_local.path.clone(), ProgramMemory::new(), Default::default()),
|
mod_local: ModuleState::new(self.mod_local.path.clone(), ProgramMemory::new(), Default::default()),
|
||||||
exec_context: Some(exec_context.clone()),
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,45 +133,26 @@ impl ExecState {
|
|||||||
/// Convert to execution outcome when running in WebAssembly. We want to
|
/// Convert to execution outcome when running in WebAssembly. We want to
|
||||||
/// reduce the amount of data that crosses the WASM boundary as much as
|
/// reduce the amount of data that crosses the WASM boundary as much as
|
||||||
/// possible.
|
/// possible.
|
||||||
pub async fn to_exec_outcome(self, main_ref: EnvironmentRef) -> ExecOutcome {
|
pub async fn to_exec_outcome(self, main_ref: EnvironmentRef, ctx: &ExecutorContext) -> ExecOutcome {
|
||||||
// Fields are opt-in so that we don't accidentally leak private internal
|
// Fields are opt-in so that we don't accidentally leak private internal
|
||||||
// state when we add more to ExecState.
|
// state when we add more to ExecState.
|
||||||
ExecOutcome {
|
ExecOutcome {
|
||||||
variables: self
|
variables: self.mod_local.variables(main_ref),
|
||||||
.stack()
|
filenames: self.global.filenames(),
|
||||||
.find_all_in_env(main_ref)
|
|
||||||
.map(|(k, v)| (k.clone(), v.clone()))
|
|
||||||
.collect(),
|
|
||||||
#[cfg(feature = "artifact-graph")]
|
#[cfg(feature = "artifact-graph")]
|
||||||
operations: self.global.operations,
|
operations: self.global.artifacts.operations,
|
||||||
#[cfg(feature = "artifact-graph")]
|
#[cfg(feature = "artifact-graph")]
|
||||||
artifact_commands: self.global.artifact_commands,
|
artifact_commands: self.global.artifacts.commands,
|
||||||
#[cfg(feature = "artifact-graph")]
|
#[cfg(feature = "artifact-graph")]
|
||||||
artifact_graph: self.global.artifact_graph,
|
artifact_graph: self.global.artifacts.graph,
|
||||||
errors: self.global.errors,
|
errors: self.global.errors,
|
||||||
filenames: self
|
default_planes: ctx.engine.get_default_planes().read().await.clone(),
|
||||||
.global
|
|
||||||
.path_to_source_id
|
|
||||||
.iter()
|
|
||||||
.map(|(k, v)| ((*v), k.clone()))
|
|
||||||
.collect(),
|
|
||||||
default_planes: if let Some(ctx) = &self.exec_context {
|
|
||||||
ctx.engine.get_default_planes().read().await.clone()
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn to_mock_exec_outcome(self, main_ref: EnvironmentRef) -> ExecOutcome {
|
pub async fn to_mock_exec_outcome(self, main_ref: EnvironmentRef, ctx: &ExecutorContext) -> ExecOutcome {
|
||||||
// Fields are opt-in so that we don't accidentally leak private internal
|
|
||||||
// state when we add more to ExecState.
|
|
||||||
ExecOutcome {
|
ExecOutcome {
|
||||||
variables: self
|
variables: self.mod_local.variables(main_ref),
|
||||||
.stack()
|
|
||||||
.find_all_in_env(main_ref)
|
|
||||||
.map(|(k, v)| (k.clone(), v.clone()))
|
|
||||||
.collect(),
|
|
||||||
#[cfg(feature = "artifact-graph")]
|
#[cfg(feature = "artifact-graph")]
|
||||||
operations: Default::default(),
|
operations: Default::default(),
|
||||||
#[cfg(feature = "artifact-graph")]
|
#[cfg(feature = "artifact-graph")]
|
||||||
@ -177,11 +161,7 @@ impl ExecState {
|
|||||||
artifact_graph: Default::default(),
|
artifact_graph: Default::default(),
|
||||||
errors: self.global.errors,
|
errors: self.global.errors,
|
||||||
filenames: Default::default(),
|
filenames: Default::default(),
|
||||||
default_planes: if let Some(ctx) = &self.exec_context {
|
default_planes: ctx.engine.get_default_planes().read().await.clone(),
|
||||||
ctx.engine.get_default_planes().read().await.clone()
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -204,12 +184,12 @@ impl ExecState {
|
|||||||
#[cfg(feature = "artifact-graph")]
|
#[cfg(feature = "artifact-graph")]
|
||||||
pub(crate) fn add_artifact(&mut self, artifact: Artifact) {
|
pub(crate) fn add_artifact(&mut self, artifact: Artifact) {
|
||||||
let id = artifact.id();
|
let id = artifact.id();
|
||||||
self.global.artifacts.insert(id, artifact);
|
self.global.artifacts.artifacts.insert(id, artifact);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn push_op(&mut self, op: Operation) {
|
pub(crate) fn push_op(&mut self, op: Operation) {
|
||||||
#[cfg(feature = "artifact-graph")]
|
#[cfg(feature = "artifact-graph")]
|
||||||
self.global.operations.push(op);
|
self.global.artifacts.operations.push(op);
|
||||||
#[cfg(not(feature = "artifact-graph"))]
|
#[cfg(not(feature = "artifact-graph"))]
|
||||||
drop(op);
|
drop(op);
|
||||||
}
|
}
|
||||||
@ -251,10 +231,6 @@ impl ExecState {
|
|||||||
self.global.id_to_source.insert(id, source.clone());
|
self.global.id_to_source.insert(id, source.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn get_source(&self, id: ModuleId) -> Option<&ModuleSource> {
|
|
||||||
self.global.id_to_source.get(&id)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) fn add_module(&mut self, id: ModuleId, path: ModulePath, repr: ModuleRepr) {
|
pub(super) fn add_module(&mut self, id: ModuleId, path: ModulePath, repr: ModuleRepr) {
|
||||||
debug_assert!(self.global.path_to_source_id.contains_key(&path));
|
debug_assert!(self.global.path_to_source_id.contains_key(&path));
|
||||||
let module_info = ModuleInfo { id, repr, path };
|
let module_info = ModuleInfo { id, repr, path };
|
||||||
@ -300,6 +276,71 @@ impl ExecState {
|
|||||||
pub(crate) fn pipe_value(&self) -> Option<&KclValue> {
|
pub(crate) fn pipe_value(&self) -> Option<&KclValue> {
|
||||||
self.mod_local.pipe_value.as_ref()
|
self.mod_local.pipe_value.as_ref()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn error_with_outputs(
|
||||||
|
&self,
|
||||||
|
error: KclError,
|
||||||
|
default_planes: Option<DefaultPlanes>,
|
||||||
|
) -> KclErrorWithOutputs {
|
||||||
|
let module_id_to_module_path: IndexMap<ModuleId, ModulePath> = self
|
||||||
|
.global
|
||||||
|
.path_to_source_id
|
||||||
|
.iter()
|
||||||
|
.map(|(k, v)| ((*v), k.clone()))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
KclErrorWithOutputs::new(
|
||||||
|
error,
|
||||||
|
self.errors().to_vec(),
|
||||||
|
#[cfg(feature = "artifact-graph")]
|
||||||
|
self.global.artifacts.operations.clone(),
|
||||||
|
#[cfg(feature = "artifact-graph")]
|
||||||
|
self.global.artifacts.commands.clone(),
|
||||||
|
#[cfg(feature = "artifact-graph")]
|
||||||
|
self.global.artifacts.graph.clone(),
|
||||||
|
module_id_to_module_path,
|
||||||
|
self.global.id_to_source.clone(),
|
||||||
|
default_planes,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "artifact-graph")]
|
||||||
|
pub(crate) async fn build_artifact_graph(
|
||||||
|
&mut self,
|
||||||
|
engine: &Arc<Box<dyn EngineManager>>,
|
||||||
|
program: NodeRef<'_, crate::parsing::ast::types::Program>,
|
||||||
|
) -> Result<(), KclError> {
|
||||||
|
let new_commands = engine.take_artifact_commands().await;
|
||||||
|
let new_responses = engine.take_responses().await;
|
||||||
|
let initial_graph = self.global.artifacts.graph.clone();
|
||||||
|
|
||||||
|
// Build the artifact graph.
|
||||||
|
let graph_result = crate::execution::artifact::build_artifact_graph(
|
||||||
|
&new_commands,
|
||||||
|
&new_responses,
|
||||||
|
program,
|
||||||
|
&mut self.global.artifacts.artifacts,
|
||||||
|
initial_graph,
|
||||||
|
);
|
||||||
|
// Move the artifact commands and responses into ExecState to
|
||||||
|
// simplify cache management and error creation.
|
||||||
|
self.global.artifacts.commands.extend(new_commands);
|
||||||
|
self.global.artifacts.responses.extend(new_responses);
|
||||||
|
|
||||||
|
let artifact_graph = graph_result?;
|
||||||
|
self.global.artifacts.graph = artifact_graph;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "artifact-graph"))]
|
||||||
|
pub(crate) async fn build_artifact_graph(
|
||||||
|
&mut self,
|
||||||
|
_engine: &Arc<Box<dyn EngineManager>>,
|
||||||
|
_program: NodeRef<'_, crate::parsing::ast::types::Program>,
|
||||||
|
) -> Result<(), KclError> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GlobalState {
|
impl GlobalState {
|
||||||
@ -307,16 +348,7 @@ impl GlobalState {
|
|||||||
let mut global = GlobalState {
|
let mut global = GlobalState {
|
||||||
path_to_source_id: Default::default(),
|
path_to_source_id: Default::default(),
|
||||||
module_infos: Default::default(),
|
module_infos: Default::default(),
|
||||||
#[cfg(feature = "artifact-graph")]
|
|
||||||
artifacts: Default::default(),
|
artifacts: Default::default(),
|
||||||
#[cfg(feature = "artifact-graph")]
|
|
||||||
artifact_commands: Default::default(),
|
|
||||||
#[cfg(feature = "artifact-graph")]
|
|
||||||
artifact_responses: Default::default(),
|
|
||||||
#[cfg(feature = "artifact-graph")]
|
|
||||||
artifact_graph: Default::default(),
|
|
||||||
#[cfg(feature = "artifact-graph")]
|
|
||||||
operations: Default::default(),
|
|
||||||
mod_loader: Default::default(),
|
mod_loader: Default::default(),
|
||||||
errors: Default::default(),
|
errors: Default::default(),
|
||||||
id_to_source: Default::default(),
|
id_to_source: Default::default(),
|
||||||
@ -339,6 +371,14 @@ impl GlobalState {
|
|||||||
.insert(ModulePath::Local { value: root_path }, root_id);
|
.insert(ModulePath::Local { value: root_path }, root_id);
|
||||||
global
|
global
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(super) fn filenames(&self) -> IndexMap<ModuleId, ModulePath> {
|
||||||
|
self.path_to_source_id.iter().map(|(k, v)| ((*v), k.clone())).collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn get_source(&self, id: ModuleId) -> Option<&ModuleSource> {
|
||||||
|
self.id_to_source.get(&id)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ModuleState {
|
impl ModuleState {
|
||||||
@ -358,6 +398,13 @@ impl ModuleState {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(super) fn variables(&self, main_ref: EnvironmentRef) -> IndexMap<String, KclValue> {
|
||||||
|
self.stack
|
||||||
|
.find_all_in_env(main_ref)
|
||||||
|
.map(|(k, v)| (k.clone(), v.clone()))
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default, Clone, Deserialize, Serialize, PartialEq, Eq, ts_rs::TS, JsonSchema)]
|
#[derive(Debug, Default, Clone, Deserialize, Serialize, PartialEq, Eq, ts_rs::TS, JsonSchema)]
|
||||||
|
@ -163,7 +163,7 @@ async fn execute_test(test: &Test, render_to_png: bool, export_step: bool) {
|
|||||||
// Run the program.
|
// Run the program.
|
||||||
let exec_res = crate::test_server::execute_and_snapshot_ast(ast, Some(test.entry_point.clone()), export_step).await;
|
let exec_res = crate::test_server::execute_and_snapshot_ast(ast, Some(test.entry_point.clone()), export_step).await;
|
||||||
match exec_res {
|
match exec_res {
|
||||||
Ok((exec_state, env_ref, png, step)) => {
|
Ok((exec_state, ctx, env_ref, png, step)) => {
|
||||||
let fail_path = test.output_dir.join("execution_error.snap");
|
let fail_path = test.output_dir.join("execution_error.snap");
|
||||||
if std::fs::exists(&fail_path).unwrap() {
|
if std::fs::exists(&fail_path).unwrap() {
|
||||||
panic!("This test case is expected to fail, but it passed. If this is intended, and the test should actually be passing now, please delete kcl-lib/{}", fail_path.to_string_lossy())
|
panic!("This test case is expected to fail, but it passed. If this is intended, and the test should actually be passing now, please delete kcl-lib/{}", fail_path.to_string_lossy())
|
||||||
@ -181,7 +181,7 @@ async fn execute_test(test: &Test, render_to_png: bool, export_step: bool) {
|
|||||||
panic!("Step data was empty");
|
panic!("Step data was empty");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let outcome = exec_state.to_exec_outcome(env_ref).await;
|
let outcome = exec_state.to_exec_outcome(env_ref, &ctx).await;
|
||||||
|
|
||||||
let mem_result = catch_unwind(AssertUnwindSafe(|| {
|
let mem_result = catch_unwind(AssertUnwindSafe(|| {
|
||||||
assert_snapshot(test, "Variables in memory after executing", || {
|
assert_snapshot(test, "Variables in memory after executing", || {
|
||||||
|
@ -36,7 +36,16 @@ pub async fn execute_and_snapshot_ast(
|
|||||||
ast: Program,
|
ast: Program,
|
||||||
current_file: Option<PathBuf>,
|
current_file: Option<PathBuf>,
|
||||||
with_export_step: bool,
|
with_export_step: bool,
|
||||||
) -> Result<(ExecState, EnvironmentRef, image::DynamicImage, Option<Vec<u8>>), ExecErrorWithState> {
|
) -> Result<
|
||||||
|
(
|
||||||
|
ExecState,
|
||||||
|
ExecutorContext,
|
||||||
|
EnvironmentRef,
|
||||||
|
image::DynamicImage,
|
||||||
|
Option<Vec<u8>>,
|
||||||
|
),
|
||||||
|
ExecErrorWithState,
|
||||||
|
> {
|
||||||
let ctx = new_context(true, current_file).await?;
|
let ctx = new_context(true, current_file).await?;
|
||||||
let (exec_state, env, img) = match do_execute_and_snapshot(&ctx, ast).await {
|
let (exec_state, env, img) = match do_execute_and_snapshot(&ctx, ast).await {
|
||||||
Ok((exec_state, env_ref, img)) => (exec_state, env_ref, img),
|
Ok((exec_state, env_ref, img)) => (exec_state, env_ref, img),
|
||||||
@ -64,7 +73,7 @@ pub async fn execute_and_snapshot_ast(
|
|||||||
step = files.into_iter().next().map(|f| f.contents);
|
step = files.into_iter().next().map(|f| f.contents);
|
||||||
}
|
}
|
||||||
ctx.close().await;
|
ctx.close().await;
|
||||||
Ok((exec_state, env, img, step))
|
Ok((exec_state, ctx, env, img, step))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn execute_and_snapshot_no_auth(
|
pub async fn execute_and_snapshot_no_auth(
|
||||||
|
@ -3,10 +3,7 @@
|
|||||||
mod ast_node;
|
mod ast_node;
|
||||||
mod ast_visitor;
|
mod ast_visitor;
|
||||||
mod ast_walk;
|
mod ast_walk;
|
||||||
mod import_graph;
|
|
||||||
|
|
||||||
pub use ast_node::Node;
|
pub(crate) use ast_node::Node;
|
||||||
pub use ast_visitor::Visitable;
|
pub(crate) use ast_visitor::Visitable;
|
||||||
pub use ast_walk::walk;
|
pub(crate) use ast_walk::walk;
|
||||||
pub use import_graph::import_graph;
|
|
||||||
pub(crate) use import_graph::{import_universe, Universe, UniverseMap};
|
|
||||||
|
Reference in New Issue
Block a user