use std::collections::HashMap;

use async_recursion::async_recursion;
use ezpz::Constraint;
use ezpz::NonLinearSystemError;
use indexmap::IndexMap;
use kcl_api::Group;
use kcl_api::NumericType;
use kcl_api::Operation;
use kcl_api::UnitAngle;

use crate::CompilationIssue;
use crate::NodePath;
use crate::NodePathExt;
use crate::SourceRange;
use crate::errors::KclError;
use crate::errors::KclErrorDetails;
use crate::exec::Sketch;
use crate::execution::AbstractSegment;
use crate::execution::Artifact;
use crate::execution::ArtifactId;
use crate::execution::BodyType;
use crate::execution::ConstraintKind;
use crate::execution::ControlFlowKind;
use crate::execution::EarlyReturn;
use crate::execution::EnvironmentRef;
use crate::execution::ExecState;
use crate::execution::ExecutorContext;
use crate::execution::KclValue;
use crate::execution::KclValueControlFlow;
use crate::execution::Metadata;
use crate::execution::ModelingCmdMeta;
use crate::execution::ModuleArtifactState;
use crate::execution::PreserveMem;
use crate::execution::SKETCH_BLOCK_PARAM_ON;
use crate::execution::SKETCH_OBJECT_META;
use crate::execution::SKETCH_OBJECT_META_SKETCH;
use crate::execution::Segment;
use crate::execution::SegmentKind;
use crate::execution::SegmentRepr;
use crate::execution::SketchConstraintKind;
use crate::execution::SketchSurface;
use crate::execution::StatementKind;
use crate::execution::TagIdentifier;
use crate::execution::UnsolvedExpr;
use crate::execution::UnsolvedSegment;
use crate::execution::UnsolvedSegmentKind;
use crate::execution::annotations;
use crate::execution::annotations::FnAttrs;
use crate::execution::cad_op::op_from_kcl_value;
use crate::execution::control_continue;
use crate::execution::early_return;
use crate::execution::fn_call::Arg;
use crate::execution::fn_call::Args;
use crate::execution::fn_call::unexpected_kw_arg_message;
use crate::execution::kcl_value::FunctionSource;
use crate::execution::kcl_value::KclFunctionSourceParams;
use crate::execution::kcl_value::KclObjectKind;
use crate::execution::kcl_value::TypeDef;
use crate::execution::memory::SKETCH_PREFIX;
use crate::execution::memory::{self};
use crate::execution::sketch_constraint_status_for_sketch;
use crate::execution::sketch_solve::FreedomAnalysis;
use crate::execution::sketch_solve::Solved;
use crate::execution::sketch_solve::create_segment_scene_objects;
use crate::execution::sketch_solve::normalize_to_solver_angle_unit;
use crate::execution::sketch_solve::normalize_to_solver_distance_unit;
use crate::execution::sketch_solve::solver_numeric_type;
use crate::execution::sketch_solve::substitute_sketch_var_in_segment;
use crate::execution::sketch_solve::substitute_sketch_vars;
use crate::execution::state::ModuleState;
use crate::execution::state::SketchBlockState;
use crate::execution::types::NumericTypeExt;
use crate::execution::types::PrimitiveType;
use crate::execution::types::RuntimeType;
use crate::front::LineCtor;
use crate::front::Object;
use crate::front::ObjectId;
use crate::front::ObjectKind;
use crate::front::PointCtor;
use crate::modules::ModuleExecutionOutcome;
use crate::modules::ModuleId;
use crate::modules::ModulePath;
use crate::modules::ModuleRepr;
use crate::parsing::ast::types::Annotation;
use crate::parsing::ast::types::ArrayExpression;
use crate::parsing::ast::types::ArrayRangeExpression;
use crate::parsing::ast::types::AscribedExpression;
use crate::parsing::ast::types::BinaryExpression;
use crate::parsing::ast::types::BinaryOperator;
use crate::parsing::ast::types::BinaryPart;
use crate::parsing::ast::types::BodyItem;
use crate::parsing::ast::types::CodeBlock;
use crate::parsing::ast::types::Expr;
use crate::parsing::ast::types::IfExpression;
use crate::parsing::ast::types::ImportPath;
use crate::parsing::ast::types::ImportSelector;
use crate::parsing::ast::types::ItemVisibility;
use crate::parsing::ast::types::MemberExpression;
use crate::parsing::ast::types::Name;
use crate::parsing::ast::types::Node;
use crate::parsing::ast::types::ObjectExpression;
use crate::parsing::ast::types::PipeExpression;
use crate::parsing::ast::types::Program;
use crate::parsing::ast::types::SketchBlock;
use crate::parsing::ast::types::SketchVar;
use crate::parsing::ast::types::TagDeclarator;
use crate::parsing::ast::types::Type;
use crate::parsing::ast::types::UnaryExpression;
use crate::parsing::ast::types::UnaryOperator;
use crate::std::StdFnProps;
use crate::std::args::FromKclValue;
use crate::std::args::TyF64;
use crate::std::shapes::SketchOrSurface;
use crate::std::sketch::ensure_sketch_plane_in_engine;
use crate::std::solver::SOLVER_CONVERGENCE_TOLERANCE;
use crate::std::solver::create_segments_in_engine;

fn internal_err(message: impl Into<String>, range: impl Into<SourceRange>) -> KclError {
    KclError::new_internal(KclErrorDetails::new(message.into(), vec![range.into()]))
}

fn datum_point_from_constrainable(
    point: &crate::execution::ConstrainablePoint2d,
    range: SourceRange,
) -> Result<ezpz::datatypes::inputs::DatumPoint, KclError> {
    Ok(ezpz::datatypes::inputs::DatumPoint::new_xy(
        point.vars.x.to_constraint_id(range)?,
        point.vars.y.to_constraint_id(range)?,
    ))
}

fn push_fixed_origin_point(
    sketch_block_state: &mut SketchBlockState,
    sketch_var_ty: NumericType,
    range: SourceRange,
) -> Result<ezpz::datatypes::inputs::DatumPoint, KclError> {
    let origin_x_id = sketch_block_state.next_sketch_var_id();
    sketch_block_state.sketch_vars.push(KclValue::SketchVar {
        value: Box::new(crate::execution::SketchVar {
            id: origin_x_id,
            initial_value: 0.0,
            ty: sketch_var_ty,
            // Synthesized fixed origin coord; not source-backed.
            node_path: None,
            meta: vec![],
        }),
    });
    let origin_y_id = sketch_block_state.next_sketch_var_id();
    sketch_block_state.sketch_vars.push(KclValue::SketchVar {
        value: Box::new(crate::execution::SketchVar {
            id: origin_y_id,
            initial_value: 0.0,
            ty: sketch_var_ty,
            // Synthesized fixed origin coord; not source-backed.
            node_path: None,
            meta: vec![],
        }),
    });

    sketch_block_state
        .solver_constraints
        .push(Constraint::Fixed(origin_x_id.to_constraint_id(range)?, 0.0));
    sketch_block_state
        .solver_constraints
        .push(Constraint::Fixed(origin_y_id.to_constraint_id(range)?, 0.0));

    Ok(ezpz::datatypes::inputs::DatumPoint::new_xy(
        origin_x_id.to_constraint_id(range)?,
        origin_y_id.to_constraint_id(range)?,
    ))
}

fn datum_point_from_constrainable_or_origin(
    sketch_block_state: &mut SketchBlockState,
    sketch_var_ty: NumericType,
    point: &crate::execution::ConstrainablePoint2dOrOrigin,
    range: SourceRange,
) -> Result<ezpz::datatypes::inputs::DatumPoint, KclError> {
    match point {
        crate::execution::ConstrainablePoint2dOrOrigin::Point(point) => datum_point_from_constrainable(point, range),
        crate::execution::ConstrainablePoint2dOrOrigin::Origin => {
            push_fixed_origin_point(sketch_block_state, sketch_var_ty, range)
        }
    }
}

fn datum_line_from_constrainable(
    line: &crate::execution::ConstrainableLine2d,
    range: SourceRange,
) -> Result<ezpz::datatypes::inputs::DatumLineSegment, KclError> {
    Ok(ezpz::datatypes::inputs::DatumLineSegment::new(
        ezpz::datatypes::inputs::DatumPoint::new_xy(
            line.vars[0].x.to_constraint_id(range)?,
            line.vars[0].y.to_constraint_id(range)?,
        ),
        ezpz::datatypes::inputs::DatumPoint::new_xy(
            line.vars[1].x.to_constraint_id(range)?,
            line.vars[1].y.to_constraint_id(range)?,
        ),
    ))
}

fn sketch_var_initial_value(
    sketch_vars: &[KclValue],
    id: crate::execution::SketchVarId,
    exec_state: &mut ExecState,
    range: SourceRange,
    description: &str,
) -> Result<f64, KclError> {
    sketch_vars
        .get(id.0)
        .and_then(KclValue::as_sketch_var)
        .map(|sketch_var| {
            sketch_var
                .initial_value_to_solver_units(exec_state, range, description)
                .map(|value| value.n)
        })
        .transpose()?
        .ok_or_else(|| internal_err(format!("Missing sketch variable initial value for id {}", id.0), range))
}

fn constrainable_point_initial_position(
    sketch_vars: &[KclValue],
    point: &crate::execution::ConstrainablePoint2d,
    exec_state: &mut ExecState,
    range: SourceRange,
    description: &str,
) -> Result<[f64; 2], KclError> {
    Ok([
        sketch_var_initial_value(sketch_vars, point.vars.x, exec_state, range, description)?,
        sketch_var_initial_value(sketch_vars, point.vars.y, exec_state, range, description)?,
    ])
}

fn constrainable_point_or_origin_initial_position(
    sketch_vars: &[KclValue],
    point: &crate::execution::ConstrainablePoint2dOrOrigin,
    exec_state: &mut ExecState,
    range: SourceRange,
    description: &str,
) -> Result<[f64; 2], KclError> {
    match point {
        crate::execution::ConstrainablePoint2dOrOrigin::Point(point) => {
            constrainable_point_initial_position(sketch_vars, point, exec_state, range, description)
        }
        crate::execution::ConstrainablePoint2dOrOrigin::Origin => Ok([0.0, 0.0]),
    }
}

// These helpers read the current sketch variable guesses so hidden support
// geometry starts near the geometry the user selected. The visible constraint
// value still comes from the KCL RHS. These initial values are only solver
// seeds for new hidden points/radii, which helps ezpz converge to the intended
// geometric branch instead of an equivalent but visually surprising one.
fn constrainable_line_initial_positions(
    sketch_vars: &[KclValue],
    line: &crate::execution::ConstrainableLine2d,
    exec_state: &mut ExecState,
    range: SourceRange,
    description: &str,
) -> Result<([f64; 2], [f64; 2]), KclError> {
    let start = crate::execution::ConstrainablePoint2d {
        vars: line.vars[0].clone(),
        object_id: line.object_id,
    };
    let end = crate::execution::ConstrainablePoint2d {
        vars: line.vars[1].clone(),
        object_id: line.object_id,
    };
    Ok((
        constrainable_point_initial_position(sketch_vars, &start, exec_state, range, description)?,
        constrainable_point_initial_position(sketch_vars, &end, exec_state, range, description)?,
    ))
}

fn projected_point_on_line_initial_position(
    sketch_vars: &[KclValue],
    point: &crate::execution::ConstrainablePoint2dOrOrigin,
    line: &crate::execution::ConstrainableLine2d,
    exec_state: &mut ExecState,
    range: SourceRange,
) -> Result<[f64; 2], KclError> {
    let point = constrainable_point_or_origin_initial_position(
        sketch_vars,
        point,
        exec_state,
        range,
        "point-line distance initial point",
    )?;
    let (line_start, line_end) =
        constrainable_line_initial_positions(sketch_vars, line, exec_state, range, "point-line distance initial line")?;
    let dx = line_end[0] - line_start[0];
    let dy = line_end[1] - line_start[1];
    let len_sq = dx * dx + dy * dy;
    if len_sq == 0.0 {
        return Err(KclError::new_semantic(KclErrorDetails::new(
            "distance() line input must have non-zero length".to_owned(),
            vec![range],
        )));
    }

    // Project the point onto the infinite target line. `t` is the scalar
    // projection of the point-start vector onto the line direction.
    let t = ((point[0] - line_start[0]) * dx + (point[1] - line_start[1]) * dy) / len_sq;
    Ok([line_start[0] + t * dx, line_start[1] + t * dy])
}

fn constrainable_points_initial_distance(
    sketch_vars: &[KclValue],
    point0: &crate::execution::ConstrainablePoint2d,
    point1: &crate::execution::ConstrainablePoint2d,
    exec_state: &mut ExecState,
    range: SourceRange,
    description: &str,
) -> Result<f64, KclError> {
    let p0 = constrainable_point_initial_position(sketch_vars, point0, exec_state, range, description)?;
    let p1 = constrainable_point_initial_position(sketch_vars, point1, exec_state, range, description)?;
    Ok(libm::hypot(p0[0] - p1[0], p0[1] - p1[1]))
}

// Circular distance lowering needs an ezpz DatumCircle, but arcs/circles in
// KCL are represented by points. This bundles the center/start/end datums and
// seeds a hidden radius variable from the current center-start distance.
#[derive(Clone, Copy)]
struct CircularDistanceDatums {
    center: ezpz::datatypes::inputs::DatumPoint,
    start: ezpz::datatypes::inputs::DatumPoint,
    end: Option<ezpz::datatypes::inputs::DatumPoint>,
    radius_initial_value: f64,
}

fn circular_distance_datums(
    sketch_vars: &[KclValue],
    center: &crate::execution::ConstrainablePoint2d,
    start: &crate::execution::ConstrainablePoint2d,
    end: Option<&crate::execution::ConstrainablePoint2d>,
    exec_state: &mut ExecState,
    range: SourceRange,
) -> Result<CircularDistanceDatums, KclError> {
    Ok(CircularDistanceDatums {
        center: datum_point_from_constrainable(center, range)?,
        start: datum_point_from_constrainable(start, range)?,
        end: end.map(|end| datum_point_from_constrainable(end, range)).transpose()?,
        radius_initial_value: constrainable_points_initial_distance(
            sketch_vars,
            center,
            start,
            exec_state,
            range,
            "circular distance radius initial value",
        )?,
    })
}

fn circular_circular_support_initial_position(
    sketch_vars: &[KclValue],
    center0: &crate::execution::ConstrainablePoint2d,
    center1: &crate::execution::ConstrainablePoint2d,
    radius0: f64,
    distance_value: f64,
    exec_state: &mut ExecState,
    range: SourceRange,
) -> Result<[f64; 2], KclError> {
    let center0_initial =
        constrainable_point_initial_position(sketch_vars, center0, exec_state, range, "circular distance center")?;
    let center1_initial =
        constrainable_point_initial_position(sketch_vars, center1, exec_state, range, "circular distance center")?;
    let dx = center1_initial[0] - center0_initial[0];
    let dy = center1_initial[1] - center0_initial[1];
    let center_distance = libm::hypot(dx, dy);
    // The circular-circular distance lowering uses a hidden spacer circle
    // with radius d/2 tangent to both targets. Seed its center on the
    // center-to-center ray at r0 + d/2 so the nonlinear solver starts on the
    // intended between-centers tangency branch.
    let support_distance = radius0 + distance_value / 2.0;

    if center_distance <= f64::EPSILON {
        // Concentric initial guesses have no center-to-center direction, so
        // pick a deterministic horizontal ray for the hidden spacer point.
        return Ok([center0_initial[0] + support_distance, center0_initial[1]]);
    }

    Ok([
        center0_initial[0] + dx / center_distance * support_distance,
        center0_initial[1] + dy / center_distance * support_distance,
    ])
}

fn push_circular_radius_constraints(
    sketch_block_state: &mut SketchBlockState,
    sketch_var_ty: NumericType,
    circular: CircularDistanceDatums,
    range: SourceRange,
) -> Result<ezpz::datatypes::inputs::DatumCircle, KclError> {
    // Create a hidden radius variable and constrain the circular segment's
    // defining points to it. For arcs, both start and end stay on the same
    // radius; for circles, the start point alone defines the radius.
    let circular_radius_id = sketch_block_state.next_sketch_var_id();
    sketch_block_state.sketch_vars.push(KclValue::SketchVar {
        value: Box::new(crate::execution::SketchVar {
            id: circular_radius_id,
            initial_value: circular.radius_initial_value,
            ty: sketch_var_ty,
            // Synthesized hidden radius for circular distance; not source-backed.
            node_path: None,
            meta: vec![],
        }),
    });
    let circular_radius = ezpz::datatypes::inputs::DatumDistance::new(circular_radius_id.to_constraint_id(range)?);

    sketch_block_state.solver_constraints.push(Constraint::DistanceVar(
        circular.start,
        circular.center,
        circular_radius,
    ));
    if let Some(end) = circular.end {
        sketch_block_state
            .solver_constraints
            .push(Constraint::DistanceVar(end, circular.center, circular_radius));
    }

    Ok(ezpz::datatypes::inputs::DatumCircle {
        center: circular.center,
        radius: circular_radius,
    })
}

fn push_circular_distance_constraints(
    sketch_block_state: &mut SketchBlockState,
    sketch_var_ty: NumericType,
    target_point: ezpz::datatypes::inputs::DatumPoint,
    circular: CircularDistanceDatums,
    distance_value: f64,
    range: SourceRange,
) -> Result<(), KclError> {
    let circular_target = push_circular_radius_constraints(sketch_block_state, sketch_var_ty, circular, range)?;

    // Point-circular distance becomes tangency between the target circle and
    // a hidden circle centered on the point with radius equal to the distance.
    let target_distance_id = sketch_block_state.next_sketch_var_id();
    sketch_block_state.sketch_vars.push(KclValue::SketchVar {
        value: Box::new(crate::execution::SketchVar {
            id: target_distance_id,
            initial_value: distance_value,
            ty: sketch_var_ty,
            // Synthesized hidden distance for point-circular tangency; not source-backed.
            node_path: None,
            meta: vec![],
        }),
    });
    let target_distance = ezpz::datatypes::inputs::DatumDistance::new(target_distance_id.to_constraint_id(range)?);

    sketch_block_state
        .solver_constraints
        .push(Constraint::Fixed(target_distance.id, distance_value));

    let target_circle = ezpz::datatypes::inputs::DatumCircle {
        center: target_point,
        radius: target_distance,
    };
    sketch_block_state
        .solver_constraints
        .push(Constraint::CircleTangentToCircle(
            target_circle,
            circular_target,
            ezpz::CircleSide::Exterior,
        ));

    Ok(())
}

fn sketch_on_cache_name(sketch_id: ObjectId) -> String {
    format!("{SKETCH_PREFIX}{}_on", sketch_id.0)
}

fn default_plane_name_from_expr(expr: &Expr) -> Option<crate::engine::PlaneName> {
    fn parse_name(name: &str, negative: bool) -> Option<crate::engine::PlaneName> {
        use crate::engine::PlaneName;

        match (name, negative) {
            ("XY", false) => Some(PlaneName::Xy),
            ("XY", true) => Some(PlaneName::NegXy),
            ("XZ", false) => Some(PlaneName::Xz),
            ("XZ", true) => Some(PlaneName::NegXz),
            ("YZ", false) => Some(PlaneName::Yz),
            ("YZ", true) => Some(PlaneName::NegYz),
            _ => None,
        }
    }

    match expr {
        Expr::Name(name) => {
            if !name.path.is_empty() {
                return None;
            }
            parse_name(&name.name.name, false)
        }
        Expr::UnaryExpression(unary) => {
            if unary.operator != UnaryOperator::Neg {
                return None;
            }
            let crate::parsing::ast::types::BinaryPart::Name(name) = &unary.argument else {
                return None;
            };
            if !name.path.is_empty() {
                return None;
            }
            parse_name(&name.name.name, true)
        }
        _ => None,
    }
}

fn sketch_on_frontend_plane(
    arguments: &[crate::parsing::ast::types::LabeledArg],
    on_object_id: crate::front::ObjectId,
) -> crate::front::Plane {
    for arg in arguments {
        let Some(label) = &arg.label else {
            continue;
        };
        if label.name != SKETCH_BLOCK_PARAM_ON {
            continue;
        }
        if let Some(name) = default_plane_name_from_expr(&arg.arg) {
            return crate::front::Plane::Default(name);
        }
        break;
    }

    crate::front::Plane::Object(on_object_id)
}

impl<'a> StatementKind<'a> {
    fn expect_name(&self) -> &'a str {
        match self {
            StatementKind::Declaration { name } => name,
            StatementKind::Expression => unreachable!(),
        }
    }
}

impl ExecutorContext {
    /// Returns true if importing the prelude should be skipped.
    async fn handle_annotations(
        &self,
        annotations: impl Iterator<Item = &Node<Annotation>>,
        body_type: BodyType,
        exec_state: &mut ExecState,
    ) -> Result<bool, KclError> {
        let mut no_prelude = false;
        for annotation in annotations {
            if annotation.name() == Some(annotations::SETTINGS) {
                if matches!(body_type, BodyType::Root) {
                    let (updated_len, updated_angle) =
                        exec_state.mod_local.settings.update_from_annotation(annotation)?;
                    if updated_len {
                        exec_state.mod_local.explicit_length_units = true;
                    }
                    if updated_angle {
                        exec_state.warn(
                            CompilationIssue::err(
                                annotation.as_source_range(),
                                "Prefer to use explicit units for angles",
                            ),
                            annotations::WARN_ANGLE_UNITS,
                        );
                    }
                } else {
                    exec_state.err(CompilationIssue::err(
                        annotation.as_source_range(),
                        "Settings can only be modified at the top level scope of a file",
                    ));
                }
            } else if annotation.name() == Some(annotations::NO_PRELUDE) {
                if matches!(body_type, BodyType::Root) {
                    no_prelude = true;
                } else {
                    exec_state.err(CompilationIssue::err(
                        annotation.as_source_range(),
                        "The standard library can only be skipped at the top level scope of a file",
                    ));
                }
            } else if annotation.name() == Some(annotations::WARNINGS) {
                // TODO we should support setting warnings for the whole project, not just one file
                if matches!(body_type, BodyType::Root) {
                    let props = annotations::expect_properties(annotations::WARNINGS, annotation)?;
                    for p in props {
                        match &*p.inner.key.name {
                            annotations::WARN_ALLOW => {
                                let allowed = annotations::many_of(
                                    &p.inner.value,
                                    &annotations::WARN_VALUES,
                                    annotation.as_source_range(),
                                )?;
                                exec_state.mod_local.allowed_warnings = allowed;
                            }
                            annotations::WARN_DENY => {
                                let denied = annotations::many_of(
                                    &p.inner.value,
                                    &annotations::WARN_VALUES,
                                    annotation.as_source_range(),
                                )?;
                                exec_state.mod_local.denied_warnings = denied;
                            }
                            name => {
                                return Err(KclError::new_semantic(KclErrorDetails::new(
                                    format!(
                                        "Unexpected warnings key: `{name}`; expected one of `{}`, `{}`",
                                        annotations::WARN_ALLOW,
                                        annotations::WARN_DENY,
                                    ),
                                    vec![annotation.as_source_range()],
                                )));
                            }
                        }
                    }
                } else {
                    exec_state.err(CompilationIssue::err(
                        annotation.as_source_range(),
                        "Warnings can only be customized at the top level scope of a file",
                    ));
                }
            } else {
                exec_state.warn(
                    CompilationIssue::err(annotation.as_source_range(), "Unknown annotation"),
                    annotations::WARN_UNKNOWN_ATTR,
                );
            }
        }
        Ok(no_prelude)
    }

    pub(super) async fn exec_module_body(
        &self,
        program: &Node<Program>,
        exec_state: &mut ExecState,
        preserve_mem: PreserveMem,
        module_id: ModuleId,
        path: &ModulePath,
    ) -> Result<ModuleExecutionOutcome, (KclError, Option<EnvironmentRef>, Option<ModuleArtifactState>)> {
        crate::log::log(format!("enter module {path} {}", exec_state.stack()));

        // When executing only the new statements in incremental execution or
        // mock executing for sketch mode, we need the scene objects that were
        // created during the last execution, which are in the execution cache.
        // The cache is read to create the initial module state. Depending on
        // whether it's mock execution or engine execution, it's rehydrated
        // differently, so we need to clone them from a different place. Then
        // make sure the object ID generator matches the number of existing
        // scene objects.
        let mut local_state = ModuleState::new(
            path.clone(),
            exec_state.stack().memory.clone(),
            Some(module_id),
            exec_state.mod_local.sketch_mode,
            exec_state.mod_local.freedom_analysis,
        );
        match preserve_mem {
            PreserveMem::Always => {
                exec_state
                    .mod_local
                    .artifacts
                    .restore_scene_objects(&exec_state.global.root_module_artifacts.scene_objects);
            }
            PreserveMem::Normal => {
                local_state
                    .artifacts
                    .restore_scene_objects(&exec_state.mod_local.artifacts.scene_objects);
                std::mem::swap(&mut exec_state.mod_local, &mut local_state);
            }
        }

        let no_prelude = self
            .handle_annotations(program.inner_attrs.iter(), crate::execution::BodyType::Root, exec_state)
            .await
            .map_err(|err| (err, None, None))?;

        if preserve_mem.normal() {
            exec_state
                .mut_stack()
                .push_new_root_env(!no_prelude)
                .map_err(|err| (err, None, None))?;
        }

        let result = self
            .exec_block(program, exec_state, crate::execution::BodyType::Root)
            .await;

        let env_ref = match preserve_mem {
            PreserveMem::Always => exec_state.mut_stack().pop_and_preserve_env(),
            PreserveMem::Normal => exec_state.mut_stack().pop_env(),
        }
        .map_err(|err| (err, None, None))?;
        let module_artifacts = match preserve_mem {
            PreserveMem::Always => std::mem::take(&mut exec_state.mod_local.artifacts),
            PreserveMem::Normal => {
                std::mem::swap(&mut exec_state.mod_local, &mut local_state);
                local_state.artifacts
            }
        };

        crate::log::log(format!("leave {path}"));

        result
            .map_err(|err| (err, Some(env_ref), Some(module_artifacts.clone())))
            .map(|last_expr| ModuleExecutionOutcome {
                last_expr: last_expr.map(|value_cf| value_cf.into_value()),
                environment: env_ref,
                exports: local_state.module_exports,
                artifacts: module_artifacts,
            })
    }

    /// Execute an AST's program.
    #[async_recursion]
    pub(super) async fn exec_block<'a, B>(
        &'a self,
        block: &'a B,
        exec_state: &mut ExecState,
        body_type: BodyType,
    ) -> Result<Option<KclValueControlFlow>, KclError>
    where
        B: CodeBlock + Sync,
    {
        let mut last_expr = None;
        // Iterate over the body of the program.
        for statement in block.body() {
            match statement {
                BodyItem::ImportStatement(import_stmt) => {
                    if exec_state.sketch_mode() {
                        continue;
                    }
                    if !matches!(body_type, BodyType::Root) {
                        return Err(KclError::new_semantic(KclErrorDetails::new(
                            "Imports are only supported at the top-level of a file.".to_owned(),
                            vec![import_stmt.into()],
                        )));
                    }

                    let source_range = SourceRange::from(import_stmt);
                    let attrs = &import_stmt.outer_attrs;
                    let module_path = ModulePath::from_import_path(
                        &import_stmt.path,
                        &self.settings.project_directory,
                        &exec_state.mod_local.path,
                    )?;
                    let module_id = self
                        .open_module(&import_stmt.path, attrs, &module_path, exec_state, source_range)
                        .await?;

                    if let ModulePath::Local { value, .. } = &module_path {
                        let name = import_stmt
                            .module_name()
                            .unwrap_or_else(|| value.file_name().unwrap_or_default());
                        exec_state.push_op(Operation::ModuleInstance {
                            name,
                            module_id,
                            glob: matches!(import_stmt.selector, ImportSelector::Glob(_)),
                            node_path: NodePath::placeholder(),
                            source_range,
                        });
                    }

                    match &import_stmt.selector {
                        ImportSelector::List { items } => {
                            let (env_ref, module_exports) =
                                self.exec_module_for_items(module_id, exec_state, source_range).await?;
                            for import_item in items {
                                // Extract the item from the module.
                                let mem = &exec_state.stack().memory;
                                let mut value =
                                    mem.get_from_owned(&import_item.name.name, env_ref, import_item.into(), 0);
                                let ty_name = format!("{}{}", memory::TYPE_PREFIX, import_item.name.name);
                                let mut ty = mem.get_from_owned(&ty_name, env_ref, import_item.into(), 0);
                                let mod_name = format!("{}{}", memory::MODULE_PREFIX, import_item.name.name);
                                let mut mod_value = mem.get_from_owned(&mod_name, env_ref, import_item.into(), 0);

                                if value.is_err() && ty.is_err() && mod_value.is_err() {
                                    return Err(KclError::new_undefined_value(
                                        KclErrorDetails::new(
                                            format!("{} is not defined in module", import_item.name.name),
                                            vec![SourceRange::from(&import_item.name)],
                                        ),
                                        None,
                                    ));
                                }

                                // Check that the item is allowed to be imported (in at least one namespace).
                                if value.is_ok() && !module_exports.contains(&import_item.name.name) {
                                    value = Err(KclError::new_semantic(KclErrorDetails::new(
                                        format!(
                                            "Cannot import \"{}\" from module because it is not exported. Add \"export\" before the definition to export it.",
                                            import_item.name.name
                                        ),
                                        vec![SourceRange::from(&import_item.name)],
                                    )));
                                }

                                if ty.is_ok() && !module_exports.contains(&ty_name) {
                                    ty = Err(KclError::new_semantic(KclErrorDetails::new(
                                        format!(
                                            "Cannot import \"{}\" from module because it is not exported. Add \"export\" before the definition to export it.",
                                            import_item.name.name
                                        ),
                                        vec![SourceRange::from(&import_item.name)],
                                    )));
                                }

                                if mod_value.is_ok() && !module_exports.contains(&mod_name) {
                                    mod_value = Err(KclError::new_semantic(KclErrorDetails::new(
                                        format!(
                                            "Cannot import \"{}\" from module because it is not exported. Add \"export\" before the definition to export it.",
                                            import_item.name.name
                                        ),
                                        vec![SourceRange::from(&import_item.name)],
                                    )));
                                }

                                if value.is_err() && ty.is_err() && mod_value.is_err() {
                                    return value.map(|v| Some(v.continue_()));
                                }

                                // Add the item to the current module.
                                if let Ok(value) = value {
                                    exec_state.mut_stack().add(
                                        import_item.identifier().to_owned(),
                                        value,
                                        SourceRange::from(&import_item.name),
                                    )?;

                                    if let ItemVisibility::Export = import_stmt.visibility {
                                        exec_state
                                            .mod_local
                                            .module_exports
                                            .push(import_item.identifier().to_owned());
                                    }
                                }

                                if let Ok(ty) = ty {
                                    let ty_name = format!("{}{}", memory::TYPE_PREFIX, import_item.identifier());
                                    exec_state.mut_stack().add(
                                        ty_name.clone(),
                                        ty,
                                        SourceRange::from(&import_item.name),
                                    )?;

                                    if let ItemVisibility::Export = import_stmt.visibility {
                                        exec_state.mod_local.module_exports.push(ty_name);
                                    }
                                }

                                if let Ok(mod_value) = mod_value {
                                    let mod_name = format!("{}{}", memory::MODULE_PREFIX, import_item.identifier());
                                    exec_state.mut_stack().add(
                                        mod_name.clone(),
                                        mod_value,
                                        SourceRange::from(&import_item.name),
                                    )?;

                                    if let ItemVisibility::Export = import_stmt.visibility {
                                        exec_state.mod_local.module_exports.push(mod_name);
                                    }
                                }
                            }
                        }
                        ImportSelector::Glob(_) => {
                            let (env_ref, module_exports) =
                                self.exec_module_for_items(module_id, exec_state, source_range).await?;
                            for name in module_exports.iter() {
                                let item = exec_state
                                    .stack()
                                    .memory
                                    .get_from_owned(name, env_ref, source_range, 0)
                                    .map_err(|_err| {
                                        internal_err(
                                            format!("{name} is not defined in module (but was exported?)"),
                                            source_range,
                                        )
                                    })?;
                                exec_state.mut_stack().add(name.to_owned(), item, source_range)?;

                                if let ItemVisibility::Export = import_stmt.visibility {
                                    exec_state.mod_local.module_exports.push(name.clone());
                                }
                            }
                        }
                        ImportSelector::None { .. } => {
                            let name = import_stmt.module_name().unwrap();
                            let item = KclValue::Module {
                                value: module_id,
                                meta: vec![source_range.into()],
                            };
                            exec_state.mut_stack().add(
                                format!("{}{}", memory::MODULE_PREFIX, name),
                                item,
                                source_range,
                            )?;
                        }
                    }
                    last_expr = None;
                }
                BodyItem::ExpressionStatement(expression_statement) => {
                    if exec_state.sketch_mode() && sketch_mode_should_skip(&expression_statement.expression) {
                        continue;
                    }

                    let metadata = Metadata::from(expression_statement);
                    let value = self
                        .execute_expr(
                            &expression_statement.expression,
                            exec_state,
                            &metadata,
                            &[],
                            StatementKind::Expression,
                        )
                        .await?;

                    let is_return = value.is_some_return();
                    last_expr = Some(value);

                    if is_return {
                        break;
                    }
                }
                BodyItem::VariableDeclaration(variable_declaration) => {
                    if exec_state.sketch_mode() && sketch_mode_should_skip(&variable_declaration.declaration.init) {
                        continue;
                    }

                    let var_name = variable_declaration.declaration.id.name.to_string();
                    let source_range = SourceRange::from(&variable_declaration.declaration.init);
                    let metadata = Metadata { source_range };

                    let annotations = &variable_declaration.outer_attrs;

                    // During the evaluation of the variable's RHS, set context that this is all happening inside a variable
                    // declaration, for the given name. This helps improve user-facing error messages.
                    let lhs = variable_declaration.inner.name().to_owned();
                    let prev_being_declared = exec_state.mod_local.being_declared.take();
                    exec_state.mod_local.being_declared = Some(lhs);
                    let rhs_result = self
                        .execute_expr(
                            &variable_declaration.declaration.init,
                            exec_state,
                            &metadata,
                            annotations,
                            StatementKind::Declaration { name: &var_name },
                        )
                        .await;
                    // Declaration over, so unset this context.
                    exec_state.mod_local.being_declared = prev_being_declared;
                    let rhs = rhs_result?;

                    if rhs.is_some_return() {
                        last_expr = Some(rhs);
                        break;
                    }
                    let mut rhs = rhs.into_value();

                    // Attach the variable name to unsolved segments as a tag.
                    // While executing the body of a sketch block, the segments
                    // won't have been solved yet.
                    if let KclValue::Segment { value } = &mut rhs
                        && let SegmentRepr::Unsolved { segment } = &mut value.repr
                    {
                        segment.tag = Some(TagIdentifier {
                            value: variable_declaration.declaration.id.name.clone(),
                            info: Default::default(),
                            meta: vec![SourceRange::from(&variable_declaration.declaration.id).into()],
                        });
                    }
                    let rhs = rhs; // Remove mutability.

                    let should_bind_name =
                        if let Some(fn_name) = variable_declaration.declaration.init.fn_declaring_name() {
                            // Declaring a function with a name, so only bind
                            // the variable name if it differs from the function
                            // name.
                            var_name != fn_name
                        } else {
                            // Not declaring a function, so we should bind the
                            // variable name.
                            true
                        };
                    if should_bind_name {
                        exec_state
                            .mut_stack()
                            .add(var_name.clone(), rhs.clone(), source_range)?;
                    }

                    if let Some(sketch_block_state) = exec_state.mod_local.sketch_block.as_mut()
                        && let KclValue::Segment { value } = &rhs
                    {
                        // Add segment to mapping so that we can tag it when
                        // sending to the engine.
                        let segment_object_id = match &value.repr {
                            SegmentRepr::Unsolved { segment } => segment.object_id,
                            SegmentRepr::Solved { segment } => segment.object_id,
                        };
                        sketch_block_state
                            .segment_tags
                            .entry(segment_object_id)
                            .or_insert_with(|| {
                                let id_node = &variable_declaration.declaration.id;
                                Node::new(
                                    TagDeclarator {
                                        name: id_node.name.clone(),
                                        digest: None,
                                    },
                                    id_node.start,
                                    id_node.end,
                                    id_node.module_id,
                                )
                            });
                    }

                    // Track operations, for the feature tree.
                    // Don't track these operations if the KCL code being executed is in the stdlib,
                    // because users shouldn't know about stdlib internals -- it's useless noise, to them.
                    let should_show_in_feature_tree =
                        !exec_state.mod_local.inside_stdlib && rhs.show_variable_in_feature_tree();
                    if should_show_in_feature_tree {
                        exec_state.push_op(Operation::VariableDeclaration {
                            name: var_name.clone(),
                            value: op_from_kcl_value(&rhs),
                            visibility: variable_declaration.visibility,
                            node_path: NodePath::placeholder(),
                            source_range,
                        });
                    }

                    // Track exports.
                    if let ItemVisibility::Export = variable_declaration.visibility {
                        if matches!(body_type, BodyType::Root) {
                            exec_state.mod_local.module_exports.push(var_name);
                        } else {
                            exec_state.err(CompilationIssue::err(
                                variable_declaration.as_source_range(),
                                "Exports are only supported at the top-level of a file. Remove `export` or move it to the top-level.",
                            ));
                        }
                    }
                    // Variable declaration can be the return value of a module.
                    last_expr = matches!(body_type, BodyType::Root).then_some(rhs.continue_());
                }
                BodyItem::TypeDeclaration(ty) => {
                    if exec_state.sketch_mode() {
                        continue;
                    }

                    let metadata = Metadata::from(&**ty);
                    let attrs = annotations::get_fn_attrs(&ty.outer_attrs, metadata.source_range)?.unwrap_or_default();
                    match attrs.impl_ {
                        annotations::Impl::Rust
                        | annotations::Impl::RustConstrainable
                        | annotations::Impl::RustConstraint => {
                            let std_path = match &exec_state.mod_local.path {
                                ModulePath::Std { value } => value,
                                ModulePath::Local { .. } | ModulePath::Main => {
                                    return Err(KclError::new_semantic(KclErrorDetails::new(
                                        "User-defined types are not yet supported.".to_owned(),
                                        vec![metadata.source_range],
                                    )));
                                }
                            };
                            let (t, props) = crate::std::std_ty(std_path, &ty.name.name);
                            let value = KclValue::Type {
                                value: TypeDef::RustRepr(t, props),
                                meta: vec![metadata],
                                experimental: attrs.experimental,
                            };
                            let name_in_mem = format!("{}{}", memory::TYPE_PREFIX, ty.name.name);
                            exec_state
                                .mut_stack()
                                .add(name_in_mem.clone(), value, metadata.source_range)
                                .map_err(|_| {
                                    KclError::new_semantic(KclErrorDetails::new(
                                        format!("Redefinition of type {}.", ty.name.name),
                                        vec![metadata.source_range],
                                    ))
                                })?;

                            if let ItemVisibility::Export = ty.visibility {
                                exec_state.mod_local.module_exports.push(name_in_mem);
                            }
                        }
                        // Do nothing for primitive types, they get special treatment and their declarations are just for documentation.
                        annotations::Impl::Primitive => {}
                        annotations::Impl::Kcl | annotations::Impl::KclConstrainable => match &ty.alias {
                            Some(alias) => {
                                let value = KclValue::Type {
                                    value: TypeDef::Alias(
                                        RuntimeType::from_parsed(
                                            alias.inner.clone(),
                                            exec_state,
                                            metadata.source_range,
                                            attrs.impl_ == annotations::Impl::KclConstrainable,
                                            false,
                                        )
                                        .map_err(|e| KclError::new_semantic(e.into()))?,
                                    ),
                                    meta: vec![metadata],
                                    experimental: attrs.experimental,
                                };
                                let name_in_mem = format!("{}{}", memory::TYPE_PREFIX, ty.name.name);
                                exec_state
                                    .mut_stack()
                                    .add(name_in_mem.clone(), value, metadata.source_range)
                                    .map_err(|_| {
                                        KclError::new_semantic(KclErrorDetails::new(
                                            format!("Redefinition of type {}.", ty.name.name),
                                            vec![metadata.source_range],
                                        ))
                                    })?;

                                if let ItemVisibility::Export = ty.visibility {
                                    exec_state.mod_local.module_exports.push(name_in_mem);
                                }
                            }
                            None => {
                                return Err(KclError::new_semantic(KclErrorDetails::new(
                                    "User-defined types are not yet supported.".to_owned(),
                                    vec![metadata.source_range],
                                )));
                            }
                        },
                    }

                    last_expr = None;
                }
                BodyItem::ReturnStatement(return_statement) => {
                    if exec_state.sketch_mode() && sketch_mode_should_skip(&return_statement.argument) {
                        continue;
                    }

                    let metadata = Metadata::from(return_statement);

                    if matches!(body_type, BodyType::Root) {
                        return Err(KclError::new_semantic(KclErrorDetails::new(
                            "Cannot return from outside a function.".to_owned(),
                            vec![metadata.source_range],
                        )));
                    }

                    let value_cf = self
                        .execute_expr(
                            &return_statement.argument,
                            exec_state,
                            &metadata,
                            &[],
                            StatementKind::Expression,
                        )
                        .await?;
                    if value_cf.is_some_return() {
                        last_expr = Some(value_cf);
                        break;
                    }
                    let value = value_cf.into_value();
                    exec_state
                        .mut_stack()
                        .add(memory::RETURN_NAME.to_owned(), value, metadata.source_range)
                        .map_err(|_| {
                            KclError::new_semantic(KclErrorDetails::new(
                                "Multiple returns from a single function.".to_owned(),
                                vec![metadata.source_range],
                            ))
                        })?;
                    last_expr = None;
                }
            }
        }

        if matches!(body_type, BodyType::Root) {
            // Flush the batch queue.
            exec_state
                .flush_batch(
                    ModelingCmdMeta::new(exec_state, self, block.to_source_range()),
                    // True here tells the engine to flush all the end commands as well like fillets
                    // and chamfers where the engine would otherwise eat the ID of the segments.
                    true,
                )
                .await?;
        }

        Ok(last_expr)
    }

    pub async fn open_module(
        &self,
        path: &ImportPath,
        attrs: &[Node<Annotation>],
        resolved_path: &ModulePath,
        exec_state: &mut ExecState,
        source_range: SourceRange,
    ) -> Result<ModuleId, KclError> {
        match path {
            ImportPath::Kcl { .. } => {
                exec_state.global.mod_loader.cycle_check(resolved_path, source_range)?;

                if let Some(id) = exec_state.id_for_module(resolved_path) {
                    return Ok(id);
                }

                let id = exec_state.next_module_id();
                // Add file path string to global state even if it fails to import
                exec_state.add_path_to_source_id(resolved_path.clone(), id);
                let source = resolved_path.source(&self.fs, source_range).await?;
                exec_state.add_id_to_source(id, source.clone());
                // TODO handle parsing errors properly
                let parsed = crate::parsing::parse_str(&source.source, id).parse_errs_as_err()?;
                exec_state.add_module(id, resolved_path.clone(), ModuleRepr::Kcl(parsed, None));

                Ok(id)
            }
            ImportPath::Foreign { .. } => {
                if let Some(id) = exec_state.id_for_module(resolved_path) {
                    return Ok(id);
                }

                let id = exec_state.next_module_id();
                let path = resolved_path.expect_path();
                // Add file path string to global state even if it fails to import
                exec_state.add_path_to_source_id(resolved_path.clone(), id);
                let format = super::import::format_from_annotations(attrs, path, source_range)?;
                let geom = super::import::import_foreign(path, format, exec_state, self, source_range).await?;
                exec_state.add_module(id, resolved_path.clone(), ModuleRepr::Foreign(geom, None));
                Ok(id)
            }
            ImportPath::Std { .. } => {
                if resolved_path.is_solver_module() && exec_state.mod_local.sketch_block.is_none() {
                    return Err(KclError::new_semantic(KclErrorDetails::new(
                        format!("The `{resolved_path}` module is only available inside sketch blocks."),
                        vec![source_range],
                    )));
                }

                if let Some(id) = exec_state.id_for_module(resolved_path) {
                    return Ok(id);
                }

                let id = exec_state.next_module_id();
                // Add file path string to global state even if it fails to import
                exec_state.add_path_to_source_id(resolved_path.clone(), id);
                let source = resolved_path.source(&self.fs, source_range).await?;
                exec_state.add_id_to_source(id, source.clone());
                let parsed = crate::parsing::parse_str(&source.source, id)
                    .parse_errs_as_err()
                    .unwrap();
                exec_state.add_module(id, resolved_path.clone(), ModuleRepr::Kcl(parsed, None));
                Ok(id)
            }
        }
    }

    pub(super) async fn exec_module_for_items(
        &self,
        module_id: ModuleId,
        exec_state: &mut ExecState,
        source_range: SourceRange,
    ) -> Result<(EnvironmentRef, Vec<String>), KclError> {
        let path = exec_state.global.module_infos[&module_id].path.clone();
        let mut repr = exec_state.global.module_infos[&module_id].take_repr();
        // DON'T EARLY RETURN! We need to restore the module repr

        let result = match &mut repr {
            ModuleRepr::Root => Err(exec_state.circular_import_error(&path, source_range)),
            ModuleRepr::Kcl(_, Some(outcome)) => Ok((outcome.environment, outcome.exports.clone())),
            ModuleRepr::Kcl(program, cache) => self
                .exec_module_from_ast(program, module_id, &path, exec_state, source_range, PreserveMem::Normal)
                .await
                .map(|outcome| {
                    *cache = Some(outcome.clone());
                    (outcome.environment, outcome.exports)
                }),
            ModuleRepr::Foreign(geom, _) => Err(KclError::new_semantic(KclErrorDetails::new(
                "Cannot import items from foreign modules".to_owned(),
                vec![geom.source_range],
            ))),
            ModuleRepr::Dummy => unreachable!("Looking up {}, but it is still being interpreted", path),
        };

        exec_state.global.module_infos[&module_id].restore_repr(repr);
        result
    }

    async fn exec_module_for_result(
        &self,
        module_id: ModuleId,
        exec_state: &mut ExecState,
        source_range: SourceRange,
    ) -> Result<Option<KclValue>, KclError> {
        let path = exec_state.global.module_infos[&module_id].path.clone();
        let mut repr = exec_state.global.module_infos[&module_id].take_repr();
        // DON'T EARLY RETURN! We need to restore the module repr

        let result = match &mut repr {
            ModuleRepr::Root => Err(exec_state.circular_import_error(&path, source_range)),
            ModuleRepr::Kcl(_, Some(outcome)) => Ok(outcome.last_expr.clone()),
            ModuleRepr::Kcl(program, cached_items) => {
                let result = self
                    .exec_module_from_ast(program, module_id, &path, exec_state, source_range, PreserveMem::Normal)
                    .await;
                match result {
                    Ok(outcome) => {
                        let value = outcome.last_expr.clone();
                        *cached_items = Some(outcome);
                        Ok(value)
                    }
                    Err(e) => Err(e),
                }
            }
            ModuleRepr::Foreign(_, Some((imported, _))) => Ok(imported.clone()),
            ModuleRepr::Foreign(geom, cached) => {
                let result = super::import::send_to_engine(geom.clone(), exec_state, self)
                    .await
                    .map(|geom| Some(KclValue::ImportedGeometry(geom)));

                match result {
                    Ok(val) => {
                        *cached = Some((val.clone(), exec_state.mod_local.artifacts.clone()));
                        Ok(val)
                    }
                    Err(e) => Err(e),
                }
            }
            ModuleRepr::Dummy => unreachable!(),
        };

        exec_state.global.module_infos[&module_id].restore_repr(repr);

        result
    }

    pub async fn exec_module_from_ast(
        &self,
        program: &Node<Program>,
        module_id: ModuleId,
        path: &ModulePath,
        exec_state: &mut ExecState,
        source_range: SourceRange,
        preserve_mem: PreserveMem,
    ) -> Result<ModuleExecutionOutcome, KclError> {
        exec_state.global.mod_loader.enter_module(path);
        let result = self
            .exec_module_body(program, exec_state, preserve_mem, module_id, path)
            .await;
        exec_state.global.mod_loader.leave_module(path, source_range)?;

        // TODO: ModuleArtifactState is getting dropped here when there's an
        // error.  Should we propagate it for non-root modules?
        result.map_err(|(err, _, _)| {
            match err {
                KclError::ImportCycle { .. } => {
                    // It was an import cycle.  Keep the original message.
                    err.override_source_ranges(vec![source_range])
                }
                KclError::EngineHangup { .. } | KclError::EngineInternal { .. } => {
                    // Propagate this type of error. It's likely a transient
                    // error that just needs to be retried.
                    err.override_source_ranges(vec![source_range])
                }
                _ => {
                    // TODO would be great to have line/column for the underlying error here
                    KclError::new_semantic(KclErrorDetails::new(
                        format!(
                            "Error loading imported file ({path}). Open it to view more details.\n  {}",
                            err.message()
                        ),
                        vec![source_range],
                    ))
                }
            }
        })
    }

    #[async_recursion]
    pub(crate) async fn execute_expr<'a: 'async_recursion>(
        &self,
        init: &Expr,
        exec_state: &mut ExecState,
        metadata: &Metadata,
        annotations: &[Node<Annotation>],
        statement_kind: StatementKind<'a>,
    ) -> Result<KclValueControlFlow, KclError> {
        let item = match init {
            Expr::None(none) => KclValue::from(none).continue_(),
            Expr::Literal(literal) => KclValue::from_literal((**literal).clone(), exec_state).continue_(),
            Expr::TagDeclarator(tag) => tag.execute(exec_state).await?.continue_(),
            Expr::Name(name) => {
                let being_declared = exec_state.mod_local.being_declared.clone();
                let value = name
                    .get_result(exec_state, self)
                    .await
                    .map_err(|e| var_in_own_ref_err(e, &being_declared))?
                    .clone();
                if let KclValue::Module { value: module_id, meta } = value {
                    self.exec_module_for_result(
                        module_id,
                        exec_state,
                        metadata.source_range
                        ).await?.map(|v| v.continue_())
                        .unwrap_or_else(|| {
                            exec_state.warn(CompilationIssue::err(
                                metadata.source_range,
                                "Imported module has no return value. The last statement of the module must be an expression, usually the Solid.",
                            ),
                        annotations::WARN_MOD_RETURN_VALUE);

                            let mut new_meta = vec![metadata.to_owned()];
                            new_meta.extend(meta);
                            KclValue::KclNone {
                                value: Default::default(),
                                meta: new_meta,
                            }.continue_()
                        })
                } else {
                    value.continue_()
                }
            }
            Expr::BinaryExpression(binary_expression) => binary_expression.get_result(exec_state, self).await?,
            Expr::FunctionExpression(function_expression) => {
                let attrs = annotations::get_fn_attrs(annotations, metadata.source_range)?;
                let experimental = attrs
                    .as_ref()
                    .map(|a| a.experimental)
                    // Use the default for the field, not the bool type.
                    .unwrap_or_else(|| FnAttrs::default().experimental);

                // Check the KCL @(feature_tree = ) annotation.
                let include_in_feature_tree = attrs
                    .as_ref()
                    .map(|a| a.include_in_feature_tree)
                    // Use the default for the field, not the bool type.
                    .unwrap_or_else(|| FnAttrs::default().include_in_feature_tree);
                let (mut closure, placeholder_env_ref) = if let Some(attrs) = attrs
                    && (attrs.impl_ == annotations::Impl::Rust
                        || attrs.impl_ == annotations::Impl::RustConstrainable
                        || attrs.impl_ == annotations::Impl::RustConstraint)
                {
                    if let ModulePath::Std { value: std_path } = &exec_state.mod_local.path {
                        let (func, props) = crate::std::std_fn(std_path, statement_kind.expect_name());
                        (
                            KclValue::Function {
                                value: Box::new(FunctionSource::rust(func, function_expression.clone(), props, attrs)),
                                meta: vec![metadata.to_owned()],
                            },
                            None,
                        )
                    } else {
                        return Err(KclError::new_semantic(KclErrorDetails::new(
                            "Rust implementation of functions is restricted to the standard library".to_owned(),
                            vec![metadata.source_range],
                        )));
                    }
                } else {
                    let std_props = function_expression
                        .name_str()
                        .and_then(|name| exec_state.mod_local.path.build_std_fully_qualified_name(name))
                        .map(|name| StdFnProps::default(&name));
                    // Snapshotting memory here is crucial for semantics so that we close
                    // over variables. Variables defined lexically later shouldn't
                    // be available to the function body.
                    let (env_ref, placeholder_env_ref) = if function_expression.name.is_some() {
                        // Recursive function needs a snapshot that includes
                        // itself.
                        let dummy = EnvironmentRef::dummy();
                        (dummy, Some(dummy))
                    } else {
                        (exec_state.mut_stack().snapshot()?, None)
                    };
                    (
                        KclValue::Function {
                            value: Box::new(FunctionSource::kcl(
                                function_expression.clone(),
                                env_ref,
                                KclFunctionSourceParams {
                                    std_props,
                                    experimental,
                                    include_in_feature_tree,
                                },
                            )),
                            meta: vec![metadata.to_owned()],
                        },
                        placeholder_env_ref,
                    )
                };

                // If the function expression has a name, i.e. `fn name() {}`,
                // bind it in the current scope.
                if let Some(fn_name) = &function_expression.name {
                    // If we used a placeholder env ref for recursion, fix it up
                    // with the name recursively bound so that it's available in
                    // the function body.
                    if let Some(placeholder_env_ref) = placeholder_env_ref {
                        closure = exec_state.mut_stack().add_recursive_closure(
                            fn_name.name.to_owned(),
                            closure,
                            placeholder_env_ref,
                            metadata.source_range,
                        )?;
                    } else {
                        // Regular non-recursive binding.
                        exec_state
                            .mut_stack()
                            .add(fn_name.name.clone(), closure.clone(), metadata.source_range)?;
                    }
                }

                closure.continue_()
            }
            Expr::CallExpressionKw(call_expression) => call_expression.execute(exec_state, self).await?,
            Expr::PipeExpression(pipe_expression) => pipe_expression.get_result(exec_state, self).await?,
            Expr::PipeSubstitution(pipe_substitution) => match statement_kind {
                StatementKind::Declaration { name } => {
                    let message = format!(
                        "you cannot declare variable {name} as %, because % can only be used in function calls"
                    );

                    return Err(KclError::new_semantic(KclErrorDetails::new(
                        message,
                        vec![pipe_substitution.into()],
                    )));
                }
                StatementKind::Expression => match exec_state.mod_local.pipe_value.clone() {
                    Some(x) => x.continue_(),
                    None => {
                        return Err(KclError::new_semantic(KclErrorDetails::new(
                            "cannot use % outside a pipe expression".to_owned(),
                            vec![pipe_substitution.into()],
                        )));
                    }
                },
            },
            Expr::ArrayExpression(array_expression) => array_expression.execute(exec_state, self).await?,
            Expr::ArrayRangeExpression(range_expression) => range_expression.execute(exec_state, self).await?,
            Expr::ObjectExpression(object_expression) => object_expression.execute(exec_state, self).await?,
            Expr::MemberExpression(member_expression) => member_expression.get_result(exec_state, self).await?,
            Expr::UnaryExpression(unary_expression) => unary_expression.get_result(exec_state, self).await?,
            Expr::IfExpression(expr) => expr.get_result(exec_state, self).await?,
            Expr::LabelledExpression(expr) => {
                let value_cf = self
                    .execute_expr(&expr.expr, exec_state, metadata, &[], statement_kind)
                    .await?;
                let value = control_continue!(value_cf);
                exec_state
                    .mut_stack()
                    .add(expr.label.name.clone(), value.clone(), init.into())?;
                // TODO this lets us use the label as a variable name, but not as a tag in most cases
                value.continue_()
            }
            Expr::AscribedExpression(expr) => expr.get_result(exec_state, self).await?,
            Expr::SketchBlock(expr) => expr.get_result(exec_state, self).await?,
            Expr::SketchVar(expr) => expr.get_result(exec_state, self).await?.continue_(),
        };
        Ok(item)
    }
}

/// When executing in sketch mode, whether we should skip executing this
/// expression.
fn sketch_mode_should_skip(expr: &Expr) -> bool {
    match expr {
        Expr::SketchBlock(sketch_block) => !sketch_block.is_being_edited,
        _ => true,
    }
}

/// If the error is about an undefined name, and that name matches the name being defined,
/// make the error message more specific.
fn var_in_own_ref_err(e: KclError, being_declared: &Option<String>) -> KclError {
    let KclError::UndefinedValue { name, mut details } = e else {
        return e;
    };
    // TODO after June 26th: replace this with a let-chain,
    // which will be available in Rust 1.88
    // https://rust-lang.github.io/rfcs/2497-if-let-chains.html
    if let (Some(name0), Some(name1)) = (&being_declared, &name)
        && name0 == name1
    {
        details.message = format!(
            "You can't use `{name0}` because you're currently trying to define it. Use a different variable here instead."
        );
    }
    KclError::UndefinedValue { details, name }
}

impl Node<AscribedExpression> {
    #[async_recursion]
    pub(super) async fn get_result(
        &self,
        exec_state: &mut ExecState,
        ctx: &ExecutorContext,
    ) -> Result<KclValueControlFlow, KclError> {
        let metadata = Metadata {
            source_range: SourceRange::from(self),
        };
        let result = ctx
            .execute_expr(&self.expr, exec_state, &metadata, &[], StatementKind::Expression)
            .await?;
        let result = control_continue!(result);
        apply_ascription(&result, &self.ty, exec_state, self.into()).map(KclValue::continue_)
    }
}

impl Node<SketchBlock> {
    pub(super) async fn get_result(
        &self,
        exec_state: &mut ExecState,
        ctx: &ExecutorContext,
    ) -> Result<KclValueControlFlow, KclError> {
        if exec_state.mod_local.sketch_block.is_some() {
            // Disallow nested sketch blocks for now.
            return Err(KclError::new_semantic(KclErrorDetails::new(
                "Cannot execute a sketch block from within another sketch block".to_owned(),
                vec![SourceRange::from(self)],
            )));
        }

        let range = SourceRange::from(self);

        // Evaluate arguments.
        let (sketch_id, sketch_surface) = match self.exec_arguments(exec_state, ctx).await {
            Ok(x) => x,
            Err(cf_error) => match cf_error {
                // Control flow needs to return early.
                EarlyReturn::Value(cf_value) => return Ok(cf_value),
                EarlyReturn::Error(err) => return Err(err),
            },
        };
        let on_object_id = if let Some(object_id) = sketch_surface.object_id() {
            object_id
        } else {
            let message = "The `on` argument should have an object after ensure_sketch_plane_in_engine".to_owned();
            debug_assert!(false, "{message}");
            return Err(internal_err(message, range));
        };
        let sketch_ctor_on = sketch_on_frontend_plane(&self.arguments, on_object_id);
        let sketch_block_artifact_id = {
            use crate::execution::CodeRef;
            use crate::execution::SketchBlock;
            use crate::front::Plane;
            use crate::front::SourceRef;

            let on_object = exec_state.mod_local.artifacts.scene_object_by_id(on_object_id);

            // Get the plane artifact ID so that we can do an exclusive borrow.
            let plane_artifact_id = on_object.map(|object| object.artifact_id);
            let plane_info = match &sketch_surface {
                SketchSurface::Plane(plane) => Some(plane.info.clone()),
                SketchSurface::Face(_) => None,
            };

            let standard_plane = match &sketch_ctor_on {
                Plane::Default(plane) => Some(*plane),
                Plane::Object(_) => None,
            };

            let artifact_id = ArtifactId::from(exec_state.next_uuid());
            // Create the sketch scene object and replace its placeholder.
            let sketch_scene_object = Object {
                id: sketch_id,
                kind: ObjectKind::Sketch(crate::frontend::sketch::Sketch {
                    args: crate::front::SketchCtor { on: sketch_ctor_on },
                    plane: on_object_id,
                    segments: Default::default(),
                    constraints: Default::default(),
                }),
                label: Default::default(),
                comments: Default::default(),
                artifact_id,
                source: SourceRef::new(self.into(), self.node_path.clone()),
            };
            exec_state.set_scene_object(sketch_scene_object);

            // Create and add the sketch block artifact.
            exec_state.add_artifact(Artifact::SketchBlock(SketchBlock {
                id: artifact_id,
                standard_plane,
                plane_id: plane_artifact_id,
                plane_info,
                // Fill this in later once we create the path. We can't just add
                // the artifact later because order relative to constraint
                // artifacts is significant.
                path_id: None,
                code_ref: CodeRef::placeholder(range),
                sketch_id,
            }));

            exec_state.push_op(Operation::GroupBegin {
                group: Group::SketchBlock { sketch_id },
                node_path: NodePath::placeholder(),
                source_range: range,
            });
            artifact_id
        };

        let (return_result, variables, sketch_block_state) = {
            // Don't early return until the stack frame is popped!
            self.prep_mem(exec_state.mut_stack().snapshot()?, exec_state)?;

            // Track that we're executing a sketch block.
            let initial_sketch_block_state = {
                SketchBlockState {
                    sketch_id: Some(sketch_id),
                    ..Default::default()
                }
            };

            let original_value = exec_state.mod_local.sketch_block.replace(initial_sketch_block_state);

            // When executing the body of the sketch block, we no longer want to
            // skip any code.
            let original_sketch_mode = std::mem::replace(&mut exec_state.mod_local.sketch_mode, false);

            // Load `sketch2::*` into the sketch block's parent scope, so calls
            // like `line(...)` resolve to sketch2 functions. Then execute the
            // user body in a child scope, so these aliases aren't included in
            // the returned sketch object.
            let (result, block_variables) = match self.load_sketch2_into_current_scope(exec_state, ctx, range).await {
                Ok(()) => {
                    let parent = exec_state.mut_stack().snapshot()?;
                    exec_state.mut_stack().push_new_env_for_call(parent)?;
                    let result = ctx.exec_block(&self.body, exec_state, BodyType::Block).await;
                    let (result, block_variables) = match exec_state.stack().find_all_in_current_env() {
                        Ok(block_variables) => (result, block_variables.into_iter().collect::<IndexMap<_, _>>()),
                        Err(err) => (Err(err), IndexMap::new()),
                    };
                    let result = match exec_state.mut_stack().pop_env() {
                        Ok(_) => result,
                        Err(err) => Err(err),
                    };
                    (result, block_variables)
                }
                Err(err) => (Err(err), IndexMap::new()),
            };

            exec_state.mod_local.sketch_mode = original_sketch_mode;

            let sketch_block_state = std::mem::replace(&mut exec_state.mod_local.sketch_block, original_value);

            // Pop the scope used for sketch2 aliases.
            let result = match exec_state.mut_stack().pop_env() {
                Ok(_) => result,
                Err(err) => Err(err),
            };

            (result, block_variables, sketch_block_state)
        };

        // Propagate errors.
        return_result?;
        let Some(sketch_block_state) = sketch_block_state else {
            debug_assert!(false, "Sketch block state should still be set to Some from just above");
            return Err(internal_err(
                "Sketch block state should still be set to Some from just above",
                self,
            ));
        };
        let mut sketch_block_state = sketch_block_state;

        // Translate sketch variables and constraints to solver input.
        let constraints = sketch_block_state
            .solver_constraints
            .iter()
            .cloned()
            .map(ezpz::ConstraintRequest::highest_priority)
            .chain(
                // Optional constraints have a lower priority.
                sketch_block_state
                    .solver_optional_constraints
                    .iter()
                    .cloned()
                    .map(|c| ezpz::ConstraintRequest::new(c, 1)),
            )
            .collect::<Vec<_>>();
        let initial_guesses = sketch_block_state
            .sketch_vars
            .iter()
            .map(|v| {
                let Some(sketch_var) = v.as_sketch_var() else {
                    return Err(internal_err("Expected sketch variable", self));
                };
                let constraint_id = sketch_var.id.to_constraint_id(range)?;
                // Normalize units.
                let number_value = KclValue::Number {
                    value: sketch_var.initial_value,
                    ty: sketch_var.ty,
                    meta: sketch_var.meta.clone(),
                };
                let initial_guess_value = normalize_to_solver_distance_unit(
                    &number_value,
                    v.into(),
                    exec_state,
                    "sketch variable initial value",
                )?;
                let initial_guess = if let Some(n) = initial_guess_value.as_ty_f64() {
                    n.n
                } else {
                    let message = format!(
                        "Expected number after coercion, but found {}",
                        initial_guess_value.human_friendly_type()
                    );
                    debug_assert!(false, "{}", &message);
                    return Err(internal_err(message, self));
                };
                Ok((constraint_id, initial_guess))
            })
            .collect::<Result<Vec<_>, KclError>>()?;
        // Solve constraints.
        let config = ezpz::Config::default()
            .with_max_iterations(50)
            .with_convergence_tolerance(SOLVER_CONVERGENCE_TOLERANCE);
        let solve_result = if exec_state.mod_local.freedom_analysis {
            ezpz::solve_analysis(&constraints, initial_guesses.clone(), config).map(|outcome| {
                let freedom_analysis = FreedomAnalysis::from_ezpz_analysis(outcome.analysis, constraints.len());
                (outcome.outcome, Some(freedom_analysis))
            })
        } else {
            ezpz::solve(&constraints, initial_guesses.clone(), config).map(|outcome| (outcome, None))
        };
        // Build a combined list of all constraints (regular + optional) for conflict detection
        let num_required_constraints = sketch_block_state.solver_constraints.len();
        let all_constraints: Vec<ezpz::Constraint> = sketch_block_state
            .solver_constraints
            .iter()
            .cloned()
            .chain(sketch_block_state.solver_optional_constraints.iter().cloned())
            .collect();

        let (solve_outcome, solve_analysis) = match solve_result {
            Ok((solved, freedom)) => {
                let outcome = Solved::from_ezpz_outcome(solved, &all_constraints, num_required_constraints);
                if !outcome.converged {
                    exec_state.warn(
                        CompilationIssue::err(range, "Constraint solver failed to find a solution".to_owned()),
                        annotations::WARN_SOLVER,
                    );
                }
                (outcome, freedom)
            }
            Err(failure) => {
                match &failure.error {
                    NonLinearSystemError::FaerMatrix { .. }
                    | NonLinearSystemError::Faer { .. }
                    | NonLinearSystemError::FaerSolve { .. }
                    | NonLinearSystemError::FaerSvd(..) => {
                        // Constraint solver failed to find a solution. Build a
                        // solution that is the initial guesses.
                        exec_state.warn(
                            CompilationIssue::err(range, "Internal error in constraint solver".to_owned()),
                            annotations::WARN_SOLVER,
                        );
                        let final_values = initial_guesses.iter().map(|(_, v)| *v).collect::<Vec<_>>();
                        (
                            Solved {
                                final_values,
                                iterations: Default::default(),
                                warnings: failure.warnings,
                                priority_solved: Default::default(),
                                variables_in_conflicts: Default::default(),
                                converged: false,
                            },
                            None,
                        )
                    }
                    NonLinearSystemError::EmptySystemNotAllowed
                    | NonLinearSystemError::WrongNumberGuesses { .. }
                    | NonLinearSystemError::MissingGuess { .. }
                    | NonLinearSystemError::NotFound(..) => {
                        // These indicate something's gone wrong in KCL or ezpz,
                        // it's not a user error. We should investigate this.
                        #[cfg(target_arch = "wasm32")]
                        web_sys::console::error_1(
                            &format!("Internal error from constraint solver: {}", &failure.error).into(),
                        );
                        return Err(internal_err(
                            format!("Internal error from constraint solver: {}", &failure.error),
                            self,
                        ));
                    }
                    _ => {
                        // Catch all error case so that it's not a breaking change to publish new errors.
                        return Err(internal_err(
                            format!("Error from constraint solver: {}", &failure.error),
                            self,
                        ));
                    }
                }
            }
        };
        // Propagate warnings.
        for warning in &solve_outcome.warnings {
            let message = if let Some(index) = warning.about_constraint.as_ref() {
                format!("{}; constraint index {}", &warning.content, index)
            } else {
                format!("{}", &warning.content)
            };
            exec_state.warn(CompilationIssue::err(range, message), annotations::WARN_SOLVER);
        }
        // Substitute solutions back into sketch variables.
        let sketch_engine_id = exec_state.next_uuid();
        let solution_ty = solver_numeric_type(exec_state);
        let mut solved_segments = Vec::with_capacity(sketch_block_state.needed_by_engine.len());
        for unsolved_segment in &sketch_block_state.needed_by_engine {
            solved_segments.push(substitute_sketch_var_in_segment(
                unsolved_segment.clone(),
                &sketch_surface,
                sketch_engine_id,
                None,
                &solve_outcome,
                solver_numeric_type(exec_state),
                solve_analysis.as_ref(),
            )?);
        }
        // Store variable solutions so that the sketch refactoring API can
        // write them back to the source. When editing a sketch block, we
        // exit early so that the sketch block that we're editing is always
        // the last one. Therefore, we should overwrite any previous
        // solutions.
        exec_state.mod_local.artifacts.var_solutions =
            sketch_block_state.var_solutions(&solve_outcome, solution_ty, SourceRange::from(self))?;

        // Create scene objects after unknowns are solved.
        let scene_objects = create_segment_scene_objects(&solved_segments, range, exec_state)?;

        // Build the sketch and send everything to the engine.
        let sketch = create_segments_in_engine(
            &sketch_surface,
            sketch_engine_id,
            &mut solved_segments,
            &sketch_block_state.segment_tags,
            ctx,
            exec_state,
            range,
        )
        .await?;

        // We now have enough information to fill in the path.
        if let Some(sketch_artifact_id) = sketch.as_ref().map(|s| s.artifact_id) {
            if let Some(Artifact::SketchBlock(sketch_block_artifact)) =
                exec_state.artifact_mut(sketch_block_artifact_id)
            {
                sketch_block_artifact.path_id = Some(sketch_artifact_id);
            } else {
                let message = "Sketch block artifact not found, so path couldn't be linked to it".to_owned();
                debug_assert!(false, "{message}");
                return Err(KclError::new_internal(KclErrorDetails::new(message, vec![range])));
            }
        }

        // Substitute solutions back into sketch variables. This time, collect
        // all the variables in the sketch block. The set of variables may have
        // overlap with the objects sent to the engine, but it isn't necessarily
        // the same.
        let variables = substitute_sketch_vars(
            variables,
            &sketch_surface,
            sketch_engine_id,
            sketch.as_ref(),
            &solve_outcome,
            solution_ty,
            solve_analysis.as_ref(),
        )?;

        let mut segment_object_ids = Vec::with_capacity(scene_objects.len());
        for scene_object in scene_objects {
            segment_object_ids.push(scene_object.id);
            // Fill in placeholder scene objects.
            exec_state.set_scene_object(scene_object);
        }
        // Update the sketch scene object with the segments.
        let Some(sketch_object) = exec_state.mod_local.artifacts.scene_object_by_id_mut(sketch_id) else {
            let message = format!("Sketch object not found after it was just created; id={:?}", sketch_id);
            debug_assert!(false, "{}", &message);
            return Err(internal_err(message, range));
        };
        let ObjectKind::Sketch(front_sketch) = &mut sketch_object.kind else {
            let message = format!(
                "Expected Sketch object after it was just created to be a sketch kind; id={:?}, actual={:?}",
                sketch_id, sketch_object
            );
            debug_assert!(
                false,
                "{}; scene_objects={:#?}",
                &message, &exec_state.mod_local.artifacts.scene_objects
            );
            return Err(internal_err(message, range));
        };
        front_sketch.segments.extend(segment_object_ids);
        // Update the sketch scene object with constraints.
        front_sketch
            .constraints
            .extend(std::mem::take(&mut sketch_block_state.sketch_constraints));

        // Close the sketch block operation group.
        exec_state.push_op(Operation::GroupEnd);

        // Warn if the sketch has conflicting constraints. Skip this when
        // freedom analysis didn't run (e.g., during dragging), because the
        // freedom values on points are stale defaults in that case.
        if exec_state.mod_local.freedom_analysis {
            let status = {
                let scene_objects = &exec_state.mod_local.artifacts.scene_objects;
                scene_objects
                    .get(sketch_id.0)
                    .and_then(|obj| sketch_constraint_status_for_sketch(scene_objects, obj))
            };
            if let Some(status) = status
                && status.status == ConstraintKind::OverConstrained
            {
                let description = if status.conflict_count == 1 {
                    "segment has"
                } else {
                    "segments have"
                };
                let message = format!(
                    "Sketch is over-constrained: {} {description} conflicting constraints",
                    status.conflict_count,
                );
                exec_state.warn(
                    CompilationIssue::err(range, message),
                    annotations::WARN_OVER_CONSTRAINED_SKETCH,
                );
            }
        }

        let properties = self.sketch_properties(sketch, variables);
        let metadata = Metadata {
            source_range: SourceRange::from(self),
        };
        let return_value = KclValue::Object {
            value: properties,
            constrainable: Default::default(),
            object_kind: KclObjectKind::Default,
            meta: vec![metadata],
        };
        Ok(if self.is_being_edited {
            // When the sketch block is being edited, we exit the program
            // immediately.
            return_value.exit()
        } else {
            return_value.continue_()
        })
    }

    /// Executes the arguments of the sketch block and returns the sketch ID and
    /// surface. The surface is the `on` argument, which is basically a Plane or
    /// Face.
    ///
    /// In sketch mode, the execution cache is used to look up the sketch
    /// surface.
    ///
    /// The sketch ID is generated in either case so that it's stable. But only
    /// a placeholder scene object is created for it.
    async fn exec_arguments(
        &self,
        exec_state: &mut ExecState,
        ctx: &ExecutorContext,
    ) -> Result<(ObjectId, SketchSurface), EarlyReturn> {
        let range = SourceRange::from(self);

        if !exec_state.sketch_mode() {
            // Evaluate arguments.
            //
            // Sketch mode only executes the sketch block body. Arguments must
            // be evaluated in engine execution so that things like Planes and
            // Faces can be created in the engine.
            let mut labeled = IndexMap::new();
            for labeled_arg in &self.arguments {
                let source_range = SourceRange::from(labeled_arg.arg.clone());
                let metadata = Metadata { source_range };
                let value_cf = ctx
                    .execute_expr(&labeled_arg.arg, exec_state, &metadata, &[], StatementKind::Expression)
                    .await?;
                let value = early_return!(value_cf);
                let arg = Arg::new(value, source_range);
                match &labeled_arg.label {
                    Some(label) => {
                        labeled.insert(label.name.clone(), arg);
                    }
                    None => {
                        let name = labeled_arg.arg.ident_name();
                        if let Some(name) = name {
                            labeled.insert(name.to_owned(), arg);
                        } else {
                            return Err(KclError::new_semantic(KclErrorDetails::new(
                                "Arguments to sketch blocks must be either labeled or simple identifiers".to_owned(),
                                vec![SourceRange::from(&labeled_arg.arg)],
                            ))
                            .into());
                        }
                    }
                }
            }
            let mut args = Args::new_no_args(
                range,
                self.node_path.clone(),
                ctx.clone(),
                Some(SketchBlock::CALLEE_NAME.to_owned()),
            );
            args.labeled = labeled;

            // Report any arguments that aren't valid sketch block parameters.
            // This is non-fatal so that the rest of the block still executes,
            // matching how unexpected keyword arguments are handled for
            // function calls.
            //
            // Checking arguments should be done after evaluating them, the same
            // order as if we were calling a function.
            self.check_for_unexpected_arguments(&args, exec_state)?;

            let arg_on_value: KclValue =
                args.get_kw_arg(SKETCH_BLOCK_PARAM_ON, &RuntimeType::sketch_or_surface(), exec_state)?;

            let Some(arg_on) = SketchOrSurface::from_kcl_val(&arg_on_value) else {
                let message =
                    "The `on` argument to a sketch block must be convertible to a sketch or surface.".to_owned();
                debug_assert!(false, "{message}");
                return Err(KclError::new_semantic(KclErrorDetails::new(message, vec![range])).into());
            };
            let mut sketch_surface = arg_on.into_sketch_surface();

            // Ensure that the plane has an ObjectId. Always create an Object so
            // that we're consistent with IDs.
            match &mut sketch_surface {
                SketchSurface::Plane(plane) => {
                    // Ensure that it's been created in the engine.
                    ensure_sketch_plane_in_engine(plane, exec_state, ctx, range, self.node_path.clone()).await?;
                }
                SketchSurface::Face(_) => {
                    // All faces should already be created in the engine.
                }
            }

            // Generate an ID for the sketch block. This must be done after
            // arguments so that we get the same result when the arguments are
            // cached. This must be done before the sketch block body so that no
            // matter how many IDs are generated due to objects in the body, the
            // sketch ID is always stable.
            let sketch_id = exec_state.next_object_id();
            exec_state.add_placeholder_scene_object(sketch_id, range, self.node_path.clone());
            let on_cache_name = sketch_on_cache_name(sketch_id);
            // Store in memory so that it's cached.
            exec_state.mut_stack().add(on_cache_name, arg_on_value, range)?;

            Ok((sketch_id, sketch_surface))
        } else {
            // In sketch mode, we can't re-evaluate arguments. Instead, look
            // them up from cache.

            // Generate an ID for the sketch block. This must be done before the
            // sketch block body so that no matter how many IDs are generated
            // due to objects in the body, the sketch ID is always stable.
            let sketch_id = exec_state.next_object_id();
            exec_state.add_placeholder_scene_object(sketch_id, range, self.node_path.clone());
            let on_cache_name = sketch_on_cache_name(sketch_id);
            let arg_on_value = exec_state.stack().get_owned(&on_cache_name, range)?;

            let Some(arg_on) = SketchOrSurface::from_kcl_val(&arg_on_value) else {
                let message =
                    "The `on` argument to a sketch block must be convertible to a sketch or surface.".to_owned();
                debug_assert!(false, "{message}");
                return Err(KclError::new_semantic(KclErrorDetails::new(message, vec![range])).into());
            };
            let mut sketch_surface = arg_on.into_sketch_surface();

            // Ensure that the plane has an ObjectId. Always create an Object so
            // that we're consistent with IDs.
            if sketch_surface.object_id().is_none() {
                // Look up the last object. Since this is where we would have
                // created it in real execution, it will be the last object.
                let Some(last_object) = exec_state.mod_local.artifacts.scene_objects.last() else {
                    return Err(internal_err(
                        "In sketch mode, the `on` plane argument must refer to an existing plane object.",
                        range,
                    )
                    .into());
                };
                sketch_surface.set_object_id(last_object.id);
            }

            Ok((sketch_id, sketch_surface))
        }
    }

    /// Report a non-fatal error for each argument that isn't a valid sketch
    /// block parameter. Currently, the only valid parameter is `on`.
    fn check_for_unexpected_arguments(&self, args: &Args, exec_state: &mut ExecState) -> Result<(), KclError> {
        if !args.unlabeled.is_empty() {
            let message = "Sketch block doesn't support unlabeled arguments; argument shorthand should have already been desugared";
            debug_assert!(false, "{message}");
            return Err(KclError::new_internal(KclErrorDetails::new(
                message.to_owned(),
                vec![args.source_range],
            )));
        }
        for (label, arg) in &args.labeled {
            if label == SKETCH_BLOCK_PARAM_ON {
                continue;
            }
            exec_state.err(CompilationIssue::err(
                arg.source_range,
                unexpected_kw_arg_message(label, Some(SketchBlock::CALLEE_NAME)),
            ));
        }
        Ok(())
    }

    async fn load_sketch2_into_current_scope(
        &self,
        exec_state: &mut ExecState,
        ctx: &ExecutorContext,
        source_range: SourceRange,
    ) -> Result<(), KclError> {
        let path = vec!["std".to_owned(), "solver".to_owned()];
        let resolved_path = ModulePath::from_std_import_path(&path)?;
        let module_id = ctx
            .open_module(&ImportPath::Std { path }, &[], &resolved_path, exec_state, source_range)
            .await?;
        let (env_ref, exports) = ctx.exec_module_for_items(module_id, exec_state, source_range).await?;

        for name in exports {
            let value = exec_state
                .stack()
                .memory
                .get_from_owned(&name, env_ref, source_range, 0)?;
            exec_state.mut_stack().add(name, value, source_range)?;
        }
        Ok(())
    }

    /// Augment the variables in the sketch block with properties that should be
    /// accessible on the returned sketch object. This includes metadata like
    /// the sketch so that the engine ID and surface can be accessed.
    pub(crate) fn sketch_properties(
        &self,
        sketch: Option<Sketch>,
        variables: HashMap<String, KclValue>,
    ) -> HashMap<String, KclValue> {
        let Some(sketch) = sketch else {
            // The sketch block did not produce a Sketch, so we cannot provide
            // it.
            return variables;
        };

        let mut properties = variables;

        let sketch_value = KclValue::Sketch {
            value: Box::new(sketch),
        };
        let mut meta_map = HashMap::with_capacity(1);
        meta_map.insert(SKETCH_OBJECT_META_SKETCH.to_owned(), sketch_value);
        let meta_value = KclValue::Object {
            value: meta_map,
            constrainable: false,
            object_kind: KclObjectKind::Default,
            meta: vec![Metadata {
                source_range: SourceRange::from(self),
            }],
        };

        properties.insert(SKETCH_OBJECT_META.to_owned(), meta_value);

        properties
    }
}

impl SketchBlock {
    fn prep_mem(&self, parent: EnvironmentRef, exec_state: &mut ExecState) -> Result<(), KclError> {
        exec_state.mut_stack().push_new_env_for_call(parent)
    }
}

impl Node<SketchVar> {
    pub async fn get_result(&self, exec_state: &mut ExecState, _ctx: &ExecutorContext) -> Result<KclValue, KclError> {
        let Some(sketch_block_state) = &exec_state.mod_local.sketch_block else {
            return Err(KclError::new_semantic(KclErrorDetails::new(
                "Cannot use a sketch variable outside of a sketch block".to_owned(),
                vec![SourceRange::from(self)],
            )));
        };
        let id = sketch_block_state.next_sketch_var_id();
        let sketch_var = if let Some(initial) = &self.initial {
            KclValue::from_sketch_var_literal(initial, id, self.node_path.clone(), exec_state)
        } else {
            let metadata = Metadata {
                source_range: SourceRange::from(self),
            };

            KclValue::SketchVar {
                value: Box::new(super::SketchVar {
                    id,
                    initial_value: 0.0,
                    ty: NumericType::default(),
                    node_path: self.node_path.clone(),
                    meta: vec![metadata],
                }),
            }
        };

        let Some(sketch_block_state) = &mut exec_state.mod_local.sketch_block else {
            return Err(KclError::new_semantic(KclErrorDetails::new(
                "Cannot use a sketch variable outside of a sketch block".to_owned(),
                vec![SourceRange::from(self)],
            )));
        };
        sketch_block_state.sketch_vars.push(sketch_var.clone());

        Ok(sketch_var)
    }
}

fn apply_ascription(
    value: &KclValue,
    ty: &Node<Type>,
    exec_state: &mut ExecState,
    source_range: SourceRange,
) -> Result<KclValue, KclError> {
    let ty = RuntimeType::from_parsed(ty.inner.clone(), exec_state, value.into(), false, false)
        .map_err(|e| KclError::new_semantic(e.into()))?;

    if matches!(&ty, &RuntimeType::Primitive(PrimitiveType::Number(..))) {
        exec_state.clear_units_warnings(&source_range);
    }

    value.coerce(&ty, false, exec_state).map_err(|_| {
        let suggestion = if ty == RuntimeType::length() {
            ", you might try coercing to a fully specified numeric type such as `mm`"
        } else if ty == RuntimeType::angle() {
            ", you might try coercing to a fully specified numeric type such as `deg`"
        } else {
            ""
        };
        let ty_str = if let Some(ty) = value.principal_type() {
            format!("(with type `{ty}`) ")
        } else {
            String::new()
        };
        KclError::new_semantic(KclErrorDetails::new(
            format!(
                "could not coerce {} {ty_str}to type `{ty}`{suggestion}",
                value.human_friendly_type()
            ),
            vec![source_range],
        ))
    })
}

impl BinaryPart {
    #[async_recursion]
    pub(super) async fn get_result(
        &self,
        exec_state: &mut ExecState,
        ctx: &ExecutorContext,
    ) -> Result<KclValueControlFlow, KclError> {
        match self {
            BinaryPart::Literal(literal) => Ok(KclValue::from_literal((**literal).clone(), exec_state).continue_()),
            BinaryPart::Name(name) => name.get_result(exec_state, ctx).await.map(KclValue::continue_),
            BinaryPart::BinaryExpression(binary_expression) => binary_expression.get_result(exec_state, ctx).await,
            BinaryPart::CallExpressionKw(call_expression) => call_expression.execute(exec_state, ctx).await,
            BinaryPart::UnaryExpression(unary_expression) => unary_expression.get_result(exec_state, ctx).await,
            BinaryPart::MemberExpression(member_expression) => member_expression.get_result(exec_state, ctx).await,
            BinaryPart::ArrayExpression(e) => e.execute(exec_state, ctx).await,
            BinaryPart::ArrayRangeExpression(e) => e.execute(exec_state, ctx).await,
            BinaryPart::ObjectExpression(e) => e.execute(exec_state, ctx).await,
            BinaryPart::IfExpression(e) => e.get_result(exec_state, ctx).await,
            BinaryPart::AscribedExpression(e) => e.get_result(exec_state, ctx).await,
            BinaryPart::SketchVar(e) => e.get_result(exec_state, ctx).await.map(KclValue::continue_),
        }
    }
}

impl Node<Name> {
    pub(super) async fn get_result(
        &self,
        exec_state: &mut ExecState,
        ctx: &ExecutorContext,
    ) -> Result<KclValue, KclError> {
        let being_declared = exec_state.mod_local.being_declared.clone();
        self.get_result_inner(exec_state, ctx)
            .await
            .map_err(|e| var_in_own_ref_err(e, &being_declared))
    }

    async fn get_result_inner(&self, exec_state: &mut ExecState, ctx: &ExecutorContext) -> Result<KclValue, KclError> {
        if self.abs_path {
            return Err(KclError::new_semantic(KclErrorDetails::new(
                "Absolute paths (names beginning with `::` are not yet supported)".to_owned(),
                self.as_source_ranges(),
            )));
        }

        let mod_name = format!("{}{}", memory::MODULE_PREFIX, self.name.name);

        if self.path.is_empty() {
            if let Ok(item_value) = exec_state.stack().get(&self.name.name, self.into()) {
                return Ok(item_value);
            }
            return exec_state.stack().get(&mod_name, self.into());
        }

        let mut mem_spec: Option<(EnvironmentRef, Vec<String>)> = None;
        for p in &self.path {
            let value = match mem_spec {
                Some((env, exports)) => {
                    if !exports.contains(&p.name) {
                        return Err(KclError::new_semantic(KclErrorDetails::new(
                            format!("Item {} not found in module's exported items", p.name),
                            p.as_source_ranges(),
                        )));
                    }

                    exec_state
                        .stack()
                        .memory
                        .get_from_owned(&p.name, env, p.as_source_range(), 0)?
                }
                None => exec_state
                    .stack()
                    .get(&format!("{}{}", memory::MODULE_PREFIX, p.name), self.into())?,
            };

            let module_id = match value {
                KclValue::Module { value, .. } => value,
                value => {
                    return Err(KclError::new_semantic(KclErrorDetails::new(
                        format!(
                            "Identifier in path must refer to a module, found {}",
                            value.human_friendly_type()
                        ),
                        p.as_source_ranges(),
                    )));
                }
            };

            mem_spec = Some(
                ctx.exec_module_for_items(module_id, exec_state, p.as_source_range())
                    .await?,
            );
        }

        let (env, exports) = mem_spec.unwrap();

        let item_exported = exports.contains(&self.name.name);
        let item_value = exec_state
            .stack()
            .memory
            .get_from_owned(&self.name.name, env, self.name.as_source_range(), 0);

        // Item is defined and exported.
        if item_exported && item_value.is_ok() {
            return item_value;
        }

        let mod_exported = exports.contains(&mod_name);
        let mod_value = exec_state
            .stack()
            .memory
            .get_from_owned(&mod_name, env, self.name.as_source_range(), 0);

        // Module is defined and exported.
        if mod_exported && mod_value.is_ok() {
            return mod_value;
        }

        // Neither item or module is defined.
        if item_value.is_err() && mod_value.is_err() {
            return item_value;
        }

        // Either item or module is defined, but not exported.
        debug_assert!((item_value.is_ok() && !item_exported) || (mod_value.is_ok() && !mod_exported));
        Err(KclError::new_semantic(KclErrorDetails::new(
            format!("Item {} not found in module's exported items", self.name.name),
            self.name.as_source_ranges(),
        )))
    }
}

impl Node<MemberExpression> {
    async fn get_result(
        &self,
        exec_state: &mut ExecState,
        ctx: &ExecutorContext,
    ) -> Result<KclValueControlFlow, KclError> {
        let meta = Metadata {
            source_range: SourceRange::from(self),
        };
        // TODO: The order of execution is wrong. We should execute the object
        // *before* the property.
        let property = Property::try_from(
            self.computed,
            self.property.clone(),
            exec_state,
            self.into(),
            ctx,
            &meta,
            &[],
            StatementKind::Expression,
        )
        .await?;
        let object_cf = ctx
            .execute_expr(&self.object, exec_state, &meta, &[], StatementKind::Expression)
            .await?;
        let object = control_continue!(object_cf);

        // Check the property and object match -- e.g. ints for arrays, strs for objects.
        match (object, property, self.computed) {
            (KclValue::Segment { value: segment }, Property::String(property), false) => match property.as_str() {
                "at" => match &segment.repr {
                    SegmentRepr::Unsolved { segment } => {
                        match &segment.kind {
                            UnsolvedSegmentKind::Point { position, .. } => {
                                // TODO: assert that types of all elements are the same.
                                Ok(KclValue::HomArray {
                                    value: vec![
                                        KclValue::from_unsolved_expr(position[0].clone(), segment.meta.clone()),
                                        KclValue::from_unsolved_expr(position[1].clone(), segment.meta.clone()),
                                    ],
                                    ty: RuntimeType::any(),
                                }
                                .continue_())
                            }
                            _ => Err(KclError::new_undefined_value(
                                KclErrorDetails::new(
                                    format!("Property '{property}' not found in segment"),
                                    vec![self.clone().into()],
                                ),
                                None,
                            )),
                        }
                    }
                    SegmentRepr::Solved { segment } => {
                        match &segment.kind {
                            SegmentKind::Point { position, .. } => {
                                // TODO: assert that types of all elements are the same.
                                Ok(KclValue::array_from_point2d(
                                    [position[0].n, position[1].n],
                                    position[0].ty,
                                    segment.meta.clone(),
                                )
                                .continue_())
                            }
                            _ => Err(KclError::new_undefined_value(
                                KclErrorDetails::new(
                                    format!("Property '{property}' not found in segment"),
                                    vec![self.clone().into()],
                                ),
                                None,
                            )),
                        }
                    }
                },
                "start" => match &segment.repr {
                    SegmentRepr::Unsolved { segment } => match &segment.kind {
                        UnsolvedSegmentKind::Point { .. } => Err(KclError::new_undefined_value(
                            KclErrorDetails::new(
                                format!("Property '{property}' not found in point segment"),
                                vec![self.clone().into()],
                            ),
                            None,
                        )),
                        UnsolvedSegmentKind::Line {
                            start,
                            ctor,
                            start_object_id,
                            ..
                        } => Ok(KclValue::Segment {
                            value: Box::new(AbstractSegment {
                                repr: SegmentRepr::Unsolved {
                                    segment: Box::new(UnsolvedSegment {
                                        id: segment.id,
                                        object_id: *start_object_id,
                                        kind: UnsolvedSegmentKind::Point {
                                            position: start.clone(),
                                            ctor: Box::new(PointCtor {
                                                position: ctor.start.clone(),
                                            }),
                                        },
                                        tag: segment.tag.clone(),
                                        node_path: segment.node_path.clone(),
                                        meta: segment.meta.clone(),
                                    }),
                                },
                                meta: segment.meta.clone(),
                            }),
                        }
                        .continue_()),
                        UnsolvedSegmentKind::Arc {
                            start,
                            ctor,
                            start_object_id,
                            ..
                        } => Ok(KclValue::Segment {
                            value: Box::new(AbstractSegment {
                                repr: SegmentRepr::Unsolved {
                                    segment: Box::new(UnsolvedSegment {
                                        id: segment.id,
                                        object_id: *start_object_id,
                                        kind: UnsolvedSegmentKind::Point {
                                            position: start.clone(),
                                            ctor: Box::new(PointCtor {
                                                position: ctor.start.clone(),
                                            }),
                                        },
                                        tag: segment.tag.clone(),
                                        node_path: segment.node_path.clone(),
                                        meta: segment.meta.clone(),
                                    }),
                                },
                                meta: segment.meta.clone(),
                            }),
                        }
                        .continue_()),
                        UnsolvedSegmentKind::Circle {
                            start,
                            ctor,
                            start_object_id,
                            ..
                        } => Ok(KclValue::Segment {
                            value: Box::new(AbstractSegment {
                                repr: SegmentRepr::Unsolved {
                                    segment: Box::new(UnsolvedSegment {
                                        id: segment.id,
                                        object_id: *start_object_id,
                                        kind: UnsolvedSegmentKind::Point {
                                            position: start.clone(),
                                            ctor: Box::new(PointCtor {
                                                position: ctor.start.clone(),
                                            }),
                                        },
                                        tag: segment.tag.clone(),
                                        node_path: segment.node_path.clone(),
                                        meta: segment.meta.clone(),
                                    }),
                                },
                                meta: segment.meta.clone(),
                            }),
                        }
                        .continue_()),
                        UnsolvedSegmentKind::ControlPointSpline { .. } => Err(KclError::new_undefined_value(
                            KclErrorDetails::new(
                                format!("Property '{property}' not found in segment"),
                                vec![self.clone().into()],
                            ),
                            None,
                        )),
                    },
                    SegmentRepr::Solved { segment } => match &segment.kind {
                        SegmentKind::Point { .. } => Err(KclError::new_undefined_value(
                            KclErrorDetails::new(
                                format!("Property '{property}' not found in point segment"),
                                vec![self.clone().into()],
                            ),
                            None,
                        )),
                        SegmentKind::Line {
                            start,
                            ctor,
                            start_object_id,
                            start_freedom,
                            ..
                        } => Ok(KclValue::Segment {
                            value: Box::new(AbstractSegment {
                                repr: SegmentRepr::Solved {
                                    segment: Box::new(Segment {
                                        id: segment.id,
                                        object_id: *start_object_id,
                                        kind: SegmentKind::Point {
                                            position: start.clone(),
                                            ctor: Box::new(PointCtor {
                                                position: ctor.start.clone(),
                                            }),
                                            freedom: *start_freedom,
                                        },
                                        surface: segment.surface.clone(),
                                        sketch_id: segment.sketch_id,
                                        sketch: segment.sketch.clone(),
                                        tag: segment.tag.clone(),
                                        node_path: segment.node_path.clone(),
                                        meta: segment.meta.clone(),
                                    }),
                                },
                                meta: segment.meta.clone(),
                            }),
                        }
                        .continue_()),
                        SegmentKind::Arc {
                            start,
                            ctor,
                            start_object_id,
                            start_freedom,
                            ..
                        } => Ok(KclValue::Segment {
                            value: Box::new(AbstractSegment {
                                repr: SegmentRepr::Solved {
                                    segment: Box::new(Segment {
                                        id: segment.id,
                                        object_id: *start_object_id,
                                        kind: SegmentKind::Point {
                                            position: start.clone(),
                                            ctor: Box::new(PointCtor {
                                                position: ctor.start.clone(),
                                            }),
                                            freedom: *start_freedom,
                                        },
                                        surface: segment.surface.clone(),
                                        sketch_id: segment.sketch_id,
                                        sketch: segment.sketch.clone(),
                                        tag: segment.tag.clone(),
                                        node_path: segment.node_path.clone(),
                                        meta: segment.meta.clone(),
                                    }),
                                },
                                meta: segment.meta.clone(),
                            }),
                        }
                        .continue_()),
                        SegmentKind::Circle {
                            start,
                            ctor,
                            start_object_id,
                            start_freedom,
                            ..
                        } => Ok(KclValue::Segment {
                            value: Box::new(AbstractSegment {
                                repr: SegmentRepr::Solved {
                                    segment: Box::new(Segment {
                                        id: segment.id,
                                        object_id: *start_object_id,
                                        kind: SegmentKind::Point {
                                            position: start.clone(),
                                            ctor: Box::new(PointCtor {
                                                position: ctor.start.clone(),
                                            }),
                                            freedom: *start_freedom,
                                        },
                                        surface: segment.surface.clone(),
                                        sketch_id: segment.sketch_id,
                                        sketch: segment.sketch.clone(),
                                        tag: segment.tag.clone(),
                                        node_path: segment.node_path.clone(),
                                        meta: segment.meta.clone(),
                                    }),
                                },
                                meta: segment.meta.clone(),
                            }),
                        }
                        .continue_()),
                        SegmentKind::ControlPointSpline { .. } => Err(KclError::new_undefined_value(
                            KclErrorDetails::new(
                                format!("Property '{property}' not found in segment"),
                                vec![self.clone().into()],
                            ),
                            None,
                        )),
                    },
                },
                "end" => match &segment.repr {
                    SegmentRepr::Unsolved { segment } => match &segment.kind {
                        UnsolvedSegmentKind::Point { .. } => Err(KclError::new_undefined_value(
                            KclErrorDetails::new(
                                format!("Property '{property}' not found in point segment"),
                                vec![self.clone().into()],
                            ),
                            None,
                        )),
                        UnsolvedSegmentKind::Line {
                            end,
                            ctor,
                            end_object_id,
                            ..
                        } => Ok(KclValue::Segment {
                            value: Box::new(AbstractSegment {
                                repr: SegmentRepr::Unsolved {
                                    segment: Box::new(UnsolvedSegment {
                                        id: segment.id,
                                        object_id: *end_object_id,
                                        kind: UnsolvedSegmentKind::Point {
                                            position: end.clone(),
                                            ctor: Box::new(PointCtor {
                                                position: ctor.end.clone(),
                                            }),
                                        },
                                        tag: segment.tag.clone(),
                                        node_path: segment.node_path.clone(),
                                        meta: segment.meta.clone(),
                                    }),
                                },
                                meta: segment.meta.clone(),
                            }),
                        }
                        .continue_()),
                        UnsolvedSegmentKind::Arc {
                            end,
                            ctor,
                            end_object_id,
                            ..
                        } => Ok(KclValue::Segment {
                            value: Box::new(AbstractSegment {
                                repr: SegmentRepr::Unsolved {
                                    segment: Box::new(UnsolvedSegment {
                                        id: segment.id,
                                        object_id: *end_object_id,
                                        kind: UnsolvedSegmentKind::Point {
                                            position: end.clone(),
                                            ctor: Box::new(PointCtor {
                                                position: ctor.end.clone(),
                                            }),
                                        },
                                        tag: segment.tag.clone(),
                                        node_path: segment.node_path.clone(),
                                        meta: segment.meta.clone(),
                                    }),
                                },
                                meta: segment.meta.clone(),
                            }),
                        }
                        .continue_()),
                        UnsolvedSegmentKind::Circle { .. } => Err(KclError::new_undefined_value(
                            KclErrorDetails::new(
                                format!("Property '{property}' not found in segment"),
                                vec![self.into()],
                            ),
                            None,
                        )),
                        UnsolvedSegmentKind::ControlPointSpline { .. } => Err(KclError::new_undefined_value(
                            KclErrorDetails::new(
                                format!("Property '{property}' not found in segment"),
                                vec![self.clone().into()],
                            ),
                            None,
                        )),
                    },
                    SegmentRepr::Solved { segment } => match &segment.kind {
                        SegmentKind::Point { .. } => Err(KclError::new_undefined_value(
                            KclErrorDetails::new(
                                format!("Property '{property}' not found in point segment"),
                                vec![self.clone().into()],
                            ),
                            None,
                        )),
                        SegmentKind::Line {
                            end,
                            ctor,
                            end_object_id,
                            end_freedom,
                            ..
                        } => Ok(KclValue::Segment {
                            value: Box::new(AbstractSegment {
                                repr: SegmentRepr::Solved {
                                    segment: Box::new(Segment {
                                        id: segment.id,
                                        object_id: *end_object_id,
                                        kind: SegmentKind::Point {
                                            position: end.clone(),
                                            ctor: Box::new(PointCtor {
                                                position: ctor.end.clone(),
                                            }),
                                            freedom: *end_freedom,
                                        },
                                        surface: segment.surface.clone(),
                                        sketch_id: segment.sketch_id,
                                        sketch: segment.sketch.clone(),
                                        tag: segment.tag.clone(),
                                        node_path: segment.node_path.clone(),
                                        meta: segment.meta.clone(),
                                    }),
                                },
                                meta: segment.meta.clone(),
                            }),
                        }
                        .continue_()),
                        SegmentKind::Arc {
                            end,
                            ctor,
                            end_object_id,
                            end_freedom,
                            ..
                        } => Ok(KclValue::Segment {
                            value: Box::new(AbstractSegment {
                                repr: SegmentRepr::Solved {
                                    segment: Box::new(Segment {
                                        id: segment.id,
                                        object_id: *end_object_id,
                                        kind: SegmentKind::Point {
                                            position: end.clone(),
                                            ctor: Box::new(PointCtor {
                                                position: ctor.end.clone(),
                                            }),
                                            freedom: *end_freedom,
                                        },
                                        surface: segment.surface.clone(),
                                        sketch_id: segment.sketch_id,
                                        sketch: segment.sketch.clone(),
                                        tag: segment.tag.clone(),
                                        node_path: segment.node_path.clone(),
                                        meta: segment.meta.clone(),
                                    }),
                                },
                                meta: segment.meta.clone(),
                            }),
                        }
                        .continue_()),
                        SegmentKind::Circle { .. } => Err(KclError::new_undefined_value(
                            KclErrorDetails::new(
                                format!("Property '{property}' not found in segment"),
                                vec![self.into()],
                            ),
                            None,
                        )),
                        SegmentKind::ControlPointSpline { .. } => Err(KclError::new_undefined_value(
                            KclErrorDetails::new(
                                format!("Property '{property}' not found in segment"),
                                vec![self.clone().into()],
                            ),
                            None,
                        )),
                    },
                },
                "center" => match &segment.repr {
                    SegmentRepr::Unsolved { segment } => match &segment.kind {
                        UnsolvedSegmentKind::Arc {
                            center,
                            ctor,
                            center_object_id,
                            ..
                        } => Ok(KclValue::Segment {
                            value: Box::new(AbstractSegment {
                                repr: SegmentRepr::Unsolved {
                                    segment: Box::new(UnsolvedSegment {
                                        id: segment.id,
                                        object_id: *center_object_id,
                                        kind: UnsolvedSegmentKind::Point {
                                            position: center.clone(),
                                            ctor: Box::new(PointCtor {
                                                position: ctor.center.clone(),
                                            }),
                                        },
                                        tag: segment.tag.clone(),
                                        node_path: segment.node_path.clone(),
                                        meta: segment.meta.clone(),
                                    }),
                                },
                                meta: segment.meta.clone(),
                            }),
                        }
                        .continue_()),
                        UnsolvedSegmentKind::Circle {
                            center,
                            ctor,
                            center_object_id,
                            ..
                        } => Ok(KclValue::Segment {
                            value: Box::new(AbstractSegment {
                                repr: SegmentRepr::Unsolved {
                                    segment: Box::new(UnsolvedSegment {
                                        id: segment.id,
                                        object_id: *center_object_id,
                                        kind: UnsolvedSegmentKind::Point {
                                            position: center.clone(),
                                            ctor: Box::new(PointCtor {
                                                position: ctor.center.clone(),
                                            }),
                                        },
                                        tag: segment.tag.clone(),
                                        node_path: segment.node_path.clone(),
                                        meta: segment.meta.clone(),
                                    }),
                                },
                                meta: segment.meta.clone(),
                            }),
                        }
                        .continue_()),
                        _ => Err(KclError::new_undefined_value(
                            KclErrorDetails::new(
                                format!("Property '{property}' not found in segment"),
                                vec![self.clone().into()],
                            ),
                            None,
                        )),
                    },
                    SegmentRepr::Solved { segment } => match &segment.kind {
                        SegmentKind::Arc {
                            center,
                            ctor,
                            center_object_id,
                            center_freedom,
                            ..
                        } => Ok(KclValue::Segment {
                            value: Box::new(AbstractSegment {
                                repr: SegmentRepr::Solved {
                                    segment: Box::new(Segment {
                                        id: segment.id,
                                        object_id: *center_object_id,
                                        kind: SegmentKind::Point {
                                            position: center.clone(),
                                            ctor: Box::new(PointCtor {
                                                position: ctor.center.clone(),
                                            }),
                                            freedom: *center_freedom,
                                        },
                                        surface: segment.surface.clone(),
                                        sketch_id: segment.sketch_id,
                                        sketch: segment.sketch.clone(),
                                        tag: segment.tag.clone(),
                                        node_path: segment.node_path.clone(),
                                        meta: segment.meta.clone(),
                                    }),
                                },
                                meta: segment.meta.clone(),
                            }),
                        }
                        .continue_()),
                        SegmentKind::Circle {
                            center,
                            ctor,
                            center_object_id,
                            center_freedom,
                            ..
                        } => Ok(KclValue::Segment {
                            value: Box::new(AbstractSegment {
                                repr: SegmentRepr::Solved {
                                    segment: Box::new(Segment {
                                        id: segment.id,
                                        object_id: *center_object_id,
                                        kind: SegmentKind::Point {
                                            position: center.clone(),
                                            ctor: Box::new(PointCtor {
                                                position: ctor.center.clone(),
                                            }),
                                            freedom: *center_freedom,
                                        },
                                        surface: segment.surface.clone(),
                                        sketch_id: segment.sketch_id,
                                        sketch: segment.sketch.clone(),
                                        tag: segment.tag.clone(),
                                        node_path: segment.node_path.clone(),
                                        meta: segment.meta.clone(),
                                    }),
                                },
                                meta: segment.meta.clone(),
                            }),
                        }
                        .continue_()),
                        _ => Err(KclError::new_undefined_value(
                            KclErrorDetails::new(
                                format!("Property '{property}' not found in segment"),
                                vec![self.clone().into()],
                            ),
                            None,
                        )),
                    },
                },
                "controls" => match &segment.repr {
                    SegmentRepr::Unsolved { segment } => match &segment.kind {
                        UnsolvedSegmentKind::ControlPointSpline {
                            controls,
                            ctor,
                            control_object_ids,
                            ..
                        } => Ok(KclValue::HomArray {
                            value: controls
                                .iter()
                                .zip(control_object_ids.iter())
                                .zip(ctor.points.iter())
                                .map(|((position, object_id), ctor_point)| KclValue::Segment {
                                    value: Box::new(AbstractSegment {
                                        repr: SegmentRepr::Unsolved {
                                            segment: Box::new(UnsolvedSegment {
                                                id: segment.id,
                                                object_id: *object_id,
                                                kind: UnsolvedSegmentKind::Point {
                                                    position: position.clone(),
                                                    ctor: Box::new(PointCtor {
                                                        position: ctor_point.clone(),
                                                    }),
                                                },
                                                tag: segment.tag.clone(),
                                                node_path: segment.node_path.clone(),
                                                meta: segment.meta.clone(),
                                            }),
                                        },
                                        meta: segment.meta.clone(),
                                    }),
                                })
                                .collect(),
                            ty: RuntimeType::segment(),
                        }
                        .continue_()),
                        _ => Err(KclError::new_undefined_value(
                            KclErrorDetails::new(
                                format!("Property '{property}' not found in segment"),
                                vec![self.clone().into()],
                            ),
                            None,
                        )),
                    },
                    SegmentRepr::Solved { segment } => match &segment.kind {
                        SegmentKind::ControlPointSpline {
                            controls,
                            ctor,
                            control_object_ids,
                            control_freedoms,
                            ..
                        } => Ok(KclValue::HomArray {
                            value: controls
                                .iter()
                                .zip(control_object_ids.iter())
                                .zip(control_freedoms.iter())
                                .zip(ctor.points.iter())
                                .map(|(((position, object_id), freedom), ctor_point)| KclValue::Segment {
                                    value: Box::new(AbstractSegment {
                                        repr: SegmentRepr::Solved {
                                            segment: Box::new(Segment {
                                                id: segment.id,
                                                object_id: *object_id,
                                                kind: SegmentKind::Point {
                                                    position: position.clone(),
                                                    ctor: Box::new(PointCtor {
                                                        position: ctor_point.clone(),
                                                    }),
                                                    freedom: *freedom,
                                                },
                                                surface: segment.surface.clone(),
                                                sketch_id: segment.sketch_id,
                                                sketch: segment.sketch.clone(),
                                                tag: segment.tag.clone(),
                                                node_path: segment.node_path.clone(),
                                                meta: segment.meta.clone(),
                                            }),
                                        },
                                        meta: segment.meta.clone(),
                                    }),
                                })
                                .collect(),
                            ty: RuntimeType::segment(),
                        }
                        .continue_()),
                        _ => Err(KclError::new_undefined_value(
                            KclErrorDetails::new(
                                format!("Property '{property}' not found in segment"),
                                vec![self.clone().into()],
                            ),
                            None,
                        )),
                    },
                },
                "edges" => match &segment.repr {
                    SegmentRepr::Unsolved { segment } => match &segment.kind {
                        UnsolvedSegmentKind::ControlPointSpline {
                            controls,
                            ctor,
                            control_object_ids,
                            control_polygon_edge_object_ids,
                            construction,
                            ..
                        } => Ok(KclValue::HomArray {
                            value: control_polygon_edge_object_ids
                                .iter()
                                .enumerate()
                                .map(|(index, object_id)| KclValue::Segment {
                                    value: Box::new(AbstractSegment {
                                        repr: SegmentRepr::Unsolved {
                                            segment: Box::new(UnsolvedSegment {
                                                id: segment.id,
                                                object_id: *object_id,
                                                kind: UnsolvedSegmentKind::Line {
                                                    start: controls[index].clone(),
                                                    end: controls[index + 1].clone(),
                                                    ctor: Box::new(LineCtor {
                                                        start: ctor.points[index].clone(),
                                                        end: ctor.points[index + 1].clone(),
                                                        construction: Some(*construction),
                                                    }),
                                                    start_object_id: control_object_ids[index],
                                                    end_object_id: control_object_ids[index + 1],
                                                    construction: *construction,
                                                },
                                                tag: segment.tag.clone(),
                                                node_path: segment.node_path.clone(),
                                                meta: segment.meta.clone(),
                                            }),
                                        },
                                        meta: segment.meta.clone(),
                                    }),
                                })
                                .collect(),
                            ty: RuntimeType::segment(),
                        }
                        .continue_()),
                        _ => Err(KclError::new_undefined_value(
                            KclErrorDetails::new(
                                format!("Property '{property}' not found in segment"),
                                vec![self.clone().into()],
                            ),
                            None,
                        )),
                    },
                    SegmentRepr::Solved { segment } => match &segment.kind {
                        SegmentKind::ControlPointSpline {
                            controls,
                            ctor,
                            control_object_ids,
                            control_polygon_edge_object_ids,
                            control_freedoms,
                            construction,
                            ..
                        } => Ok(KclValue::HomArray {
                            value: control_polygon_edge_object_ids
                                .iter()
                                .enumerate()
                                .map(|(index, object_id)| KclValue::Segment {
                                    value: Box::new(AbstractSegment {
                                        repr: SegmentRepr::Solved {
                                            segment: Box::new(Segment {
                                                id: segment.id,
                                                object_id: *object_id,
                                                kind: SegmentKind::Line {
                                                    start: controls[index].clone(),
                                                    end: controls[index + 1].clone(),
                                                    ctor: Box::new(LineCtor {
                                                        start: ctor.points[index].clone(),
                                                        end: ctor.points[index + 1].clone(),
                                                        construction: Some(*construction),
                                                    }),
                                                    start_object_id: control_object_ids[index],
                                                    end_object_id: control_object_ids[index + 1],
                                                    start_freedom: control_freedoms[index],
                                                    end_freedom: control_freedoms[index + 1],
                                                    construction: *construction,
                                                },
                                                surface: segment.surface.clone(),
                                                sketch_id: segment.sketch_id,
                                                sketch: segment.sketch.clone(),
                                                tag: segment.tag.clone(),
                                                node_path: segment.node_path.clone(),
                                                meta: segment.meta.clone(),
                                            }),
                                        },
                                        meta: segment.meta.clone(),
                                    }),
                                })
                                .collect(),
                            ty: RuntimeType::segment(),
                        }
                        .continue_()),
                        _ => Err(KclError::new_undefined_value(
                            KclErrorDetails::new(
                                format!("Property '{property}' not found in segment"),
                                vec![self.clone().into()],
                            ),
                            None,
                        )),
                    },
                },
                other => Err(KclError::new_undefined_value(
                    KclErrorDetails::new(
                        format!("Property '{other}' not found in segment"),
                        vec![self.clone().into()],
                    ),
                    None,
                )),
            },
            (KclValue::Plane { value: plane }, Property::String(property), false) => match property.as_str() {
                "zAxis" => {
                    let (p, u) = plane.info.z_axis.as_3_dims();
                    Ok(KclValue::array_from_point3d(p, NumericType::optional_length(u), vec![meta]).continue_())
                }
                "yAxis" => {
                    let (p, u) = plane.info.y_axis.as_3_dims();
                    Ok(KclValue::array_from_point3d(p, NumericType::optional_length(u), vec![meta]).continue_())
                }
                "xAxis" => {
                    let (p, u) = plane.info.x_axis.as_3_dims();
                    Ok(KclValue::array_from_point3d(p, NumericType::optional_length(u), vec![meta]).continue_())
                }
                "origin" => {
                    let (p, u) = plane.info.origin.as_3_dims();
                    Ok(KclValue::array_from_point3d(p, NumericType::optional_length(u), vec![meta]).continue_())
                }
                other => Err(KclError::new_undefined_value(
                    KclErrorDetails::new(
                        format!("Property '{other}' not found in plane"),
                        vec![self.clone().into()],
                    ),
                    None,
                )),
            },
            (
                KclValue::Object {
                    value: map,
                    object_kind,
                    ..
                },
                Property::String(property),
                false,
            ) => {
                if let Some(value) = map.get(&property) {
                    if object_kind
                        .deprecated_solid_tag_names()
                        .iter()
                        .any(|tag_name| tag_name == &property)
                    {
                        exec_state.warn(
                            CompilationIssue::err(
                                SourceRange::from(self),
                                format!(
                                    "Accessing solid-created face `{property}` through sketch tags is deprecated. Use the body's faces instead, e.g. `body.faces.{property}`."
                                ),
                            ),
                            annotations::WARN_DEPRECATED,
                        );
                    }
                    Ok(value.to_owned().continue_())
                } else {
                    Err(KclError::new_undefined_value(
                        KclErrorDetails::new(
                            format!("Property '{property}' not found in object"),
                            vec![self.clone().into()],
                        ),
                        None,
                    ))
                }
            }
            (KclValue::Object { .. }, Property::String(property), true) => {
                Err(KclError::new_semantic(KclErrorDetails::new(
                    format!("Cannot index object with string; use dot notation instead, e.g. `obj.{property}`"),
                    vec![self.clone().into()],
                )))
            }
            (KclValue::Object { value: map, .. }, p @ Property::UInt(i), _) => {
                if i == 0
                    && let Some(value) = map.get("x")
                {
                    return Ok(value.to_owned().continue_());
                }
                if i == 1
                    && let Some(value) = map.get("y")
                {
                    return Ok(value.to_owned().continue_());
                }
                if i == 2
                    && let Some(value) = map.get("z")
                {
                    return Ok(value.to_owned().continue_());
                }
                let t = p.type_name();
                let article = article_for(t);
                Err(KclError::new_semantic(KclErrorDetails::new(
                    format!("Only strings can be used as the property of an object, but you're using {article} {t}",),
                    vec![self.clone().into()],
                )))
            }
            (KclValue::HomArray { value: arr, .. }, Property::UInt(index), _) => {
                let value_of_arr = arr.get(index);
                if let Some(value) = value_of_arr {
                    Ok(value.to_owned().continue_())
                } else {
                    Err(KclError::new_undefined_value(
                        KclErrorDetails::new(
                            format!("The array doesn't have any item at index {index}"),
                            vec![self.clone().into()],
                        ),
                        None,
                    ))
                }
            }
            // Singletons and single-element arrays should be interchangeable, but only indexing by 0 should work.
            // This is kind of a silly property, but it's possible it occurs in generic code or something.
            (obj, Property::UInt(0), _) => Ok(obj.continue_()),
            (KclValue::HomArray { .. }, p, _) => {
                let t = p.type_name();
                let article = article_for(t);
                Err(KclError::new_semantic(KclErrorDetails::new(
                    format!("Only integers >= 0 can be used as the index of an array, but you're using {article} {t}",),
                    vec![self.clone().into()],
                )))
            }
            (KclValue::Solid { value }, Property::String(prop), false) if prop == "sketch" => {
                let Some(sketch) = value.sketch() else {
                    return Err(KclError::new_semantic(KclErrorDetails::new(
                        "This solid was created without a sketch, so `solid.sketch` is unavailable.".to_owned(),
                        vec![self.clone().into()],
                    )));
                };
                Ok(KclValue::Sketch {
                    value: Box::new(sketch.clone()),
                }
                .continue_())
            }
            (KclValue::Solid { value: solid }, Property::String(prop), false) if prop == "faces" => {
                Ok(KclValue::Object {
                    meta: vec![Metadata {
                        source_range: SourceRange::from(self.clone()),
                    }],
                    value: solid
                        .faces
                        .iter()
                        .map(|(k, tag)| (k.to_owned(), KclValue::TagIdentifier(Box::new(tag.to_owned()))))
                        .collect(),
                    constrainable: false,
                    object_kind: KclObjectKind::Default,
                }
                .continue_())
            }
            (geometry @ KclValue::Solid { .. }, Property::String(prop), false) if prop == "tags" => {
                // This is a common mistake.
                Err(KclError::new_semantic(KclErrorDetails::new(
                    format!(
                        "Property `{prop}` not found on {}. You can get a solid's faces through `exampleSolid.faces`, or its sketch tags through `exampleSolid.sketch.tags`.",
                        geometry.human_friendly_type()
                    ),
                    vec![self.clone().into()],
                )))
            }
            (KclValue::Sketch { value: sk }, Property::String(prop), false) if prop == "tags" => Ok(KclValue::Object {
                meta: vec![Metadata {
                    source_range: SourceRange::from(self.clone()),
                }],
                value: sk
                    .tags
                    .iter()
                    .map(|(k, tag)| (k.to_owned(), KclValue::TagIdentifier(Box::new(tag.to_owned()))))
                    .collect(),
                constrainable: false,
                object_kind: KclObjectKind::SketchTags {
                    deprecated_solid_tag_names: sk
                        .tags
                        .iter()
                        .filter(|(_, tag)| tag.is_body_created_tag())
                        .map(|(name, _)| name.to_owned())
                        .collect(),
                },
            }
            .continue_()),
            (geometry @ (KclValue::Sketch { .. } | KclValue::Solid { .. }), Property::String(property), false) => {
                Err(KclError::new_semantic(KclErrorDetails::new(
                    format!("Property `{property}` not found on {}", geometry.human_friendly_type()),
                    vec![self.clone().into()],
                )))
            }
            (being_indexed, _, false) => Err(KclError::new_semantic(KclErrorDetails::new(
                format!(
                    "Only objects can have members accessed with dot notation, but you're trying to access {}",
                    being_indexed.human_friendly_type()
                ),
                vec![self.clone().into()],
            ))),
            (being_indexed, _, true) => Err(KclError::new_semantic(KclErrorDetails::new(
                format!(
                    "Only arrays can be indexed, but you're trying to index {}",
                    being_indexed.human_friendly_type()
                ),
                vec![self.clone().into()],
            ))),
        }
    }
}

impl Node<BinaryExpression> {
    pub(super) async fn get_result(
        &self,
        exec_state: &mut ExecState,
        ctx: &ExecutorContext,
    ) -> Result<KclValueControlFlow, KclError> {
        enum State {
            EvaluateLeft(Node<BinaryExpression>),
            FromLeft {
                node: Node<BinaryExpression>,
            },
            EvaluateRight {
                node: Node<BinaryExpression>,
                left: KclValue,
            },
            FromRight {
                node: Node<BinaryExpression>,
                left: KclValue,
            },
        }

        let mut stack = vec![State::EvaluateLeft(self.clone())];
        let mut last_result: Option<KclValue> = None;

        while let Some(state) = stack.pop() {
            match state {
                State::EvaluateLeft(node) => {
                    let left_part = node.left.clone();
                    match left_part {
                        BinaryPart::BinaryExpression(child) => {
                            stack.push(State::FromLeft { node });
                            stack.push(State::EvaluateLeft(*child));
                        }
                        part => {
                            let left_value = part.get_result(exec_state, ctx).await?;
                            let left_value = control_continue!(left_value);
                            stack.push(State::EvaluateRight { node, left: left_value });
                        }
                    }
                }
                State::FromLeft { node } => {
                    let Some(left_value) = last_result.take() else {
                        return Err(Self::missing_result_error(&node));
                    };
                    stack.push(State::EvaluateRight { node, left: left_value });
                }
                State::EvaluateRight { node, left } => {
                    let right_part = node.right.clone();
                    match right_part {
                        BinaryPart::BinaryExpression(child) => {
                            stack.push(State::FromRight { node, left });
                            stack.push(State::EvaluateLeft(*child));
                        }
                        part => {
                            let right_value = part.get_result(exec_state, ctx).await?;
                            let right_value = control_continue!(right_value);
                            let result = node.apply_operator(exec_state, ctx, left, right_value).await?;
                            last_result = Some(result);
                        }
                    }
                }
                State::FromRight { node, left } => {
                    let Some(right_value) = last_result.take() else {
                        return Err(Self::missing_result_error(&node));
                    };
                    let result = node.apply_operator(exec_state, ctx, left, right_value).await?;
                    last_result = Some(result);
                }
            }
        }

        last_result
            .map(KclValue::continue_)
            .ok_or_else(|| Self::missing_result_error(self))
    }

    async fn apply_operator(
        &self,
        exec_state: &mut ExecState,
        ctx: &ExecutorContext,
        left_value: KclValue,
        right_value: KclValue,
    ) -> Result<KclValue, KclError> {
        let mut meta = left_value.metadata();
        meta.extend(right_value.metadata());

        // First check if we are doing string concatenation.
        if self.operator == BinaryOperator::Add
            && let (KclValue::String { value: left, .. }, KclValue::String { value: right, .. }) =
                (&left_value, &right_value)
        {
            return Ok(KclValue::String {
                value: format!("{left}{right}"),
                meta,
            });
        }

        // Then check if we have solids.
        if self.operator == BinaryOperator::Add || self.operator == BinaryOperator::Or {
            if let (KclValue::Solid { value: left }, KclValue::Solid { value: right }) = (&left_value, &right_value) {
                let args = Args::new_no_args(
                    self.into(),
                    self.node_path.clone(),
                    ctx.clone(),
                    Some("union".to_owned()),
                );
                let result = crate::std::csg::inner_union(
                    vec![*left.clone(), *right.clone()],
                    Default::default(),
                    crate::std::csg::CsgAlgorithm::Latest,
                    exec_state,
                    args,
                )
                .await?;
                return Ok(result.into());
            }
        } else if self.operator == BinaryOperator::Sub {
            // Check if we have solids.
            if let (KclValue::Solid { value: left }, KclValue::Solid { value: right }) = (&left_value, &right_value) {
                let args = Args::new_no_args(
                    self.into(),
                    self.node_path.clone(),
                    ctx.clone(),
                    Some("subtract".to_owned()),
                );
                let result = crate::std::csg::inner_subtract(
                    vec![*left.clone()],
                    vec![*right.clone()],
                    Default::default(),
                    crate::std::csg::CsgAlgorithm::Latest,
                    exec_state,
                    args,
                )
                .await?;
                return Ok(result.into());
            }
        } else if self.operator == BinaryOperator::And
            && let (KclValue::Solid { value: left }, KclValue::Solid { value: right }) = (&left_value, &right_value)
        {
            // Check if we have solids.
            let args = Args::new_no_args(
                self.into(),
                self.node_path.clone(),
                ctx.clone(),
                Some("intersect".to_owned()),
            );
            let result = crate::std::csg::inner_intersect(
                vec![*left.clone(), *right.clone()],
                Default::default(),
                crate::std::csg::CsgAlgorithm::Latest,
                exec_state,
                args,
            )
            .await?;
            return Ok(result.into());
        }

        // Check if we are doing logical operations on booleans.
        if self.operator == BinaryOperator::Or || self.operator == BinaryOperator::And {
            let KclValue::Bool { value: left_value, .. } = left_value else {
                return Err(KclError::new_semantic(KclErrorDetails::new(
                    format!(
                        "Cannot apply logical operator to non-boolean value: {}",
                        left_value.human_friendly_type()
                    ),
                    vec![self.left.clone().into()],
                )));
            };
            let KclValue::Bool { value: right_value, .. } = right_value else {
                return Err(KclError::new_semantic(KclErrorDetails::new(
                    format!(
                        "Cannot apply logical operator to non-boolean value: {}",
                        right_value.human_friendly_type()
                    ),
                    vec![self.right.clone().into()],
                )));
            };
            let raw_value = match self.operator {
                BinaryOperator::Or => left_value || right_value,
                BinaryOperator::And => left_value && right_value,
                _ => unreachable!(),
            };
            return Ok(KclValue::Bool { value: raw_value, meta });
        }

        // Check if we're doing equivalence in sketch mode.
        if self.operator == BinaryOperator::Eq && exec_state.mod_local.sketch_block.is_some() {
            match (&left_value, &right_value) {
                // Same sketch variables.
                (KclValue::SketchVar { value: left_value, .. }, KclValue::SketchVar { value: right_value, .. })
                    if left_value.id == right_value.id =>
                {
                    return Ok(KclValue::none());
                }
                // Different sketch variables.
                (KclValue::SketchVar { value: var0 }, KclValue::SketchVar { value: var1, .. }) => {
                    let constraint = Constraint::ScalarEqual(
                        var0.id.to_constraint_id(self.as_source_range())?,
                        var1.id.to_constraint_id(self.as_source_range())?,
                    );
                    let Some(sketch_block_state) = &mut exec_state.mod_local.sketch_block else {
                        let message = "Being inside a sketch block should have already been checked above".to_owned();
                        debug_assert!(false, "{}", &message);
                        return Err(internal_err(message, self));
                    };
                    sketch_block_state.solver_constraints.push(constraint);
                    return Ok(KclValue::none());
                }
                // One sketch variable, one number.
                (KclValue::SketchVar { value: var, .. }, input_number @ KclValue::Number { .. })
                | (input_number @ KclValue::Number { .. }, KclValue::SketchVar { value: var, .. }) => {
                    let number_value = normalize_to_solver_distance_unit(
                        input_number,
                        input_number.into(),
                        exec_state,
                        "fixed constraint value",
                    )?;
                    let Some(n) = number_value.as_ty_f64() else {
                        let message = format!(
                            "Expected number after coercion, but found {}",
                            number_value.human_friendly_type()
                        );
                        debug_assert!(false, "{}", &message);
                        return Err(internal_err(message, self));
                    };
                    let constraint = Constraint::Fixed(var.id.to_constraint_id(self.as_source_range())?, n.n);
                    let Some(sketch_block_state) = &mut exec_state.mod_local.sketch_block else {
                        let message = "Being inside a sketch block should have already been checked above".to_owned();
                        debug_assert!(false, "{}", &message);
                        return Err(internal_err(message, self));
                    };
                    sketch_block_state.solver_constraints.push(constraint);
                    exec_state.warn_experimental("scalar fixed constraint", self.as_source_range());
                    return Ok(KclValue::none());
                }
                // One sketch constraint, one number.
                (KclValue::SketchConstraint { value: constraint }, input_number @ KclValue::Number { .. })
                | (input_number @ KclValue::Number { .. }, KclValue::SketchConstraint { value: constraint }) => {
                    let number_value = match constraint.kind {
                        // These constraint kinds expect the RHS to be an angle.
                        SketchConstraintKind::Angle { .. } => normalize_to_solver_angle_unit(
                            input_number,
                            input_number.into(),
                            exec_state,
                            "fixed constraint value",
                        )?,
                        // These constraint kinds expect the RHS to be a distance.
                        SketchConstraintKind::Distance { .. }
                        | SketchConstraintKind::PointLineDistance { .. }
                        | SketchConstraintKind::LineLineDistance { .. }
                        | SketchConstraintKind::PointCircularDistance { .. }
                        | SketchConstraintKind::LineCircularDistance { .. }
                        | SketchConstraintKind::CircularCircularDistance { .. }
                        | SketchConstraintKind::Radius { .. }
                        | SketchConstraintKind::Diameter { .. }
                        | SketchConstraintKind::HorizontalDistance { .. }
                        | SketchConstraintKind::VerticalDistance { .. } => normalize_to_solver_distance_unit(
                            input_number,
                            input_number.into(),
                            exec_state,
                            "fixed constraint value",
                        )?,
                    };
                    let Some(n) = number_value.as_ty_f64() else {
                        let message = format!(
                            "Expected number after coercion, but found {}",
                            number_value.human_friendly_type()
                        );
                        debug_assert!(false, "{}", &message);
                        return Err(internal_err(message, self));
                    };
                    // Recast the number side of == to get the source expression text.
                    let number_binary_part = if matches!(&left_value, KclValue::SketchConstraint { .. }) {
                        &self.right
                    } else {
                        &self.left
                    };
                    let source = {
                        use crate::unparser::ExprContext;
                        let mut buf = String::new();
                        number_binary_part.recast(&mut buf, &Default::default(), 0, ExprContext::Other);
                        crate::frontend::sketch::ConstraintSource {
                            expr: buf,
                            is_literal: matches!(number_binary_part, BinaryPart::Literal(_)),
                        }
                    };

                    match &constraint.kind {
                        SketchConstraintKind::Angle { line0, line1 } => {
                            let range = self.as_source_range();
                            // Line 0 is points A and B.
                            // Line 1 is points C and D.
                            let ax = line0.vars[0].x.to_constraint_id(range)?;
                            let ay = line0.vars[0].y.to_constraint_id(range)?;
                            let bx = line0.vars[1].x.to_constraint_id(range)?;
                            let by = line0.vars[1].y.to_constraint_id(range)?;
                            let cx = line1.vars[0].x.to_constraint_id(range)?;
                            let cy = line1.vars[0].y.to_constraint_id(range)?;
                            let dx = line1.vars[1].x.to_constraint_id(range)?;
                            let dy = line1.vars[1].y.to_constraint_id(range)?;
                            let solver_line0 = ezpz::datatypes::inputs::DatumLineSegment::new(
                                ezpz::datatypes::inputs::DatumPoint::new_xy(ax, ay),
                                ezpz::datatypes::inputs::DatumPoint::new_xy(bx, by),
                            );
                            let solver_line1 = ezpz::datatypes::inputs::DatumLineSegment::new(
                                ezpz::datatypes::inputs::DatumPoint::new_xy(cx, cy),
                                ezpz::datatypes::inputs::DatumPoint::new_xy(dx, dy),
                            );
                            let desired_angle = match n.ty {
                                NumericType::Known(crate::exec::UnitType::Angle(crate::exec::UnitAngle::Degrees))
                                | NumericType::Default {
                                    len: _,
                                    angle: UnitAngle::Degrees,
                                } => ezpz::datatypes::Angle::from_degrees(n.n),
                                NumericType::Known(crate::exec::UnitType::Angle(crate::exec::UnitAngle::Radians))
                                | NumericType::Default {
                                    len: _,
                                    angle: UnitAngle::Radians,
                                } => ezpz::datatypes::Angle::from_radians(n.n),
                                NumericType::Known(crate::exec::UnitType::Count)
                                | NumericType::Known(crate::exec::UnitType::GenericLength)
                                | NumericType::Known(crate::exec::UnitType::GenericAngle)
                                | NumericType::Known(crate::exec::UnitType::Length(_))
                                | NumericType::Unknown
                                | NumericType::Any => {
                                    let message = format!("Expected angle but found {:?}", n);
                                    debug_assert!(false, "{}", &message);
                                    return Err(internal_err(message, self));
                                }
                            };
                            let solver_constraint = Constraint::LinesAtAngle(
                                solver_line0,
                                solver_line1,
                                ezpz::datatypes::AngleKind::Other(desired_angle),
                            );
                            let constraint_id = exec_state.next_object_id();
                            let Some(sketch_block_state) = &mut exec_state.mod_local.sketch_block else {
                                let message =
                                    "Being inside a sketch block should have already been checked above".to_owned();
                                debug_assert!(false, "{}", &message);
                                return Err(internal_err(message, self));
                            };
                            sketch_block_state.solver_constraints.push(solver_constraint);
                            use crate::execution::Artifact;
                            use crate::execution::CodeRef;
                            use crate::execution::SketchBlockConstraint;
                            use crate::execution::SketchBlockConstraintType;
                            use crate::front::Angle;
                            use crate::front::SourceRef;

                            let Some(sketch_id) = sketch_block_state.sketch_id else {
                                let message = "Sketch id missing for constraint artifact".to_owned();
                                debug_assert!(false, "{}", &message);
                                return Err(KclError::new_internal(KclErrorDetails::new(message, vec![range])));
                            };
                            let sketch_constraint = crate::front::Constraint::Angle(Angle {
                                lines: vec![line0.object_id, line1.object_id],
                                angle: n.try_into().map_err(|_| {
                                    internal_err("Failed to convert angle units numeric suffix:", range)
                                })?,
                                source,
                            });
                            sketch_block_state.sketch_constraints.push(constraint_id);
                            let artifact_id = exec_state.next_artifact_id();
                            exec_state.add_artifact(Artifact::SketchBlockConstraint(SketchBlockConstraint {
                                id: artifact_id,
                                sketch_id,
                                constraint_id,
                                constraint_type: SketchBlockConstraintType::from(&sketch_constraint),
                                code_ref: CodeRef::placeholder(range),
                            }));
                            exec_state.add_scene_object(
                                Object {
                                    id: constraint_id,
                                    kind: ObjectKind::Constraint {
                                        constraint: sketch_constraint,
                                    },
                                    label: Default::default(),
                                    comments: Default::default(),
                                    artifact_id,
                                    source: SourceRef::new(range, self.node_path.clone()),
                                },
                                range,
                            );
                        }
                        SketchConstraintKind::Distance { points, label_position } => {
                            let range = self.as_source_range();
                            let p0 = &points[0];
                            let p1 = &points[1];
                            let sketch_var_ty = solver_numeric_type(exec_state);
                            let constraint_id = exec_state.next_object_id();
                            let Some(sketch_block_state) = &mut exec_state.mod_local.sketch_block else {
                                let message =
                                    "Being inside a sketch block should have already been checked above".to_owned();
                                debug_assert!(false, "{}", &message);
                                return Err(internal_err(message, self));
                            };
                            match (p0, p1) {
                                (
                                    crate::execution::ConstrainablePoint2dOrOrigin::Point(p0),
                                    crate::execution::ConstrainablePoint2dOrOrigin::Point(p1),
                                ) => {
                                    let solver_pt0 = ezpz::datatypes::inputs::DatumPoint::new_xy(
                                        p0.vars.x.to_constraint_id(range)?,
                                        p0.vars.y.to_constraint_id(range)?,
                                    );
                                    let solver_pt1 = ezpz::datatypes::inputs::DatumPoint::new_xy(
                                        p1.vars.x.to_constraint_id(range)?,
                                        p1.vars.y.to_constraint_id(range)?,
                                    );
                                    sketch_block_state
                                        .solver_constraints
                                        .push(Constraint::Distance(solver_pt0, solver_pt1, n.n));
                                }
                                (
                                    crate::execution::ConstrainablePoint2dOrOrigin::Point(point),
                                    crate::execution::ConstrainablePoint2dOrOrigin::Origin,
                                )
                                | (
                                    crate::execution::ConstrainablePoint2dOrOrigin::Origin,
                                    crate::execution::ConstrainablePoint2dOrOrigin::Point(point),
                                ) => {
                                    let origin_x_id = sketch_block_state.next_sketch_var_id();
                                    sketch_block_state.sketch_vars.push(KclValue::SketchVar {
                                        value: Box::new(crate::execution::SketchVar {
                                            id: origin_x_id,
                                            initial_value: 0.0,
                                            ty: sketch_var_ty,
                                            // Synthesized origin coord for distance(); not source-backed.
                                            node_path: None,
                                            meta: vec![],
                                        }),
                                    });
                                    let origin_y_id = sketch_block_state.next_sketch_var_id();
                                    sketch_block_state.sketch_vars.push(KclValue::SketchVar {
                                        value: Box::new(crate::execution::SketchVar {
                                            id: origin_y_id,
                                            initial_value: 0.0,
                                            ty: sketch_var_ty,
                                            // Synthesized origin coord for distance(); not source-backed.
                                            node_path: None,
                                            meta: vec![],
                                        }),
                                    });
                                    let origin_x = origin_x_id.to_constraint_id(range)?;
                                    let origin_y = origin_y_id.to_constraint_id(range)?;
                                    sketch_block_state
                                        .solver_constraints
                                        .push(Constraint::Fixed(origin_x, 0.0));
                                    sketch_block_state
                                        .solver_constraints
                                        .push(Constraint::Fixed(origin_y, 0.0));
                                    let solver_point = ezpz::datatypes::inputs::DatumPoint::new_xy(
                                        point.vars.x.to_constraint_id(range)?,
                                        point.vars.y.to_constraint_id(range)?,
                                    );
                                    let origin_point = ezpz::datatypes::inputs::DatumPoint::new_xy(origin_x, origin_y);
                                    sketch_block_state.solver_constraints.push(Constraint::Distance(
                                        solver_point,
                                        origin_point,
                                        n.n,
                                    ));
                                }
                                (
                                    crate::execution::ConstrainablePoint2dOrOrigin::Origin,
                                    crate::execution::ConstrainablePoint2dOrOrigin::Origin,
                                ) => {
                                    return Err(internal_err(
                                        "distance() cannot constrain ORIGIN against ORIGIN".to_owned(),
                                        range,
                                    ));
                                }
                            }
                            use crate::execution::Artifact;
                            use crate::execution::CodeRef;
                            use crate::execution::SketchBlockConstraint;
                            use crate::execution::SketchBlockConstraintType;
                            use crate::front::Distance;
                            use crate::front::SourceRef;
                            use crate::frontend::sketch::ConstraintSegment;

                            let Some(sketch_id) = sketch_block_state.sketch_id else {
                                let message = "Sketch id missing for constraint artifact".to_owned();
                                debug_assert!(false, "{}", &message);
                                return Err(KclError::new_internal(KclErrorDetails::new(message, vec![range])));
                            };
                            let sketch_constraint = crate::front::Constraint::Distance(Distance {
                                points: vec![
                                    match p0 {
                                        crate::execution::ConstrainablePoint2dOrOrigin::Point(point) => {
                                            ConstraintSegment::from(point.object_id)
                                        }
                                        crate::execution::ConstrainablePoint2dOrOrigin::Origin => {
                                            ConstraintSegment::ORIGIN
                                        }
                                    },
                                    match p1 {
                                        crate::execution::ConstrainablePoint2dOrOrigin::Point(point) => {
                                            ConstraintSegment::from(point.object_id)
                                        }
                                        crate::execution::ConstrainablePoint2dOrOrigin::Origin => {
                                            ConstraintSegment::ORIGIN
                                        }
                                    },
                                ],
                                distance: n.try_into().map_err(|_| {
                                    internal_err("Failed to convert distance units numeric suffix:", range)
                                })?,
                                label_position: label_position.clone(),
                                source,
                            });
                            sketch_block_state.sketch_constraints.push(constraint_id);
                            let artifact_id = exec_state.next_artifact_id();
                            exec_state.add_artifact(Artifact::SketchBlockConstraint(SketchBlockConstraint {
                                id: artifact_id,
                                sketch_id,
                                constraint_id,
                                constraint_type: SketchBlockConstraintType::from(&sketch_constraint),
                                code_ref: CodeRef::placeholder(range),
                            }));
                            exec_state.add_scene_object(
                                Object {
                                    id: constraint_id,
                                    kind: ObjectKind::Constraint {
                                        constraint: sketch_constraint,
                                    },
                                    label: Default::default(),
                                    comments: Default::default(),
                                    artifact_id,
                                    source: SourceRef::new(range, self.node_path.clone()),
                                },
                                range,
                            );
                        }
                        SketchConstraintKind::PointLineDistance {
                            point,
                            line,
                            input_object_ids,
                            label_position,
                        } => {
                            let range = self.as_source_range();
                            let sketch_var_ty = solver_numeric_type(exec_state);
                            let sketch_vars = exec_state
                                .mod_local
                                .sketch_block
                                .as_ref()
                                .ok_or_else(|| {
                                    internal_err(
                                        "Being inside a sketch block should have already been checked above",
                                        self,
                                    )
                                })?
                                .sketch_vars
                                .clone();
                            let support_initial =
                                projected_point_on_line_initial_position(&sketch_vars, point, line, exec_state, range)?;
                            let solver_line = datum_line_from_constrainable(line, range)?;

                            let constraint_id = exec_state.next_object_id();
                            let Some(sketch_block_state) = &mut exec_state.mod_local.sketch_block else {
                                let message =
                                    "Being inside a sketch block should have already been checked above".to_owned();
                                debug_assert!(false, "{}", &message);
                                return Err(internal_err(message, self));
                            };

                            // Lower point-line distance by adding a hidden
                            // support point on the line, then constrain the
                            // selected point-to-support segment to be
                            // perpendicular and equal to the requested
                            // distance.
                            let solver_point = datum_point_from_constrainable_or_origin(
                                sketch_block_state,
                                sketch_var_ty,
                                point,
                                range,
                            )?;
                            let support_x_id = sketch_block_state.next_sketch_var_id();
                            sketch_block_state.sketch_vars.push(KclValue::SketchVar {
                                value: Box::new(crate::execution::SketchVar {
                                    id: support_x_id,
                                    initial_value: support_initial[0],
                                    ty: sketch_var_ty,
                                    // Synthesized support point coord for distance lowering; not source-backed.
                                    node_path: None,
                                    meta: vec![],
                                }),
                            });
                            let support_y_id = sketch_block_state.next_sketch_var_id();
                            sketch_block_state.sketch_vars.push(KclValue::SketchVar {
                                value: Box::new(crate::execution::SketchVar {
                                    id: support_y_id,
                                    initial_value: support_initial[1],
                                    ty: sketch_var_ty,
                                    // Synthesized support point coord for distance lowering; not source-backed.
                                    node_path: None,
                                    meta: vec![],
                                }),
                            });
                            let support_point = ezpz::datatypes::inputs::DatumPoint::new_xy(
                                support_x_id.to_constraint_id(range)?,
                                support_y_id.to_constraint_id(range)?,
                            );
                            let support_line =
                                ezpz::datatypes::inputs::DatumLineSegment::new(solver_point, support_point);

                            sketch_block_state
                                .solver_constraints
                                .push(Constraint::PointLineDistance(support_point, solver_line, 0.0));
                            sketch_block_state.solver_constraints.push(Constraint::LinesAtAngle(
                                support_line,
                                solver_line,
                                ezpz::datatypes::AngleKind::Perpendicular,
                            ));
                            sketch_block_state.solver_constraints.push(Constraint::Distance(
                                solver_point,
                                support_point,
                                n.n,
                            ));

                            use crate::execution::Artifact;
                            use crate::execution::CodeRef;
                            use crate::execution::SketchBlockConstraint;
                            use crate::execution::SketchBlockConstraintType;
                            use crate::front::Distance;
                            use crate::front::SourceRef;
                            use crate::frontend::sketch::ConstraintSegment;

                            let Some(sketch_id) = sketch_block_state.sketch_id else {
                                let message = "Sketch id missing for constraint artifact".to_owned();
                                debug_assert!(false, "{}", &message);
                                return Err(KclError::new_internal(KclErrorDetails::new(message, vec![range])));
                            };
                            let sketch_constraint = crate::front::Constraint::Distance(Distance {
                                points: input_object_ids
                                    .iter()
                                    .copied()
                                    .map(|id| id.map_or(ConstraintSegment::ORIGIN, ConstraintSegment::from))
                                    .collect(),
                                distance: n.try_into().map_err(|_| {
                                    internal_err("Failed to convert distance units numeric suffix:", range)
                                })?,
                                label_position: label_position.clone(),
                                source,
                            });
                            sketch_block_state.sketch_constraints.push(constraint_id);
                            let artifact_id = exec_state.next_artifact_id();
                            exec_state.add_artifact(Artifact::SketchBlockConstraint(SketchBlockConstraint {
                                id: artifact_id,
                                sketch_id,
                                constraint_id,
                                constraint_type: SketchBlockConstraintType::from(&sketch_constraint),
                                code_ref: CodeRef::placeholder(range),
                            }));
                            exec_state.add_scene_object(
                                Object {
                                    id: constraint_id,
                                    kind: ObjectKind::Constraint {
                                        constraint: sketch_constraint,
                                    },
                                    label: Default::default(),
                                    comments: Default::default(),
                                    artifact_id,
                                    source: SourceRef::new(range, self.node_path.clone()),
                                },
                                range,
                            );
                        }
                        SketchConstraintKind::LineLineDistance {
                            line0,
                            line1,
                            input_object_ids,
                            label_position,
                        } => {
                            let range = self.as_source_range();
                            let reference_point = crate::execution::ConstrainablePoint2d {
                                vars: line0.vars[0].clone(),
                                object_id: line0.object_id,
                            };
                            let sketch_var_ty = solver_numeric_type(exec_state);
                            let sketch_vars = exec_state
                                .mod_local
                                .sketch_block
                                .as_ref()
                                .ok_or_else(|| {
                                    internal_err(
                                        "Being inside a sketch block should have already been checked above",
                                        self,
                                    )
                                })?
                                .sketch_vars
                                .clone();
                            let support_initial = projected_point_on_line_initial_position(
                                &sketch_vars,
                                &crate::execution::ConstrainablePoint2dOrOrigin::Point(reference_point.clone()),
                                line1,
                                exec_state,
                                range,
                            )?;
                            let solver_point = datum_point_from_constrainable(&reference_point, range)?;
                            let solver_line0 = datum_line_from_constrainable(line0, range)?;
                            let solver_line1 = datum_line_from_constrainable(line1, range)?;

                            let constraint_id = exec_state.next_object_id();
                            let Some(sketch_block_state) = &mut exec_state.mod_local.sketch_block else {
                                let message =
                                    "Being inside a sketch block should have already been checked above".to_owned();
                                debug_assert!(false, "{}", &message);
                                return Err(internal_err(message, self));
                            };

                            // Lower line-line distance to the point-line
                            // construction above by choosing one endpoint on
                            // line0 as the reference point, forcing the lines
                            // parallel, and measuring perpendicularly to
                            // line1.
                            let support_x_id = sketch_block_state.next_sketch_var_id();
                            sketch_block_state.sketch_vars.push(KclValue::SketchVar {
                                value: Box::new(crate::execution::SketchVar {
                                    id: support_x_id,
                                    initial_value: support_initial[0],
                                    ty: sketch_var_ty,
                                    // Synthesized support point coord for distance lowering; not source-backed.
                                    node_path: None,
                                    meta: vec![],
                                }),
                            });
                            let support_y_id = sketch_block_state.next_sketch_var_id();
                            sketch_block_state.sketch_vars.push(KclValue::SketchVar {
                                value: Box::new(crate::execution::SketchVar {
                                    id: support_y_id,
                                    initial_value: support_initial[1],
                                    ty: sketch_var_ty,
                                    // Synthesized support point coord for distance lowering; not source-backed.
                                    node_path: None,
                                    meta: vec![],
                                }),
                            });
                            let support_point = ezpz::datatypes::inputs::DatumPoint::new_xy(
                                support_x_id.to_constraint_id(range)?,
                                support_y_id.to_constraint_id(range)?,
                            );
                            let support_line =
                                ezpz::datatypes::inputs::DatumLineSegment::new(solver_point, support_point);

                            sketch_block_state.solver_constraints.push(Constraint::LinesAtAngle(
                                solver_line0,
                                solver_line1,
                                ezpz::datatypes::AngleKind::Parallel,
                            ));
                            sketch_block_state
                                .solver_constraints
                                .push(Constraint::PointLineDistance(support_point, solver_line1, 0.0));
                            sketch_block_state.solver_constraints.push(Constraint::LinesAtAngle(
                                support_line,
                                solver_line1,
                                ezpz::datatypes::AngleKind::Perpendicular,
                            ));
                            sketch_block_state.solver_constraints.push(Constraint::Distance(
                                solver_point,
                                support_point,
                                n.n,
                            ));

                            use crate::execution::Artifact;
                            use crate::execution::CodeRef;
                            use crate::execution::SketchBlockConstraint;
                            use crate::execution::SketchBlockConstraintType;
                            use crate::front::Distance;
                            use crate::front::SourceRef;
                            use crate::frontend::sketch::ConstraintSegment;

                            let Some(sketch_id) = sketch_block_state.sketch_id else {
                                let message = "Sketch id missing for constraint artifact".to_owned();
                                debug_assert!(false, "{}", &message);
                                return Err(KclError::new_internal(KclErrorDetails::new(message, vec![range])));
                            };
                            let sketch_constraint = crate::front::Constraint::Distance(Distance {
                                points: input_object_ids.iter().copied().map(ConstraintSegment::from).collect(),
                                distance: n.try_into().map_err(|_| {
                                    internal_err("Failed to convert distance units numeric suffix:", range)
                                })?,
                                label_position: label_position.clone(),
                                source,
                            });
                            sketch_block_state.sketch_constraints.push(constraint_id);
                            let artifact_id = exec_state.next_artifact_id();
                            exec_state.add_artifact(Artifact::SketchBlockConstraint(SketchBlockConstraint {
                                id: artifact_id,
                                sketch_id,
                                constraint_id,
                                constraint_type: SketchBlockConstraintType::from(&sketch_constraint),
                                code_ref: CodeRef::placeholder(range),
                            }));
                            exec_state.add_scene_object(
                                Object {
                                    id: constraint_id,
                                    kind: ObjectKind::Constraint {
                                        constraint: sketch_constraint,
                                    },
                                    label: Default::default(),
                                    comments: Default::default(),
                                    artifact_id,
                                    source: SourceRef::new(range, self.node_path.clone()),
                                },
                                range,
                            );
                        }
                        SketchConstraintKind::PointCircularDistance {
                            point,
                            center,
                            start,
                            end,
                            input_object_ids,
                            label_position,
                        } => {
                            let range = self.as_source_range();
                            let sketch_var_ty = solver_numeric_type(exec_state);
                            let sketch_vars = exec_state
                                .mod_local
                                .sketch_block
                                .as_ref()
                                .ok_or_else(|| {
                                    internal_err(
                                        "Being inside a sketch block should have already been checked above",
                                        self,
                                    )
                                })?
                                .sketch_vars
                                .clone();
                            let circular =
                                circular_distance_datums(&sketch_vars, center, start, end.as_ref(), exec_state, range)?;

                            let constraint_id = exec_state.next_object_id();
                            let Some(sketch_block_state) = &mut exec_state.mod_local.sketch_block else {
                                let message =
                                    "Being inside a sketch block should have already been checked above".to_owned();
                                debug_assert!(false, "{}", &message);
                                return Err(internal_err(message, self));
                            };

                            // Lower point-circular distance to exterior
                            // circle tangency: a hidden circle centered on the
                            // point has radius equal to the requested distance
                            // and is tangent to the target arc/circle.
                            let target_point = datum_point_from_constrainable_or_origin(
                                sketch_block_state,
                                sketch_var_ty,
                                point,
                                range,
                            )?;
                            push_circular_distance_constraints(
                                sketch_block_state,
                                sketch_var_ty,
                                target_point,
                                circular,
                                n.n,
                                range,
                            )?;

                            use crate::execution::Artifact;
                            use crate::execution::CodeRef;
                            use crate::execution::SketchBlockConstraint;
                            use crate::execution::SketchBlockConstraintType;
                            use crate::front::Distance;
                            use crate::front::SourceRef;
                            use crate::frontend::sketch::ConstraintSegment;

                            let Some(sketch_id) = sketch_block_state.sketch_id else {
                                let message = "Sketch id missing for constraint artifact".to_owned();
                                debug_assert!(false, "{}", &message);
                                return Err(KclError::new_internal(KclErrorDetails::new(message, vec![range])));
                            };
                            let sketch_constraint = crate::front::Constraint::Distance(Distance {
                                points: input_object_ids
                                    .iter()
                                    .copied()
                                    .map(|id| id.map_or(ConstraintSegment::ORIGIN, ConstraintSegment::from))
                                    .collect(),
                                distance: n.try_into().map_err(|_| {
                                    internal_err("Failed to convert distance units numeric suffix:", range)
                                })?,
                                label_position: label_position.clone(),
                                source,
                            });
                            sketch_block_state.sketch_constraints.push(constraint_id);
                            let artifact_id = exec_state.next_artifact_id();
                            exec_state.add_artifact(Artifact::SketchBlockConstraint(SketchBlockConstraint {
                                id: artifact_id,
                                sketch_id,
                                constraint_id,
                                constraint_type: SketchBlockConstraintType::from(&sketch_constraint),
                                code_ref: CodeRef::placeholder(range),
                            }));
                            exec_state.add_scene_object(
                                Object {
                                    id: constraint_id,
                                    kind: ObjectKind::Constraint {
                                        constraint: sketch_constraint,
                                    },
                                    label: Default::default(),
                                    comments: Default::default(),
                                    artifact_id,
                                    source: SourceRef::new(range, self.node_path.clone()),
                                },
                                range,
                            );
                        }
                        SketchConstraintKind::LineCircularDistance {
                            line,
                            center,
                            start,
                            end,
                            input_object_ids,
                            label_position,
                        } => {
                            let range = self.as_source_range();
                            let sketch_var_ty = solver_numeric_type(exec_state);
                            let sketch_vars = exec_state
                                .mod_local
                                .sketch_block
                                .as_ref()
                                .ok_or_else(|| {
                                    internal_err(
                                        "Being inside a sketch block should have already been checked above",
                                        self,
                                    )
                                })?
                                .sketch_vars
                                .clone();
                            let support_initial = projected_point_on_line_initial_position(
                                &sketch_vars,
                                &crate::execution::ConstrainablePoint2dOrOrigin::Point(center.clone()),
                                line,
                                exec_state,
                                range,
                            )?;
                            let solver_line = datum_line_from_constrainable(line, range)?;
                            let circular =
                                circular_distance_datums(&sketch_vars, center, start, end.as_ref(), exec_state, range)?;

                            let constraint_id = exec_state.next_object_id();
                            let Some(sketch_block_state) = &mut exec_state.mod_local.sketch_block else {
                                let message =
                                    "Being inside a sketch block should have already been checked above".to_owned();
                                debug_assert!(false, "{}", &message);
                                return Err(internal_err(message, self));
                            };

                            // Lower line-circular distance by first projecting
                            // the circular center onto the target line with a
                            // hidden support point. The circular distance is
                            // then the point-circular construction from that
                            // support point.
                            let support_x_id = sketch_block_state.next_sketch_var_id();
                            sketch_block_state.sketch_vars.push(KclValue::SketchVar {
                                value: Box::new(crate::execution::SketchVar {
                                    id: support_x_id,
                                    initial_value: support_initial[0],
                                    ty: sketch_var_ty,
                                    // Synthesized support point coord for distance lowering; not source-backed.
                                    node_path: None,
                                    meta: vec![],
                                }),
                            });
                            let support_y_id = sketch_block_state.next_sketch_var_id();
                            sketch_block_state.sketch_vars.push(KclValue::SketchVar {
                                value: Box::new(crate::execution::SketchVar {
                                    id: support_y_id,
                                    initial_value: support_initial[1],
                                    ty: sketch_var_ty,
                                    // Synthesized support point coord for distance lowering; not source-backed.
                                    node_path: None,
                                    meta: vec![],
                                }),
                            });
                            let support_point = ezpz::datatypes::inputs::DatumPoint::new_xy(
                                support_x_id.to_constraint_id(range)?,
                                support_y_id.to_constraint_id(range)?,
                            );
                            let support_line =
                                ezpz::datatypes::inputs::DatumLineSegment::new(circular.center, support_point);

                            sketch_block_state
                                .solver_constraints
                                .push(Constraint::PointLineDistance(support_point, solver_line, 0.0));
                            sketch_block_state.solver_constraints.push(Constraint::LinesAtAngle(
                                support_line,
                                solver_line,
                                ezpz::datatypes::AngleKind::Perpendicular,
                            ));
                            push_circular_distance_constraints(
                                sketch_block_state,
                                sketch_var_ty,
                                support_point,
                                circular,
                                n.n,
                                range,
                            )?;

                            use crate::execution::Artifact;
                            use crate::execution::CodeRef;
                            use crate::execution::SketchBlockConstraint;
                            use crate::execution::SketchBlockConstraintType;
                            use crate::front::Distance;
                            use crate::front::SourceRef;
                            use crate::frontend::sketch::ConstraintSegment;

                            let Some(sketch_id) = sketch_block_state.sketch_id else {
                                let message = "Sketch id missing for constraint artifact".to_owned();
                                debug_assert!(false, "{}", &message);
                                return Err(KclError::new_internal(KclErrorDetails::new(message, vec![range])));
                            };
                            let sketch_constraint = crate::front::Constraint::Distance(Distance {
                                points: input_object_ids.iter().copied().map(ConstraintSegment::from).collect(),
                                distance: n.try_into().map_err(|_| {
                                    internal_err("Failed to convert distance units numeric suffix:", range)
                                })?,
                                label_position: label_position.clone(),
                                source,
                            });
                            sketch_block_state.sketch_constraints.push(constraint_id);
                            let artifact_id = exec_state.next_artifact_id();
                            exec_state.add_artifact(Artifact::SketchBlockConstraint(SketchBlockConstraint {
                                id: artifact_id,
                                sketch_id,
                                constraint_id,
                                constraint_type: SketchBlockConstraintType::from(&sketch_constraint),
                                code_ref: CodeRef::placeholder(range),
                            }));
                            exec_state.add_scene_object(
                                Object {
                                    id: constraint_id,
                                    kind: ObjectKind::Constraint {
                                        constraint: sketch_constraint,
                                    },
                                    label: Default::default(),
                                    comments: Default::default(),
                                    artifact_id,
                                    source: SourceRef::new(range, self.node_path.clone()),
                                },
                                range,
                            );
                        }
                        SketchConstraintKind::CircularCircularDistance {
                            center0,
                            start0,
                            end0,
                            center1,
                            start1,
                            end1,
                            input_object_ids,
                            label_position,
                        } => {
                            let range = self.as_source_range();
                            let sketch_var_ty = solver_numeric_type(exec_state);
                            let sketch_vars = exec_state
                                .mod_local
                                .sketch_block
                                .as_ref()
                                .ok_or_else(|| {
                                    internal_err(
                                        "Being inside a sketch block should have already been checked above",
                                        self,
                                    )
                                })?
                                .sketch_vars
                                .clone();
                            let circular0 = circular_distance_datums(
                                &sketch_vars,
                                center0,
                                start0,
                                end0.as_ref(),
                                exec_state,
                                range,
                            )?;
                            let circular1 = circular_distance_datums(
                                &sketch_vars,
                                center1,
                                start1,
                                end1.as_ref(),
                                exec_state,
                                range,
                            )?;
                            let support_initial = circular_circular_support_initial_position(
                                &sketch_vars,
                                center0,
                                center1,
                                circular0.radius_initial_value,
                                n.n,
                                exec_state,
                                range,
                            )?;

                            let constraint_id = exec_state.next_object_id();
                            let Some(sketch_block_state) = &mut exec_state.mod_local.sketch_block else {
                                let message =
                                    "Being inside a sketch block should have already been checked above".to_owned();
                                debug_assert!(false, "{}", &message);
                                return Err(internal_err(message, self));
                            };

                            // Lower circular-circular distance with a hidden
                            // spacer circle of radius d/2. Constraining its
                            // center onto the line between target centers and
                            // making it exterior-tangent to both targets gives
                            // center distance r0 + d + r1.
                            let circular_target0 =
                                push_circular_radius_constraints(sketch_block_state, sketch_var_ty, circular0, range)?;
                            let circular_target1 =
                                push_circular_radius_constraints(sketch_block_state, sketch_var_ty, circular1, range)?;

                            let support_x_id = sketch_block_state.next_sketch_var_id();
                            sketch_block_state.sketch_vars.push(KclValue::SketchVar {
                                value: Box::new(crate::execution::SketchVar {
                                    id: support_x_id,
                                    initial_value: support_initial[0],
                                    ty: sketch_var_ty,
                                    // Synthesized support point coord for distance lowering; not source-backed.
                                    node_path: None,
                                    meta: vec![],
                                }),
                            });
                            let support_y_id = sketch_block_state.next_sketch_var_id();
                            sketch_block_state.sketch_vars.push(KclValue::SketchVar {
                                value: Box::new(crate::execution::SketchVar {
                                    id: support_y_id,
                                    initial_value: support_initial[1],
                                    ty: sketch_var_ty,
                                    // Synthesized support point coord for distance lowering; not source-backed.
                                    node_path: None,
                                    meta: vec![],
                                }),
                            });
                            let support_point = ezpz::datatypes::inputs::DatumPoint::new_xy(
                                support_x_id.to_constraint_id(range)?,
                                support_y_id.to_constraint_id(range)?,
                            );

                            let support_radius_id = sketch_block_state.next_sketch_var_id();
                            let support_radius_value = n.n / 2.0;
                            sketch_block_state.sketch_vars.push(KclValue::SketchVar {
                                value: Box::new(crate::execution::SketchVar {
                                    id: support_radius_id,
                                    initial_value: support_radius_value,
                                    ty: sketch_var_ty,
                                    // Synthesized hidden support radius for circular-circular distance; not source-backed.
                                    node_path: None,
                                    meta: vec![],
                                }),
                            });
                            let support_radius =
                                ezpz::datatypes::inputs::DatumDistance::new(support_radius_id.to_constraint_id(range)?);
                            let support_circle = ezpz::datatypes::inputs::DatumCircle {
                                center: support_point,
                                radius: support_radius,
                            };
                            let center_line = ezpz::datatypes::inputs::DatumLineSegment::new(
                                circular_target0.center,
                                circular_target1.center,
                            );

                            sketch_block_state
                                .solver_constraints
                                .push(Constraint::Fixed(support_radius.id, support_radius_value));
                            sketch_block_state
                                .solver_constraints
                                .push(Constraint::PointLineDistance(support_point, center_line, 0.0));
                            sketch_block_state
                                .solver_constraints
                                .push(Constraint::CircleTangentToCircle(
                                    circular_target0,
                                    support_circle,
                                    ezpz::CircleSide::Exterior,
                                ));
                            sketch_block_state
                                .solver_constraints
                                .push(Constraint::CircleTangentToCircle(
                                    support_circle,
                                    circular_target1,
                                    ezpz::CircleSide::Exterior,
                                ));

                            use crate::execution::Artifact;
                            use crate::execution::CodeRef;
                            use crate::execution::SketchBlockConstraint;
                            use crate::execution::SketchBlockConstraintType;
                            use crate::front::Distance;
                            use crate::front::SourceRef;
                            use crate::frontend::sketch::ConstraintSegment;

                            let Some(sketch_id) = sketch_block_state.sketch_id else {
                                let message = "Sketch id missing for constraint artifact".to_owned();
                                debug_assert!(false, "{}", &message);
                                return Err(KclError::new_internal(KclErrorDetails::new(message, vec![range])));
                            };
                            let sketch_constraint = crate::front::Constraint::Distance(Distance {
                                points: input_object_ids.iter().copied().map(ConstraintSegment::from).collect(),
                                distance: n.try_into().map_err(|_| {
                                    internal_err("Failed to convert distance units numeric suffix:", range)
                                })?,
                                label_position: label_position.clone(),
                                source,
                            });
                            sketch_block_state.sketch_constraints.push(constraint_id);
                            let artifact_id = exec_state.next_artifact_id();
                            exec_state.add_artifact(Artifact::SketchBlockConstraint(SketchBlockConstraint {
                                id: artifact_id,
                                sketch_id,
                                constraint_id,
                                constraint_type: SketchBlockConstraintType::from(&sketch_constraint),
                                code_ref: CodeRef::placeholder(range),
                            }));
                            exec_state.add_scene_object(
                                Object {
                                    id: constraint_id,
                                    kind: ObjectKind::Constraint {
                                        constraint: sketch_constraint,
                                    },
                                    label: Default::default(),
                                    comments: Default::default(),
                                    artifact_id,
                                    source: SourceRef::new(range, self.node_path.clone()),
                                },
                                range,
                            );
                        }
                        SketchConstraintKind::Radius { .. } | SketchConstraintKind::Diameter { .. } => {
                            #[derive(Clone, Copy)]
                            enum CircularSegmentConstraintTarget {
                                Arc {
                                    object_id: ObjectId,
                                    end: [crate::execution::SketchVarId; 2],
                                },
                                Circle {
                                    object_id: ObjectId,
                                },
                            }

                            fn sketch_var_initial_value(
                                sketch_vars: &[KclValue],
                                id: crate::execution::SketchVarId,
                                exec_state: &mut ExecState,
                                range: SourceRange,
                            ) -> Result<f64, KclError> {
                                sketch_vars
                                    .get(id.0)
                                    .and_then(KclValue::as_sketch_var)
                                    .map(|sketch_var| {
                                        sketch_var
                                            .initial_value_to_solver_units(
                                                exec_state,
                                                range,
                                                "circle radius initial value",
                                            )
                                            .map(|value| value.n)
                                    })
                                    .transpose()?
                                    .ok_or_else(|| {
                                        internal_err(
                                            format!("Missing sketch variable initial value for id {}", id.0),
                                            range,
                                        )
                                    })
                            }

                            let (points, label_position) = match &constraint.kind {
                                SketchConstraintKind::Radius { points, label_position } => {
                                    (points, label_position.clone())
                                }
                                SketchConstraintKind::Diameter { points, label_position } => {
                                    (points, label_position.clone())
                                }
                                _ => unreachable!(),
                            };
                            let range = self.as_source_range();
                            let center = &points[0];
                            let start = &points[1];
                            let Some(sketch_block_state) = &exec_state.mod_local.sketch_block else {
                                return Err(internal_err(
                                    "Being inside a sketch block should have already been checked above",
                                    self,
                                ));
                            };
                            let (constraint_name, is_diameter) = match &constraint.kind {
                                SketchConstraintKind::Radius { .. } => ("radius", false),
                                SketchConstraintKind::Diameter { .. } => ("diameter", true),
                                _ => unreachable!(),
                            };
                            let sketch_vars = sketch_block_state.sketch_vars.clone();
                            let target_segment = sketch_block_state
                                .needed_by_engine
                                .iter()
                                .find_map(|seg| match &seg.kind {
                                    UnsolvedSegmentKind::Arc {
                                        center_object_id,
                                        start_object_id,
                                        end,
                                        ..
                                    } if *center_object_id == center.object_id
                                        && *start_object_id == start.object_id =>
                                    {
                                        let (end_x_var, end_y_var) = match (&end[0], &end[1]) {
                                            (UnsolvedExpr::Unknown(end_x), UnsolvedExpr::Unknown(end_y)) => {
                                                (*end_x, *end_y)
                                            }
                                            _ => return None,
                                        };
                                        Some(CircularSegmentConstraintTarget::Arc {
                                            object_id: seg.object_id,
                                            end: [end_x_var, end_y_var],
                                        })
                                    }
                                    UnsolvedSegmentKind::Circle {
                                        center_object_id,
                                        start_object_id,
                                        ..
                                    } if *center_object_id == center.object_id
                                        && *start_object_id == start.object_id =>
                                    {
                                        Some(CircularSegmentConstraintTarget::Circle {
                                            object_id: seg.object_id,
                                        })
                                    }
                                    _ => None,
                                })
                                .ok_or_else(|| {
                                    internal_err(
                                        format!("Could not find circular segment for {} constraint", constraint_name),
                                        range,
                                    )
                                })?;
                            let radius_value = if is_diameter { n.n / 2.0 } else { n.n };
                            let center_point = ezpz::datatypes::inputs::DatumPoint::new_xy(
                                center.vars.x.to_constraint_id(range)?,
                                center.vars.y.to_constraint_id(range)?,
                            );
                            let start_point = ezpz::datatypes::inputs::DatumPoint::new_xy(
                                start.vars.x.to_constraint_id(range)?,
                                start.vars.y.to_constraint_id(range)?,
                            );
                            let solver_constraint = match target_segment {
                                CircularSegmentConstraintTarget::Arc { end, .. } => {
                                    let solver_arc = ezpz::datatypes::inputs::DatumCircularArc {
                                        center: center_point,
                                        start: start_point,
                                        end: ezpz::datatypes::inputs::DatumPoint::new_xy(
                                            end[0].to_constraint_id(range)?,
                                            end[1].to_constraint_id(range)?,
                                        ),
                                    };
                                    Constraint::ArcRadius(solver_arc, radius_value)
                                }
                                CircularSegmentConstraintTarget::Circle { .. } => {
                                    let sketch_var_ty = solver_numeric_type(exec_state);
                                    let start_x =
                                        sketch_var_initial_value(&sketch_vars, start.vars.x, exec_state, range)?;
                                    let start_y =
                                        sketch_var_initial_value(&sketch_vars, start.vars.y, exec_state, range)?;
                                    let center_x =
                                        sketch_var_initial_value(&sketch_vars, center.vars.x, exec_state, range)?;
                                    let center_y =
                                        sketch_var_initial_value(&sketch_vars, center.vars.y, exec_state, range)?;

                                    // Get the hypotenuse between the two points, the radius
                                    let radius_initial_value = libm::hypot(start_x - center_x, start_y - center_y);

                                    let Some(sketch_block_state) = &mut exec_state.mod_local.sketch_block else {
                                        let message =
                                            "Being inside a sketch block should have already been checked above"
                                                .to_owned();
                                        debug_assert!(false, "{}", &message);
                                        return Err(internal_err(message, self));
                                    };
                                    let radius_id = sketch_block_state.next_sketch_var_id();
                                    sketch_block_state.sketch_vars.push(KclValue::SketchVar {
                                        value: Box::new(crate::execution::SketchVar {
                                            id: radius_id,
                                            initial_value: radius_initial_value,
                                            ty: sketch_var_ty,
                                            // Synthesized hidden radius for circle constraint; not source-backed.
                                            node_path: None,
                                            meta: vec![],
                                        }),
                                    });
                                    let radius =
                                        ezpz::datatypes::inputs::DatumDistance::new(radius_id.to_constraint_id(range)?);
                                    let solver_circle = ezpz::datatypes::inputs::DatumCircle {
                                        center: center_point,
                                        radius,
                                    };
                                    sketch_block_state.solver_constraints.push(Constraint::DistanceVar(
                                        start_point,
                                        center_point,
                                        radius,
                                    ));
                                    Constraint::CircleRadius(solver_circle, radius_value)
                                }
                            };

                            let constraint_id = exec_state.next_object_id();
                            let Some(sketch_block_state) = &mut exec_state.mod_local.sketch_block else {
                                let message =
                                    "Being inside a sketch block should have already been checked above".to_owned();
                                debug_assert!(false, "{}", &message);
                                return Err(internal_err(message, self));
                            };
                            sketch_block_state.solver_constraints.push(solver_constraint);
                            use crate::execution::Artifact;
                            use crate::execution::CodeRef;
                            use crate::execution::SketchBlockConstraint;
                            use crate::execution::SketchBlockConstraintType;
                            use crate::front::SourceRef;
                            let segment_object_id = match target_segment {
                                CircularSegmentConstraintTarget::Arc { object_id, .. }
                                | CircularSegmentConstraintTarget::Circle { object_id } => object_id,
                            };

                            let constraint = if is_diameter {
                                use crate::frontend::sketch::Diameter;
                                crate::front::Constraint::Diameter(Diameter {
                                    arc: segment_object_id,
                                    diameter: n.try_into().map_err(|_| {
                                        internal_err("Failed to convert diameter units numeric suffix:", range)
                                    })?,
                                    label_position,
                                    source,
                                })
                            } else {
                                use crate::frontend::sketch::Radius;
                                crate::front::Constraint::Radius(Radius {
                                    arc: segment_object_id,
                                    radius: n.try_into().map_err(|_| {
                                        internal_err("Failed to convert radius units numeric suffix:", range)
                                    })?,
                                    label_position,
                                    source,
                                })
                            };
                            sketch_block_state.sketch_constraints.push(constraint_id);
                            let Some(sketch_id) = sketch_block_state.sketch_id else {
                                let message = "Sketch id missing for constraint artifact".to_owned();
                                debug_assert!(false, "{}", &message);
                                return Err(KclError::new_internal(KclErrorDetails::new(message, vec![range])));
                            };
                            let artifact_id = exec_state.next_artifact_id();
                            exec_state.add_artifact(Artifact::SketchBlockConstraint(SketchBlockConstraint {
                                id: artifact_id,
                                sketch_id,
                                constraint_id,
                                constraint_type: SketchBlockConstraintType::from(&constraint),
                                code_ref: CodeRef::placeholder(range),
                            }));
                            exec_state.add_scene_object(
                                Object {
                                    id: constraint_id,
                                    kind: ObjectKind::Constraint { constraint },
                                    label: Default::default(),
                                    comments: Default::default(),
                                    artifact_id,
                                    source: SourceRef::new(range, self.node_path.clone()),
                                },
                                range,
                            );
                        }
                        SketchConstraintKind::HorizontalDistance { points, label_position } => {
                            let range = self.as_source_range();
                            let p0 = &points[0];
                            let p1 = &points[1];
                            let constraint_id = exec_state.next_object_id();
                            let Some(sketch_block_state) = &mut exec_state.mod_local.sketch_block else {
                                let message =
                                    "Being inside a sketch block should have already been checked above".to_owned();
                                debug_assert!(false, "{}", &message);
                                return Err(internal_err(message, self));
                            };
                            match (p0, p1) {
                                (
                                    crate::execution::ConstrainablePoint2dOrOrigin::Point(p0),
                                    crate::execution::ConstrainablePoint2dOrOrigin::Point(p1),
                                ) => {
                                    let solver_pt0 = ezpz::datatypes::inputs::DatumPoint::new_xy(
                                        p0.vars.x.to_constraint_id(range)?,
                                        p0.vars.y.to_constraint_id(range)?,
                                    );
                                    let solver_pt1 = ezpz::datatypes::inputs::DatumPoint::new_xy(
                                        p1.vars.x.to_constraint_id(range)?,
                                        p1.vars.y.to_constraint_id(range)?,
                                    );
                                    sketch_block_state
                                        .solver_constraints
                                        .push(ezpz::Constraint::HorizontalDistance(solver_pt1, solver_pt0, n.n));
                                }
                                (
                                    crate::execution::ConstrainablePoint2dOrOrigin::Point(point),
                                    crate::execution::ConstrainablePoint2dOrOrigin::Origin,
                                ) => {
                                    // horizontalDistance([point, ORIGIN]) == n means 0 - point.x = n, so point.x = -n.
                                    sketch_block_state
                                        .solver_constraints
                                        .push(ezpz::Constraint::Fixed(point.vars.x.to_constraint_id(range)?, -n.n));
                                }
                                (
                                    crate::execution::ConstrainablePoint2dOrOrigin::Origin,
                                    crate::execution::ConstrainablePoint2dOrOrigin::Point(point),
                                ) => {
                                    // horizontalDistance([ORIGIN, point]) == n means point.x - 0 = n, so point.x = n.
                                    sketch_block_state
                                        .solver_constraints
                                        .push(ezpz::Constraint::Fixed(point.vars.x.to_constraint_id(range)?, n.n));
                                }
                                (
                                    crate::execution::ConstrainablePoint2dOrOrigin::Origin,
                                    crate::execution::ConstrainablePoint2dOrOrigin::Origin,
                                ) => {
                                    return Err(internal_err(
                                        "horizontalDistance() cannot constrain ORIGIN against ORIGIN".to_owned(),
                                        range,
                                    ));
                                }
                            }
                            use crate::execution::Artifact;
                            use crate::execution::CodeRef;
                            use crate::execution::SketchBlockConstraint;
                            use crate::execution::SketchBlockConstraintType;
                            use crate::front::Distance;
                            use crate::front::SourceRef;
                            use crate::frontend::sketch::ConstraintSegment;

                            let constraint = crate::front::Constraint::HorizontalDistance(Distance {
                                points: vec![
                                    match p0 {
                                        crate::execution::ConstrainablePoint2dOrOrigin::Point(point) => {
                                            ConstraintSegment::from(point.object_id)
                                        }
                                        crate::execution::ConstrainablePoint2dOrOrigin::Origin => {
                                            ConstraintSegment::ORIGIN
                                        }
                                    },
                                    match p1 {
                                        crate::execution::ConstrainablePoint2dOrOrigin::Point(point) => {
                                            ConstraintSegment::from(point.object_id)
                                        }
                                        crate::execution::ConstrainablePoint2dOrOrigin::Origin => {
                                            ConstraintSegment::ORIGIN
                                        }
                                    },
                                ],
                                distance: n.try_into().map_err(|_| {
                                    internal_err("Failed to convert distance units numeric suffix:", range)
                                })?,
                                label_position: label_position.clone(),
                                source,
                            });
                            sketch_block_state.sketch_constraints.push(constraint_id);
                            let Some(sketch_id) = sketch_block_state.sketch_id else {
                                let message = "Sketch id missing for constraint artifact".to_owned();
                                debug_assert!(false, "{}", &message);
                                return Err(KclError::new_internal(KclErrorDetails::new(message, vec![range])));
                            };
                            let artifact_id = exec_state.next_artifact_id();
                            exec_state.add_artifact(Artifact::SketchBlockConstraint(SketchBlockConstraint {
                                id: artifact_id,
                                sketch_id,
                                constraint_id,
                                constraint_type: SketchBlockConstraintType::from(&constraint),
                                code_ref: CodeRef::placeholder(range),
                            }));
                            exec_state.add_scene_object(
                                Object {
                                    id: constraint_id,
                                    kind: ObjectKind::Constraint { constraint },
                                    label: Default::default(),
                                    comments: Default::default(),
                                    artifact_id,
                                    source: SourceRef::new(range, self.node_path.clone()),
                                },
                                range,
                            );
                        }
                        SketchConstraintKind::VerticalDistance { points, label_position } => {
                            let range = self.as_source_range();
                            let p0 = &points[0];
                            let p1 = &points[1];
                            let constraint_id = exec_state.next_object_id();
                            let Some(sketch_block_state) = &mut exec_state.mod_local.sketch_block else {
                                let message =
                                    "Being inside a sketch block should have already been checked above".to_owned();
                                debug_assert!(false, "{}", &message);
                                return Err(internal_err(message, self));
                            };
                            match (p0, p1) {
                                (
                                    crate::execution::ConstrainablePoint2dOrOrigin::Point(p0),
                                    crate::execution::ConstrainablePoint2dOrOrigin::Point(p1),
                                ) => {
                                    let solver_pt0 = ezpz::datatypes::inputs::DatumPoint::new_xy(
                                        p0.vars.x.to_constraint_id(range)?,
                                        p0.vars.y.to_constraint_id(range)?,
                                    );
                                    let solver_pt1 = ezpz::datatypes::inputs::DatumPoint::new_xy(
                                        p1.vars.x.to_constraint_id(range)?,
                                        p1.vars.y.to_constraint_id(range)?,
                                    );
                                    sketch_block_state
                                        .solver_constraints
                                        .push(ezpz::Constraint::VerticalDistance(solver_pt1, solver_pt0, n.n));
                                }
                                (
                                    crate::execution::ConstrainablePoint2dOrOrigin::Point(point),
                                    crate::execution::ConstrainablePoint2dOrOrigin::Origin,
                                ) => {
                                    sketch_block_state
                                        .solver_constraints
                                        .push(ezpz::Constraint::Fixed(point.vars.y.to_constraint_id(range)?, -n.n));
                                }
                                (
                                    crate::execution::ConstrainablePoint2dOrOrigin::Origin,
                                    crate::execution::ConstrainablePoint2dOrOrigin::Point(point),
                                ) => {
                                    sketch_block_state
                                        .solver_constraints
                                        .push(ezpz::Constraint::Fixed(point.vars.y.to_constraint_id(range)?, n.n));
                                }
                                (
                                    crate::execution::ConstrainablePoint2dOrOrigin::Origin,
                                    crate::execution::ConstrainablePoint2dOrOrigin::Origin,
                                ) => {
                                    return Err(internal_err(
                                        "verticalDistance() cannot constrain ORIGIN against ORIGIN".to_owned(),
                                        range,
                                    ));
                                }
                            }
                            use crate::execution::Artifact;
                            use crate::execution::CodeRef;
                            use crate::execution::SketchBlockConstraint;
                            use crate::execution::SketchBlockConstraintType;
                            use crate::front::Distance;
                            use crate::front::SourceRef;
                            use crate::frontend::sketch::ConstraintSegment;

                            let constraint = crate::front::Constraint::VerticalDistance(Distance {
                                points: vec![
                                    match p0 {
                                        crate::execution::ConstrainablePoint2dOrOrigin::Point(point) => {
                                            ConstraintSegment::from(point.object_id)
                                        }
                                        crate::execution::ConstrainablePoint2dOrOrigin::Origin => {
                                            ConstraintSegment::ORIGIN
                                        }
                                    },
                                    match p1 {
                                        crate::execution::ConstrainablePoint2dOrOrigin::Point(point) => {
                                            ConstraintSegment::from(point.object_id)
                                        }
                                        crate::execution::ConstrainablePoint2dOrOrigin::Origin => {
                                            ConstraintSegment::ORIGIN
                                        }
                                    },
                                ],
                                distance: n.try_into().map_err(|_| {
                                    internal_err("Failed to convert distance units numeric suffix:", range)
                                })?,
                                label_position: label_position.clone(),
                                source,
                            });
                            sketch_block_state.sketch_constraints.push(constraint_id);
                            let Some(sketch_id) = sketch_block_state.sketch_id else {
                                let message = "Sketch id missing for constraint artifact".to_owned();
                                debug_assert!(false, "{}", &message);
                                return Err(KclError::new_internal(KclErrorDetails::new(message, vec![range])));
                            };
                            let artifact_id = exec_state.next_artifact_id();
                            exec_state.add_artifact(Artifact::SketchBlockConstraint(SketchBlockConstraint {
                                id: artifact_id,
                                sketch_id,
                                constraint_id,
                                constraint_type: SketchBlockConstraintType::from(&constraint),
                                code_ref: CodeRef::placeholder(range),
                            }));
                            exec_state.add_scene_object(
                                Object {
                                    id: constraint_id,
                                    kind: ObjectKind::Constraint { constraint },
                                    label: Default::default(),
                                    comments: Default::default(),
                                    artifact_id,
                                    source: SourceRef::new(range, self.node_path.clone()),
                                },
                                range,
                            );
                        }
                    }
                    return Ok(KclValue::none());
                }
                _ => {
                    return Err(KclError::new_semantic(KclErrorDetails::new(
                        format!(
                            "Cannot create an equivalence constraint between values of these types: {} and {}",
                            left_value.human_friendly_type(),
                            right_value.human_friendly_type()
                        ),
                        vec![self.into()],
                    )));
                }
            }
        }

        let left = number_as_f64(&left_value, self.left.clone().into())?;
        let right = number_as_f64(&right_value, self.right.clone().into())?;

        let value = match self.operator {
            BinaryOperator::Add => {
                let (l, r, ty) = NumericType::combine_eq_coerce(left, right, None);
                self.warn_on_unknown(&ty, "Adding", exec_state);
                KclValue::Number { value: l + r, meta, ty }
            }
            BinaryOperator::Sub => {
                let (l, r, ty) = NumericType::combine_eq_coerce(left, right, None);
                self.warn_on_unknown(&ty, "Subtracting", exec_state);
                KclValue::Number { value: l - r, meta, ty }
            }
            BinaryOperator::Mul => {
                let (l, r, ty) = NumericType::combine_mul(left, right);
                self.warn_on_unknown(&ty, "Multiplying", exec_state);
                KclValue::Number { value: l * r, meta, ty }
            }
            BinaryOperator::Div => {
                let (l, r, ty) = NumericType::combine_div(left, right);
                self.warn_on_unknown(&ty, "Dividing", exec_state);
                KclValue::Number { value: l / r, meta, ty }
            }
            BinaryOperator::Mod => {
                let (l, r, ty) = NumericType::combine_mod(left, right);
                self.warn_on_unknown(&ty, "Modulo of", exec_state);
                KclValue::Number { value: l % r, meta, ty }
            }
            BinaryOperator::Pow => KclValue::Number {
                value: libm::pow(left.n, right.n),
                meta,
                ty: exec_state.current_default_units(),
            },
            BinaryOperator::Neq => {
                let (l, r, ty) = NumericType::combine_eq(left, right, exec_state, self.as_source_range());
                self.warn_on_unknown(&ty, "Comparing", exec_state);
                KclValue::Bool { value: l != r, meta }
            }
            BinaryOperator::Gt => {
                let (l, r, ty) = NumericType::combine_eq(left, right, exec_state, self.as_source_range());
                self.warn_on_unknown(&ty, "Comparing", exec_state);
                KclValue::Bool { value: l > r, meta }
            }
            BinaryOperator::Gte => {
                let (l, r, ty) = NumericType::combine_eq(left, right, exec_state, self.as_source_range());
                self.warn_on_unknown(&ty, "Comparing", exec_state);
                KclValue::Bool { value: l >= r, meta }
            }
            BinaryOperator::Lt => {
                let (l, r, ty) = NumericType::combine_eq(left, right, exec_state, self.as_source_range());
                self.warn_on_unknown(&ty, "Comparing", exec_state);
                KclValue::Bool { value: l < r, meta }
            }
            BinaryOperator::Lte => {
                let (l, r, ty) = NumericType::combine_eq(left, right, exec_state, self.as_source_range());
                self.warn_on_unknown(&ty, "Comparing", exec_state);
                KclValue::Bool { value: l <= r, meta }
            }
            BinaryOperator::Eq => {
                let (l, r, ty) = NumericType::combine_eq(left, right, exec_state, self.as_source_range());
                self.warn_on_unknown(&ty, "Comparing", exec_state);
                KclValue::Bool { value: l == r, meta }
            }
            BinaryOperator::And | BinaryOperator::Or => unreachable!(),
        };

        Ok(value)
    }

    fn missing_result_error(node: &Node<BinaryExpression>) -> KclError {
        internal_err("missing result while evaluating binary expression", node)
    }

    fn warn_on_unknown(&self, ty: &NumericType, verb: &str, exec_state: &mut ExecState) {
        if ty == &NumericType::Unknown {
            let sr = self.as_source_range();
            exec_state.clear_units_warnings(&sr);
            let mut err = CompilationIssue::err(
                sr,
                format!(
                    "{verb} numbers which have unknown or incompatible units.\nYou can probably fix this error by specifying the units using type ascription, e.g., `len: number(mm)` or `(a * b): number(deg)`."
                ),
            );
            err.tag = crate::errors::Tag::UnknownNumericUnits;
            exec_state.warn(err, annotations::WARN_UNKNOWN_UNITS);
        }
    }
}

impl Node<UnaryExpression> {
    pub(super) async fn get_result(
        &self,
        exec_state: &mut ExecState,
        ctx: &ExecutorContext,
    ) -> Result<KclValueControlFlow, KclError> {
        match self.operator {
            UnaryOperator::Not => {
                let value = self.argument.get_result(exec_state, ctx).await?;
                let value = control_continue!(value);
                let KclValue::Bool {
                    value: bool_value,
                    meta: _,
                } = value
                else {
                    return Err(KclError::new_semantic(KclErrorDetails::new(
                        format!(
                            "Cannot apply unary operator ! to non-boolean value: {}",
                            value.human_friendly_type()
                        ),
                        vec![self.into()],
                    )));
                };
                let meta = vec![Metadata {
                    source_range: self.into(),
                }];
                let negated = KclValue::Bool {
                    value: !bool_value,
                    meta,
                };

                Ok(negated.continue_())
            }
            UnaryOperator::Neg => {
                let value = self.argument.get_result(exec_state, ctx).await?;
                let value = control_continue!(value);
                let err = || {
                    KclError::new_semantic(KclErrorDetails::new(
                        format!(
                            "You can only negate numbers, planes, or lines, but this is a {}",
                            value.human_friendly_type()
                        ),
                        vec![self.into()],
                    ))
                };
                match &value {
                    KclValue::Number { value, ty, .. } => {
                        let meta = vec![Metadata {
                            source_range: self.into(),
                        }];
                        Ok(KclValue::Number {
                            value: -value,
                            meta,
                            ty: *ty,
                        }
                        .continue_())
                    }
                    KclValue::Plane { value } => {
                        let mut plane = value.clone();
                        if plane.info.x_axis.x != 0.0 {
                            plane.info.x_axis.x *= -1.0;
                        }
                        if plane.info.x_axis.y != 0.0 {
                            plane.info.x_axis.y *= -1.0;
                        }
                        if plane.info.x_axis.z != 0.0 {
                            plane.info.x_axis.z *= -1.0;
                        }
                        plane.info.z_axis = plane.info.x_axis.axes_cross_product(&plane.info.y_axis);
                        plane.info.z_axis.canonicalize_signed_zero();

                        plane.id = exec_state.next_uuid();
                        plane.object_id = None;
                        Ok(KclValue::Plane { value: plane }.continue_())
                    }
                    KclValue::Object {
                        value: values, meta, ..
                    } => {
                        // Special-case for negating line-like objects.
                        let Some(direction) = values.get("direction") else {
                            return Err(err());
                        };

                        let direction = match direction {
                            KclValue::Tuple { value: values, meta } => {
                                let values = values
                                    .iter()
                                    .map(|v| match v {
                                        KclValue::Number { value, ty, meta } => Ok(KclValue::Number {
                                            value: *value * -1.0,
                                            ty: *ty,
                                            meta: meta.clone(),
                                        }),
                                        _ => Err(err()),
                                    })
                                    .collect::<Result<Vec<_>, _>>()?;

                                KclValue::Tuple {
                                    value: values,
                                    meta: meta.clone(),
                                }
                            }
                            KclValue::HomArray {
                                value: values,
                                ty: ty @ RuntimeType::Primitive(PrimitiveType::Number(_)),
                            } => {
                                let values = values
                                    .iter()
                                    .map(|v| match v {
                                        KclValue::Number { value, ty, meta } => Ok(KclValue::Number {
                                            value: *value * -1.0,
                                            ty: *ty,
                                            meta: meta.clone(),
                                        }),
                                        _ => Err(err()),
                                    })
                                    .collect::<Result<Vec<_>, _>>()?;

                                KclValue::HomArray {
                                    value: values,
                                    ty: ty.clone(),
                                }
                            }
                            _ => return Err(err()),
                        };

                        let mut value = values.clone();
                        value.insert("direction".to_owned(), direction);
                        Ok(KclValue::Object {
                            value,
                            meta: meta.clone(),
                            constrainable: false,
                            object_kind: KclObjectKind::Default,
                        }
                        .continue_())
                    }
                    _ => Err(err()),
                }
            }
            UnaryOperator::Plus => {
                let operand = self.argument.get_result(exec_state, ctx).await?;
                let operand = control_continue!(operand);
                match operand {
                    KclValue::Number { .. } | KclValue::Plane { .. } => Ok(operand.continue_()),
                    _ => Err(KclError::new_semantic(KclErrorDetails::new(
                        format!(
                            "You can only apply unary + to numbers or planes, but this is a {}",
                            operand.human_friendly_type()
                        ),
                        vec![self.into()],
                    ))),
                }
            }
        }
    }
}

pub(crate) async fn execute_pipe_body(
    exec_state: &mut ExecState,
    body: &[Expr],
    source_range: SourceRange,
    ctx: &ExecutorContext,
) -> Result<KclValueControlFlow, KclError> {
    let Some((first, body)) = body.split_first() else {
        return Err(KclError::new_semantic(KclErrorDetails::new(
            "Pipe expressions cannot be empty".to_owned(),
            vec![source_range],
        )));
    };
    // Evaluate the first element in the pipeline.
    // They use the pipe_value from some AST node above this, so that if pipe expression is nested in a larger pipe expression,
    // they use the % from the parent. After all, this pipe expression hasn't been executed yet, so it doesn't have any % value
    // of its own.
    let meta = Metadata {
        source_range: SourceRange::from(first),
    };
    let output = ctx
        .execute_expr(first, exec_state, &meta, &[], StatementKind::Expression)
        .await?;
    let output = control_continue!(output);

    // Now that we've evaluated the first child expression in the pipeline, following child expressions
    // should use the previous child expression for %.
    // This means there's no more need for the previous pipe_value from the parent AST node above this one.
    let previous_pipe_value = exec_state.mod_local.pipe_value.replace(output);
    // Evaluate remaining elements.
    let result = inner_execute_pipe_body(exec_state, body, ctx).await;
    // Restore the previous pipe value.
    exec_state.mod_local.pipe_value = previous_pipe_value;

    result
}

/// Execute the tail of a pipe expression.  exec_state.pipe_value must be set by
/// the caller.
#[async_recursion]
async fn inner_execute_pipe_body(
    exec_state: &mut ExecState,
    body: &[Expr],
    ctx: &ExecutorContext,
) -> Result<KclValueControlFlow, KclError> {
    for expression in body {
        if let Expr::TagDeclarator(_) = expression {
            return Err(KclError::new_semantic(KclErrorDetails::new(
                format!("This cannot be in a PipeExpression: {expression:?}"),
                vec![expression.into()],
            )));
        }
        let metadata = Metadata {
            source_range: SourceRange::from(expression),
        };
        let output = ctx
            .execute_expr(expression, exec_state, &metadata, &[], StatementKind::Expression)
            .await?;
        let output = control_continue!(output);
        exec_state.mod_local.pipe_value = Some(output);
    }
    // Safe to unwrap here, because pipe_value always has something pushed in when the `match first` executes.
    let final_output = exec_state.mod_local.pipe_value.take().unwrap();
    Ok(final_output.continue_())
}

impl Node<TagDeclarator> {
    pub async fn execute(&self, exec_state: &mut ExecState) -> Result<KclValue, KclError> {
        let memory_item = KclValue::TagIdentifier(Box::new(TagIdentifier {
            value: self.name.clone(),
            info: Vec::new(),
            meta: vec![Metadata {
                source_range: self.into(),
            }],
        }));

        exec_state
            .mut_stack()
            .add(self.name.clone(), memory_item, self.into())?;

        Ok(self.into())
    }
}

impl Node<ArrayExpression> {
    #[async_recursion]
    pub(super) async fn execute(
        &self,
        exec_state: &mut ExecState,
        ctx: &ExecutorContext,
    ) -> Result<KclValueControlFlow, KclError> {
        let mut results = Vec::with_capacity(self.elements.len());

        for element in &self.elements {
            let metadata = Metadata::from(element);
            // TODO: Carry statement kind here so that we know if we're
            // inside a variable declaration.
            let value = ctx
                .execute_expr(element, exec_state, &metadata, &[], StatementKind::Expression)
                .await?;
            let value = control_continue!(value);

            results.push(value);
        }

        Ok(KclValue::HomArray {
            value: results,
            ty: RuntimeType::Primitive(PrimitiveType::Any),
        }
        .continue_())
    }
}

impl Node<ArrayRangeExpression> {
    #[async_recursion]
    pub(super) async fn execute(
        &self,
        exec_state: &mut ExecState,
        ctx: &ExecutorContext,
    ) -> Result<KclValueControlFlow, KclError> {
        let metadata = Metadata::from(&self.start_element);
        let start_val = ctx
            .execute_expr(
                &self.start_element,
                exec_state,
                &metadata,
                &[],
                StatementKind::Expression,
            )
            .await?;
        let start_val = control_continue!(start_val);
        let start = start_val
            .as_ty_f64()
            .ok_or(KclError::new_semantic(KclErrorDetails::new(
                format!(
                    "Expected number for range start but found {}",
                    start_val.human_friendly_type()
                ),
                vec![self.into()],
            )))?;
        let metadata = Metadata::from(&self.end_element);
        let end_val = ctx
            .execute_expr(&self.end_element, exec_state, &metadata, &[], StatementKind::Expression)
            .await?;
        let end_val = control_continue!(end_val);
        let end = end_val.as_ty_f64().ok_or(KclError::new_semantic(KclErrorDetails::new(
            format!(
                "Expected number for range end but found {}",
                end_val.human_friendly_type()
            ),
            vec![self.into()],
        )))?;

        let (start, end, ty) = NumericType::combine_range(start, end, exec_state, self.as_source_range())?;
        let Some(start) = crate::try_f64_to_i64(start) else {
            return Err(KclError::new_semantic(KclErrorDetails::new(
                format!("Range start must be an integer, but found {start}"),
                vec![self.into()],
            )));
        };
        let Some(end) = crate::try_f64_to_i64(end) else {
            return Err(KclError::new_semantic(KclErrorDetails::new(
                format!("Range end must be an integer, but found {end}"),
                vec![self.into()],
            )));
        };

        if end < start {
            return Err(KclError::new_semantic(KclErrorDetails::new(
                format!("Range start is greater than range end: {start} .. {end}"),
                vec![self.into()],
            )));
        }

        let range: Vec<_> = if self.end_inclusive {
            (start..=end).collect()
        } else {
            (start..end).collect()
        };

        let meta = vec![Metadata {
            source_range: self.into(),
        }];

        Ok(KclValue::HomArray {
            value: range
                .into_iter()
                .map(|num| KclValue::Number {
                    value: num as f64,
                    ty,
                    meta: meta.clone(),
                })
                .collect(),
            ty: RuntimeType::Primitive(PrimitiveType::Number(ty)),
        }
        .continue_())
    }
}

impl Node<ObjectExpression> {
    #[async_recursion]
    pub(super) async fn execute(
        &self,
        exec_state: &mut ExecState,
        ctx: &ExecutorContext,
    ) -> Result<KclValueControlFlow, KclError> {
        let mut object = HashMap::with_capacity(self.properties.len());
        for property in &self.properties {
            let metadata = Metadata::from(&property.value);
            let result = ctx
                .execute_expr(&property.value, exec_state, &metadata, &[], StatementKind::Expression)
                .await?;
            let result = control_continue!(result);
            object.insert(property.key.name.clone(), result);
        }

        Ok(KclValue::Object {
            value: object,
            meta: vec![Metadata {
                source_range: self.into(),
            }],
            constrainable: false,
            object_kind: KclObjectKind::Default,
        }
        .continue_())
    }
}

fn article_for<S: AsRef<str>>(s: S) -> &'static str {
    // '[' is included since it's an array.
    if s.as_ref().starts_with(['a', 'e', 'i', 'o', 'u', '[']) {
        "an"
    } else {
        "a"
    }
}

fn number_as_f64(v: &KclValue, source_range: SourceRange) -> Result<TyF64, KclError> {
    v.as_ty_f64().ok_or_else(|| {
        let actual_type = v.human_friendly_type();
        KclError::new_semantic(KclErrorDetails::new(
            format!("Expected a number, but found {actual_type}",),
            vec![source_range],
        ))
    })
}

impl Node<IfExpression> {
    #[async_recursion]
    pub(super) async fn get_result(
        &self,
        exec_state: &mut ExecState,
        ctx: &ExecutorContext,
    ) -> Result<KclValueControlFlow, KclError> {
        // Check the `if` branch.
        let cond_value = ctx
            .execute_expr(
                &self.cond,
                exec_state,
                &Metadata::from(self),
                &[],
                StatementKind::Expression,
            )
            .await?;
        let cond_value = control_continue!(cond_value);
        if cond_value.get_bool()? {
            let block_result = ctx.exec_block(&*self.then_val, exec_state, BodyType::Block).await?;
            // Block must end in an expression, so this has to be Some.
            // Enforced by the parser.
            // See https://github.com/KittyCAD/modeling-app/issues/4015
            return Ok(block_result.unwrap());
        }

        // Check any `else if` branches.
        for else_if in &self.else_ifs {
            let cond_value = ctx
                .execute_expr(
                    &else_if.cond,
                    exec_state,
                    &Metadata::from(self),
                    &[],
                    StatementKind::Expression,
                )
                .await?;
            let cond_value = control_continue!(cond_value);
            if cond_value.get_bool()? {
                let block_result = ctx.exec_block(&*else_if.then_val, exec_state, BodyType::Block).await?;
                // Block must end in an expression, so this has to be Some.
                // Enforced by the parser.
                // See https://github.com/KittyCAD/modeling-app/issues/4015
                return Ok(block_result.unwrap());
            }
        }

        // Run the final `else` branch.
        ctx.exec_block(&*self.final_else, exec_state, BodyType::Block)
            .await
            .map(|expr| expr.unwrap())
    }
}

#[derive(Debug)]
enum Property {
    UInt(usize),
    String(String),
}

impl Property {
    #[allow(clippy::too_many_arguments)]
    async fn try_from<'a>(
        computed: bool,
        value: Expr,
        exec_state: &mut ExecState,
        sr: SourceRange,
        ctx: &ExecutorContext,
        metadata: &Metadata,
        annotations: &[Node<Annotation>],
        statement_kind: StatementKind<'a>,
    ) -> Result<Self, KclError> {
        let property_sr = vec![sr];
        if !computed {
            let Expr::Name(identifier) = value else {
                // Should actually be impossible because the parser would reject it.
                return Err(KclError::new_semantic(KclErrorDetails::new(
                    "Object expressions like `obj.property` must use simple identifier names, not complex expressions"
                        .to_owned(),
                    property_sr,
                )));
            };
            return Ok(Property::String(identifier.to_string()));
        }

        let prop_value = ctx
            .execute_expr(&value, exec_state, metadata, annotations, statement_kind)
            .await?;
        let prop_value = match prop_value.control {
            ControlFlowKind::Continue => prop_value.into_value(),
            ControlFlowKind::Exit => {
                let message = "Early return inside array brackets is currently not supported".to_owned();
                debug_assert!(false, "{}", &message);
                return Err(internal_err(message, sr));
            }
        };
        match prop_value {
            KclValue::Number { value, ty, meta: _ } => {
                if !matches!(
                    ty,
                    NumericType::Unknown
                        | NumericType::Default { .. }
                        | NumericType::Known(crate::exec::UnitType::Count)
                ) {
                    return Err(KclError::new_semantic(KclErrorDetails::new(
                        format!(
                            "{value} is not a valid index, indices must be non-dimensional numbers. If you're sure this is correct, you can add `: number(Count)` to tell KCL this number is an index"
                        ),
                        property_sr,
                    )));
                }
                if let Some(x) = crate::try_f64_to_usize(value) {
                    Ok(Property::UInt(x))
                } else {
                    Err(KclError::new_semantic(KclErrorDetails::new(
                        format!("{value} is not a valid index, indices must be whole numbers >= 0"),
                        property_sr,
                    )))
                }
            }
            _ => Err(KclError::new_semantic(KclErrorDetails::new(
                "Only numbers (>= 0) can be indexes".to_owned(),
                vec![sr],
            ))),
        }
    }
}

impl Property {
    fn type_name(&self) -> &'static str {
        match self {
            Property::UInt(_) => "number",
            Property::String(_) => "string",
        }
    }
}

impl Node<PipeExpression> {
    #[async_recursion]
    pub(super) async fn get_result(
        &self,
        exec_state: &mut ExecState,
        ctx: &ExecutorContext,
    ) -> Result<KclValueControlFlow, KclError> {
        execute_pipe_body(exec_state, &self.body, self.into(), ctx).await
    }
}

#[cfg(test)]
mod test {
    use std::sync::Arc;

    use kcl_api::UnitLength;
    use tokio::io::AsyncWriteExt;

    use super::*;
    use crate::ExecutorSettings;
    use crate::engine::engine_manager;
    use crate::errors::Severity;
    use crate::exec::UnitType;
    use crate::execution::ContextType;
    use crate::execution::parse_execute;

    #[tokio::test(flavor = "multi_thread")]
    async fn ascription() {
        let program = r#"
a = 42: number
b = a: number
p = {
  origin = { x = 0, y = 0, z = 0 },
  xAxis = { x = 1, y = 0, z = 0 },
  yAxis = { x = 0, y = 1, z = 0 },
  zAxis = { x = 0, y = 0, z = 1 }
}: Plane
arr1 = [42]: [number(cm)]
"#;

        let result = parse_execute(program).await.unwrap();
        let mem = result.exec_state.stack();
        assert!(matches!(
            mem.memory
                .get_from_owned("p", result.mem_env, SourceRange::default(), 0)
                .unwrap(),
            KclValue::Plane { .. }
        ));
        let arr1 = mem
            .memory
            .get_from_owned("arr1", result.mem_env, SourceRange::default(), 0)
            .unwrap();
        if let KclValue::HomArray { value, ty } = arr1 {
            assert_eq!(value.len(), 1, "Expected Vec with specific length: found {value:?}");
            assert_eq!(ty, RuntimeType::known_length(UnitLength::Centimeters));
            // Compare, ignoring meta.
            if let KclValue::Number { value, ty, .. } = &value[0] {
                // It should not convert units.
                assert_eq!(*value, 42.0);
                assert_eq!(*ty, NumericType::Known(UnitType::Length(UnitLength::Centimeters)));
            } else {
                panic!("Expected a number; found {:?}", value[0]);
            }
        } else {
            panic!("Expected HomArray; found {arr1:?}");
        }

        let program = r#"
a = 42: string
"#;
        let result = parse_execute(program).await;
        let err = result.unwrap_err();
        assert!(
            err.to_string()
                .contains("could not coerce a number (with type `number`) to type `string`"),
            "Expected error but found {err:?}"
        );

        let program = r#"
a = 42: Plane
"#;
        let result = parse_execute(program).await;
        let err = result.unwrap_err();
        assert!(
            err.to_string()
                .contains("could not coerce a number (with type `number`) to type `Plane`"),
            "Expected error but found {err:?}"
        );

        let program = r#"
arr = [0]: [string]
"#;
        let result = parse_execute(program).await;
        let err = result.unwrap_err();
        assert!(
            err.to_string().contains(
                "could not coerce an array of `number` with 1 value (with type `[any; 1]`) to type `[string]`"
            ),
            "Expected error but found {err:?}"
        );

        let program = r#"
mixedArr = [0, "a"]: [number(mm)]
"#;
        let result = parse_execute(program).await;
        let err = result.unwrap_err();
        assert!(
            err.to_string().contains(
                "could not coerce an array of `number`, `string` (with type `[any; 2]`) to type `[number(mm)]`"
            ),
            "Expected error but found {err:?}"
        );

        let program = r#"
mixedArr = [0, "a"]: [mm]
"#;
        let result = parse_execute(program).await;
        let err = result.unwrap_err();
        assert!(
            err.to_string().contains(
                "could not coerce an array of `number`, `string` (with type `[any; 2]`) to type `[number(mm)]`"
            ),
            "Expected error but found {err:?}"
        );
    }

    #[tokio::test(flavor = "multi_thread")]
    async fn neg_plane() {
        let program = r#"
p = {
  origin = { x = 0, y = 0, z = 0 },
  xAxis = { x = 1, y = 0, z = 0 },
  yAxis = { x = 0, y = 1, z = 0 },
}: Plane
p2 = -p
"#;

        let result = parse_execute(program).await.unwrap();
        let mem = result.exec_state.stack();
        match mem
            .memory
            .get_from_owned("p2", result.mem_env, SourceRange::default(), 0)
            .unwrap()
        {
            KclValue::Plane { value } => {
                assert_eq!(value.info.x_axis.x, -1.0);
                assert_eq!(value.info.x_axis.y, 0.0);
                assert_eq!(value.info.x_axis.z, 0.0);
            }
            _ => unreachable!(),
        }
    }

    #[tokio::test(flavor = "multi_thread")]
    async fn multiple_returns() {
        let program = r#"fn foo() {
  return 0
  return 42
}

a = foo()
"#;

        let result = parse_execute(program).await;
        assert!(result.unwrap_err().to_string().contains("return"));
    }

    #[tokio::test(flavor = "multi_thread")]
    async fn load_all_modules() {
        // program a.kcl
        let program_a_kcl = r#"
export a = 1
"#;
        // program b.kcl
        let program_b_kcl = r#"
import a from 'a.kcl'

export b = a + 1
"#;
        // program c.kcl
        let program_c_kcl = r#"
import a from 'a.kcl'

export c = a + 2
"#;

        // program main.kcl
        let main_kcl = r#"
import b from 'b.kcl'
import c from 'c.kcl'

d = b + c
"#;

        let main = crate::parsing::parse_str(main_kcl, ModuleId::default())
            .parse_errs_as_err()
            .unwrap();

        let tmpdir = tempfile::TempDir::with_prefix("zma_kcl_load_all_modules").unwrap();

        tokio::fs::File::create(tmpdir.path().join("main.kcl"))
            .await
            .unwrap()
            .write_all(main_kcl.as_bytes())
            .await
            .unwrap();

        tokio::fs::File::create(tmpdir.path().join("a.kcl"))
            .await
            .unwrap()
            .write_all(program_a_kcl.as_bytes())
            .await
            .unwrap();

        tokio::fs::File::create(tmpdir.path().join("b.kcl"))
            .await
            .unwrap()
            .write_all(program_b_kcl.as_bytes())
            .await
            .unwrap();

        tokio::fs::File::create(tmpdir.path().join("c.kcl"))
            .await
            .unwrap()
            .write_all(program_c_kcl.as_bytes())
            .await
            .unwrap();

        let exec_ctxt = ExecutorContext {
            engine: Arc::new(engine_manager::EngineManager::new_mock()),
            engine_batch: crate::engine::EngineBatchContext::default(),
            fs: crate::fs::new_file_system_handle(crate::fs::FileManager::new()),
            settings: ExecutorSettings {
                project_directory: Some(crate::TypedPath(tmpdir.path().into())),
                ..Default::default()
            },
            context_type: ContextType::Mock,
            execution_callbacks: Default::default(),
        };
        let mut exec_state = ExecState::new(&exec_ctxt);

        exec_ctxt
            .run(
                &crate::Program {
                    ast: main.clone(),
                    original_file_contents: "".to_owned(),
                },
                &mut exec_state,
            )
            .await
            .unwrap();
    }

    #[tokio::test(flavor = "multi_thread")]
    async fn user_coercion() {
        let program = r#"fn foo(x: Axis2d) {
  return 0
}

foo(x = { direction = [0, 0], origin = [0, 0]})
"#;

        parse_execute(program).await.unwrap();

        let program = r#"fn foo(x: Axis3d) {
  return 0
}

foo(x = { direction = [0, 0], origin = [0, 0]})
"#;

        parse_execute(program).await.unwrap_err();
    }

    #[tokio::test(flavor = "multi_thread")]
    async fn coerce_return() {
        let program = r#"fn foo(): number(mm) {
  return 42
}

a = foo()
"#;

        parse_execute(program).await.unwrap();

        let program = r#"fn foo(): mm {
  return 42
}

a = foo()
"#;

        parse_execute(program).await.unwrap();

        let program = r#"fn foo(): number(mm) {
  return { bar: 42 }
}

a = foo()
"#;

        parse_execute(program).await.unwrap_err();

        let program = r#"fn foo(): mm {
  return { bar: 42 }
}

a = foo()
"#;

        parse_execute(program).await.unwrap_err();
    }

    #[tokio::test(flavor = "multi_thread")]
    async fn test_sensible_error_when_missing_equals_in_kwarg() {
        for (i, call) in ["f(x=1,3,0)", "f(x=1,3,z)", "f(x=1,0,z=1)", "f(x=1, 3 + 4, z)"]
            .into_iter()
            .enumerate()
        {
            let program = format!(
                "fn foo() {{ return 0 }}
z = 0
fn f(x, y, z) {{ return 0 }}
{call}"
            );
            let err = parse_execute(&program).await.unwrap_err();
            let msg = err.message();
            assert!(
                msg.contains("This argument needs a label, but it doesn't have one"),
                "failed test {i}: {msg}"
            );
            assert!(msg.contains("`y`"), "failed test {i}, missing `y`: {msg}");
            if i == 0 {
                assert!(msg.contains("`z`"), "failed test {i}, missing `z`: {msg}");
            }
        }
    }

    #[tokio::test(flavor = "multi_thread")]
    async fn default_param_for_unlabeled() {
        // Tests that the input param for myExtrude is taken from the pipeline value and same-name
        // keyword args.
        let ast = r#"fn myExtrude(@sk, length) {
  return extrude(sk, length)
}
sketch001 = startSketchOn(XY)
  |> circle(center = [0, 0], radius = 93.75)
  |> myExtrude(length = 40)
"#;

        parse_execute(ast).await.unwrap();
    }

    #[tokio::test(flavor = "multi_thread")]
    async fn dont_use_unlabelled_as_input() {
        // `length` should be used as the `length` argument to extrude, not the unlabelled input
        let ast = r#"length = 10
startSketchOn(XY)
  |> circle(center = [0, 0], radius = 93.75)
  |> extrude(length)
"#;

        parse_execute(ast).await.unwrap();
    }

    #[tokio::test(flavor = "multi_thread")]
    async fn ascription_in_binop() {
        let ast = r#"foo = tan(0): number(rad) - 4deg"#;
        parse_execute(ast).await.unwrap();

        let ast = r#"foo = tan(0): rad - 4deg"#;
        parse_execute(ast).await.unwrap();
    }

    #[tokio::test(flavor = "multi_thread")]
    async fn neg_sqrt() {
        let ast = r#"bad = sqrt(-2)"#;

        let e = parse_execute(ast).await.unwrap_err();
        // Make sure we get a useful error message and not an engine error.
        assert!(e.message().contains("sqrt"), "Error message: '{}'", e.message());
    }

    #[tokio::test(flavor = "multi_thread")]
    async fn non_array_fns() {
        let ast = r#"push(1, item = 2)
pop(1)
map(1, f = fn(@x) { return x + 1 })
reduce(1, f = fn(@x, accum) { return accum + x}, initial = 0)"#;

        parse_execute(ast).await.unwrap();
    }

    #[tokio::test(flavor = "multi_thread")]
    async fn non_array_indexing() {
        let good = r#"a = 42
good = a[0]
"#;
        let result = parse_execute(good).await.unwrap();
        let mem = result.exec_state.stack();
        let num = mem
            .memory
            .get_from_owned("good", result.mem_env, SourceRange::default(), 0)
            .unwrap()
            .as_ty_f64()
            .unwrap();
        assert_eq!(num.n, 42.0);

        let bad = r#"a = 42
bad = a[1]
"#;

        parse_execute(bad).await.unwrap_err();
    }

    #[tokio::test(flavor = "multi_thread")]
    async fn coerce_unknown_to_length() {
        let ast = r#"x = 2mm * 2mm
y = x: number(Length)"#;
        let e = parse_execute(ast).await.unwrap_err();
        assert!(
            e.message().contains("could not coerce"),
            "Error message: '{}'",
            e.message()
        );

        let ast = r#"x = 2mm
y = x: number(Length)"#;
        let result = parse_execute(ast).await.unwrap();
        let mem = result.exec_state.stack();
        let num = mem
            .memory
            .get_from_owned("y", result.mem_env, SourceRange::default(), 0)
            .unwrap()
            .as_ty_f64()
            .unwrap();
        assert_eq!(num.n, 2.0);
        assert_eq!(num.ty, NumericType::mm());
    }

    #[tokio::test(flavor = "multi_thread")]
    async fn one_warning_unknown() {
        let ast = r#"
// Should warn once
a = PI * 2
// Should warn once
b = (PI * 2) / 3
// Should not warn
c = ((PI * 2) / 3): number(deg)
"#;

        let result = parse_execute(ast).await.unwrap();
        assert_eq!(result.exec_state.issues().len(), 2);
    }

    #[tokio::test(flavor = "multi_thread")]
    async fn non_count_indexing() {
        let ast = r#"x = [0, 0]
y = x[1mm]
"#;
        parse_execute(ast).await.unwrap_err();

        let ast = r#"x = [0, 0]
y = 1deg
z = x[y]
"#;
        parse_execute(ast).await.unwrap_err();

        let ast = r#"x = [0, 0]
y = x[0mm + 1]
"#;
        parse_execute(ast).await.unwrap_err();
    }

    #[tokio::test(flavor = "multi_thread")]
    async fn getting_property_of_plane() {
        let ast = std::fs::read_to_string("tests/inputs/planestuff.kcl").unwrap();
        parse_execute(&ast).await.unwrap();
    }

    #[tokio::test(flavor = "multi_thread")]
    async fn no_artifacts_from_within_hole_call() {
        // Test that executing stdlib KCL, like the `hole` function
        // (which is actually implemented in KCL not Rust)
        // does not generate artifacts from within the stdlib code,
        // only from the user code.
        let ast = std::fs::read_to_string("tests/inputs/sample_hole.kcl").unwrap();
        let out = parse_execute(&ast).await.unwrap();

        // Get all the operations that occurred.
        let actual_operations = out.exec_state.global.root_module_artifacts.operations;

        // There should be 5, for sketching the cube and applying the hole.
        // If the stdlib internal calls are being tracked, that's a bug,
        // and the actual number of operations will be something like 35.
        let expected = 5;
        assert_eq!(
            actual_operations.len(),
            expected,
            "expected {expected} operations, received {}:\n{actual_operations:#?}",
            actual_operations.len(),
        );
    }

    #[tokio::test(flavor = "multi_thread")]
    async fn feature_tree_annotation_on_user_defined_kcl() {
        // The call to foo() should not generate an operation,
        // because its 'feature_tree' attribute has been set to false.
        let ast = std::fs::read_to_string("tests/inputs/feature_tree_annotation_on_user_defined_kcl.kcl").unwrap();
        let out = parse_execute(&ast).await.unwrap();

        // Get all the operations that occurred.
        let actual_operations = out.exec_state.global.root_module_artifacts.operations;

        let expected = 0;
        assert_eq!(
            actual_operations.len(),
            expected,
            "expected {expected} operations, received {}:\n{actual_operations:#?}",
            actual_operations.len(),
        );
    }

    #[tokio::test(flavor = "multi_thread")]
    async fn no_feature_tree_annotation_on_user_defined_kcl() {
        // The call to foo() should generate an operation,
        // because @(feature_tree) defaults to true.
        let ast = std::fs::read_to_string("tests/inputs/no_feature_tree_annotation_on_user_defined_kcl.kcl").unwrap();
        let out = parse_execute(&ast).await.unwrap();

        // Get all the operations that occurred.
        let actual_operations = out.exec_state.global.root_module_artifacts.operations;

        let expected = 2;
        assert_eq!(
            actual_operations.len(),
            expected,
            "expected {expected} operations, received {}:\n{actual_operations:#?}",
            actual_operations.len(),
        );
        assert!(matches!(actual_operations[0], Operation::GroupBegin { .. }));
        assert!(matches!(actual_operations[1], Operation::GroupEnd));
    }

    #[tokio::test(flavor = "multi_thread")]
    async fn custom_warning() {
        let warn = r#"
a = PI * 2
"#;
        let result = parse_execute(warn).await.unwrap();
        assert_eq!(result.exec_state.issues().len(), 1);
        assert_eq!(result.exec_state.issues()[0].severity, Severity::Warning);

        let allow = r#"
@warnings(allow = unknownUnits)
a = PI * 2
"#;
        let result = parse_execute(allow).await.unwrap();
        assert_eq!(result.exec_state.issues().len(), 0);

        let deny = r#"
@warnings(deny = [unknownUnits])
a = PI * 2
"#;
        let result = parse_execute(deny).await.unwrap();
        assert_eq!(result.exec_state.issues().len(), 1);
        assert_eq!(result.exec_state.issues()[0].severity, Severity::Error);
    }

    #[tokio::test(flavor = "multi_thread")]
    async fn sketch_block_unqualified_functions_use_sketch2() {
        let ast = r#"
s = sketch(on = XY) {
  line1 = line(start = [var 0mm, var 0mm], end = [var 1mm, var 0mm])
  line2 = line(start = [var 1mm, var 0mm], end = [var 1mm, var 1mm])
  coincident([line1.end, line2.start])
}
"#;
        let result = parse_execute(ast).await.unwrap();
        let mem = result.exec_state.stack();
        let sketch_value = mem
            .memory
            .get_from_owned("s", result.mem_env, SourceRange::default(), 0)
            .unwrap();

        let KclValue::Object { value, .. } = sketch_value else {
            panic!("Expected sketch block to return an object, got {sketch_value:?}");
        };

        assert!(value.contains_key("line1"));
        assert!(value.contains_key("line2"));
        // Ensure sketch2 aliases used during execution are not returned as
        // sketch block fields.
        assert!(!value.contains_key("line"));
        assert!(!value.contains_key("coincident"));
    }

    #[tokio::test(flavor = "multi_thread")]
    async fn solver_module_is_not_available_outside_sketch_blocks() {
        let err = parse_execute("a = solver::ORIGIN").await.unwrap_err();
        assert!(err.message().contains("solver"), "Error message: '{}'", err.message());

        let err = parse_execute(
            r#"@settings(experimentalFeatures = allow)

import "std::solver""#,
        )
        .await
        .unwrap_err();
        assert!(
            err.message().contains("only available inside sketch blocks"),
            "Error message: '{}'",
            err.message()
        );
    }

    #[tokio::test(flavor = "multi_thread")]
    async fn cannot_solid_extrude_an_open_profile() {
        // This should fail during mock execution, because KCL should catch
        // that the profile is not closed.
        let code = std::fs::read_to_string("tests/inputs/cannot_solid_extrude_an_open_profile.kcl").unwrap();
        let program = crate::Program::parse_no_errs(&code).expect("should parse");
        let exec_ctxt = ExecutorContext::new_mock(None).await;
        let mut exec_state = ExecState::new(&exec_ctxt);

        let err = exec_ctxt.run(&program, &mut exec_state).await.unwrap_err().error;
        assert!(matches!(err, KclError::Semantic { .. }));
        exec_ctxt.close().await;
    }
}
