KCL: Use named fields for KclError (#7321)
We've changed the unnamed field of `KclError` variants to a named called `details`.
To clarify: previously KCL errors looked like this:
```rust
pub enum KclError {
    Lexical(KclErrorDetails),
    Syntax(KclErrorDetails),
```
Now they look like this:
```rust
pub enum KclError {
    Lexical { details: KclErrorDetails },
    Syntax { details: KclErrorDetails },
}
```
This lets us more easily add fields to the errors. For example, in the UndefinedValue case, adding a field for what the undefined name was. This PR refactors the code to make my PR in https://github.com/KittyCAD/modeling-app/pull/7309 much easier.
Pure refactor, should not change any behaviour.
			
			
This commit is contained in:
		@ -439,7 +439,7 @@ impl EngineManager for EngineConnection {
 | 
			
		||||
                request_sent: tx,
 | 
			
		||||
            })
 | 
			
		||||
            .await
 | 
			
		||||
            .map_err(|e| KclError::Engine(KclErrorDetails::new(format!("Failed to send debug: {}", e), vec![])))?;
 | 
			
		||||
            .map_err(|e| KclError::new_engine(KclErrorDetails::new(format!("Failed to send debug: {}", e), vec![])))?;
 | 
			
		||||
 | 
			
		||||
        let _ = rx.await;
 | 
			
		||||
        Ok(())
 | 
			
		||||
@ -474,7 +474,7 @@ impl EngineManager for EngineConnection {
 | 
			
		||||
            })
 | 
			
		||||
            .await
 | 
			
		||||
            .map_err(|e| {
 | 
			
		||||
                KclError::Engine(KclErrorDetails::new(
 | 
			
		||||
                KclError::new_engine(KclErrorDetails::new(
 | 
			
		||||
                    format!("Failed to send modeling command: {}", e),
 | 
			
		||||
                    vec![source_range],
 | 
			
		||||
                ))
 | 
			
		||||
@ -483,13 +483,13 @@ impl EngineManager for EngineConnection {
 | 
			
		||||
        // Wait for the request to be sent.
 | 
			
		||||
        rx.await
 | 
			
		||||
            .map_err(|e| {
 | 
			
		||||
                KclError::Engine(KclErrorDetails::new(
 | 
			
		||||
                KclError::new_engine(KclErrorDetails::new(
 | 
			
		||||
                    format!("could not send request to the engine actor: {e}"),
 | 
			
		||||
                    vec![source_range],
 | 
			
		||||
                ))
 | 
			
		||||
            })?
 | 
			
		||||
            .map_err(|e| {
 | 
			
		||||
                KclError::Engine(KclErrorDetails::new(
 | 
			
		||||
                KclError::new_engine(KclErrorDetails::new(
 | 
			
		||||
                    format!("could not send request to the engine: {e}"),
 | 
			
		||||
                    vec![source_range],
 | 
			
		||||
                ))
 | 
			
		||||
@ -516,12 +516,12 @@ impl EngineManager for EngineConnection {
 | 
			
		||||
                // Check if we have any pending errors.
 | 
			
		||||
                let pe = self.pending_errors.read().await;
 | 
			
		||||
                if !pe.is_empty() {
 | 
			
		||||
                    return Err(KclError::Engine(KclErrorDetails::new(
 | 
			
		||||
                    return Err(KclError::new_engine(KclErrorDetails::new(
 | 
			
		||||
                        pe.join(", ").to_string(),
 | 
			
		||||
                        vec![source_range],
 | 
			
		||||
                    )));
 | 
			
		||||
                } else {
 | 
			
		||||
                    return Err(KclError::Engine(KclErrorDetails::new(
 | 
			
		||||
                    return Err(KclError::new_engine(KclErrorDetails::new(
 | 
			
		||||
                        "Modeling command failed: websocket closed early".to_string(),
 | 
			
		||||
                        vec![source_range],
 | 
			
		||||
                    )));
 | 
			
		||||
@ -543,7 +543,7 @@ impl EngineManager for EngineConnection {
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Err(KclError::Engine(KclErrorDetails::new(
 | 
			
		||||
        Err(KclError::new_engine(KclErrorDetails::new(
 | 
			
		||||
            format!("Modeling command timed out `{}`", id),
 | 
			
		||||
            vec![source_range],
 | 
			
		||||
        )))
 | 
			
		||||
 | 
			
		||||
@ -147,19 +147,19 @@ impl EngineConnection {
 | 
			
		||||
        id_to_source_range: HashMap<uuid::Uuid, SourceRange>,
 | 
			
		||||
    ) -> Result<(), KclError> {
 | 
			
		||||
        let source_range_str = serde_json::to_string(&source_range).map_err(|e| {
 | 
			
		||||
            KclError::Engine(KclErrorDetails::new(
 | 
			
		||||
            KclError::new_engine(KclErrorDetails::new(
 | 
			
		||||
                format!("Failed to serialize source range: {:?}", e),
 | 
			
		||||
                vec![source_range],
 | 
			
		||||
            ))
 | 
			
		||||
        })?;
 | 
			
		||||
        let cmd_str = serde_json::to_string(&cmd).map_err(|e| {
 | 
			
		||||
            KclError::Engine(KclErrorDetails::new(
 | 
			
		||||
            KclError::new_engine(KclErrorDetails::new(
 | 
			
		||||
                format!("Failed to serialize modeling command: {:?}", e),
 | 
			
		||||
                vec![source_range],
 | 
			
		||||
            ))
 | 
			
		||||
        })?;
 | 
			
		||||
        let id_to_source_range_str = serde_json::to_string(&id_to_source_range).map_err(|e| {
 | 
			
		||||
            KclError::Engine(KclErrorDetails::new(
 | 
			
		||||
            KclError::new_engine(KclErrorDetails::new(
 | 
			
		||||
                format!("Failed to serialize id to source range: {:?}", e),
 | 
			
		||||
                vec![source_range],
 | 
			
		||||
            ))
 | 
			
		||||
@ -167,7 +167,7 @@ impl EngineConnection {
 | 
			
		||||
 | 
			
		||||
        self.manager
 | 
			
		||||
            .fire_modeling_cmd_from_wasm(id.to_string(), source_range_str, cmd_str, id_to_source_range_str)
 | 
			
		||||
            .map_err(|e| KclError::Engine(KclErrorDetails::new(e.to_string().into(), vec![source_range])))?;
 | 
			
		||||
            .map_err(|e| KclError::new_engine(KclErrorDetails::new(e.to_string().into(), vec![source_range])))?;
 | 
			
		||||
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
@ -180,19 +180,19 @@ impl EngineConnection {
 | 
			
		||||
        id_to_source_range: HashMap<uuid::Uuid, SourceRange>,
 | 
			
		||||
    ) -> Result<WebSocketResponse, KclError> {
 | 
			
		||||
        let source_range_str = serde_json::to_string(&source_range).map_err(|e| {
 | 
			
		||||
            KclError::Engine(KclErrorDetails::new(
 | 
			
		||||
            KclError::new_engine(KclErrorDetails::new(
 | 
			
		||||
                format!("Failed to serialize source range: {:?}", e),
 | 
			
		||||
                vec![source_range],
 | 
			
		||||
            ))
 | 
			
		||||
        })?;
 | 
			
		||||
        let cmd_str = serde_json::to_string(&cmd).map_err(|e| {
 | 
			
		||||
            KclError::Engine(KclErrorDetails::new(
 | 
			
		||||
            KclError::new_engine(KclErrorDetails::new(
 | 
			
		||||
                format!("Failed to serialize modeling command: {:?}", e),
 | 
			
		||||
                vec![source_range],
 | 
			
		||||
            ))
 | 
			
		||||
        })?;
 | 
			
		||||
        let id_to_source_range_str = serde_json::to_string(&id_to_source_range).map_err(|e| {
 | 
			
		||||
            KclError::Engine(KclErrorDetails::new(
 | 
			
		||||
            KclError::new_engine(KclErrorDetails::new(
 | 
			
		||||
                format!("Failed to serialize id to source range: {:?}", e),
 | 
			
		||||
                vec![source_range],
 | 
			
		||||
            ))
 | 
			
		||||
@ -201,7 +201,7 @@ impl EngineConnection {
 | 
			
		||||
        let promise = self
 | 
			
		||||
            .manager
 | 
			
		||||
            .send_modeling_cmd_from_wasm(id.to_string(), source_range_str, cmd_str, id_to_source_range_str)
 | 
			
		||||
            .map_err(|e| KclError::Engine(KclErrorDetails::new(e.to_string().into(), vec![source_range])))?;
 | 
			
		||||
            .map_err(|e| KclError::new_engine(KclErrorDetails::new(e.to_string().into(), vec![source_range])))?;
 | 
			
		||||
 | 
			
		||||
        let value = crate::wasm::JsFuture::from(promise).await.map_err(|e| {
 | 
			
		||||
            // Try to parse the error as an engine error.
 | 
			
		||||
@ -209,7 +209,7 @@ impl EngineConnection {
 | 
			
		||||
            if let Ok(kittycad_modeling_cmds::websocket::FailureWebSocketResponse { errors, .. }) =
 | 
			
		||||
                serde_json::from_str(&err_str)
 | 
			
		||||
            {
 | 
			
		||||
                KclError::Engine(KclErrorDetails::new(
 | 
			
		||||
                KclError::new_engine(KclErrorDetails::new(
 | 
			
		||||
                    errors.iter().map(|e| e.message.clone()).collect::<Vec<_>>().join("\n"),
 | 
			
		||||
                    vec![source_range],
 | 
			
		||||
                ))
 | 
			
		||||
@ -218,7 +218,7 @@ impl EngineConnection {
 | 
			
		||||
            {
 | 
			
		||||
                if let Some(data) = data.first() {
 | 
			
		||||
                    // It could also be an array of responses.
 | 
			
		||||
                    KclError::Engine(KclErrorDetails::new(
 | 
			
		||||
                    KclError::new_engine(KclErrorDetails::new(
 | 
			
		||||
                        data.errors
 | 
			
		||||
                            .iter()
 | 
			
		||||
                            .map(|e| e.message.clone())
 | 
			
		||||
@ -227,13 +227,13 @@ impl EngineConnection {
 | 
			
		||||
                        vec![source_range],
 | 
			
		||||
                    ))
 | 
			
		||||
                } else {
 | 
			
		||||
                    KclError::Engine(KclErrorDetails::new(
 | 
			
		||||
                    KclError::new_engine(KclErrorDetails::new(
 | 
			
		||||
                        "Received empty response from engine".into(),
 | 
			
		||||
                        vec![source_range],
 | 
			
		||||
                    ))
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                KclError::Engine(KclErrorDetails::new(
 | 
			
		||||
                KclError::new_engine(KclErrorDetails::new(
 | 
			
		||||
                    format!("Failed to wait for promise from send modeling command: {:?}", e),
 | 
			
		||||
                    vec![source_range],
 | 
			
		||||
                ))
 | 
			
		||||
@ -241,7 +241,7 @@ impl EngineConnection {
 | 
			
		||||
        })?;
 | 
			
		||||
 | 
			
		||||
        if value.is_null() || value.is_undefined() {
 | 
			
		||||
            return Err(KclError::Engine(KclErrorDetails::new(
 | 
			
		||||
            return Err(KclError::new_engine(KclErrorDetails::new(
 | 
			
		||||
                "Received null or undefined response from engine".into(),
 | 
			
		||||
                vec![source_range],
 | 
			
		||||
            )));
 | 
			
		||||
@ -251,7 +251,7 @@ impl EngineConnection {
 | 
			
		||||
        let data = js_sys::Uint8Array::from(value);
 | 
			
		||||
 | 
			
		||||
        let ws_result: WebSocketResponse = bson::from_slice(&data.to_vec()).map_err(|e| {
 | 
			
		||||
            KclError::Engine(KclErrorDetails::new(
 | 
			
		||||
            KclError::new_engine(KclErrorDetails::new(
 | 
			
		||||
                format!("Failed to deserialize bson response from engine: {:?}", e),
 | 
			
		||||
                vec![source_range],
 | 
			
		||||
            ))
 | 
			
		||||
@ -308,10 +308,10 @@ impl crate::engine::EngineManager for EngineConnection {
 | 
			
		||||
        let promise = self
 | 
			
		||||
            .manager
 | 
			
		||||
            .start_new_session()
 | 
			
		||||
            .map_err(|e| KclError::Engine(KclErrorDetails::new(e.to_string().into(), vec![source_range])))?;
 | 
			
		||||
            .map_err(|e| KclError::new_engine(KclErrorDetails::new(e.to_string().into(), vec![source_range])))?;
 | 
			
		||||
 | 
			
		||||
        crate::wasm::JsFuture::from(promise).await.map_err(|e| {
 | 
			
		||||
            KclError::Engine(KclErrorDetails::new(
 | 
			
		||||
            KclError::new_engine(KclErrorDetails::new(
 | 
			
		||||
                format!("Failed to wait for promise from start new session: {:?}", e),
 | 
			
		||||
                vec![source_range],
 | 
			
		||||
            ))
 | 
			
		||||
 | 
			
		||||
@ -276,7 +276,7 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
 | 
			
		||||
                {
 | 
			
		||||
                    let duration = instant::Duration::from_millis(1);
 | 
			
		||||
                    wasm_timer::Delay::new(duration).await.map_err(|err| {
 | 
			
		||||
                        KclError::Internal(KclErrorDetails::new(
 | 
			
		||||
                        KclError::new_internal(KclErrorDetails::new(
 | 
			
		||||
                            format!("Failed to sleep: {:?}", err),
 | 
			
		||||
                            vec![source_range],
 | 
			
		||||
                        ))
 | 
			
		||||
@ -293,7 +293,7 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
 | 
			
		||||
            return Ok(response);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Err(KclError::Engine(KclErrorDetails::new(
 | 
			
		||||
        Err(KclError::new_engine(KclErrorDetails::new(
 | 
			
		||||
            "async command timed out".to_string(),
 | 
			
		||||
            vec![source_range],
 | 
			
		||||
        )))
 | 
			
		||||
@ -547,7 +547,7 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
 | 
			
		||||
                    id_to_source_range.insert(Uuid::from(*cmd_id), *range);
 | 
			
		||||
                }
 | 
			
		||||
                _ => {
 | 
			
		||||
                    return Err(KclError::Engine(KclErrorDetails::new(
 | 
			
		||||
                    return Err(KclError::new_engine(KclErrorDetails::new(
 | 
			
		||||
                        format!("The request is not a modeling command: {:?}", req),
 | 
			
		||||
                        vec![*range],
 | 
			
		||||
                    )));
 | 
			
		||||
@ -595,7 +595,7 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
 | 
			
		||||
                    self.parse_batch_responses(last_id.into(), id_to_source_range, responses)
 | 
			
		||||
                } else {
 | 
			
		||||
                    // We should never get here.
 | 
			
		||||
                    Err(KclError::Engine(KclErrorDetails::new(
 | 
			
		||||
                    Err(KclError::new_engine(KclErrorDetails::new(
 | 
			
		||||
                        format!("Failed to get batch response: {:?}", response),
 | 
			
		||||
                        vec![source_range],
 | 
			
		||||
                    )))
 | 
			
		||||
@ -610,7 +610,7 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
 | 
			
		||||
                // request so we need the original request source range in case the engine returns
 | 
			
		||||
                // an error.
 | 
			
		||||
                let source_range = id_to_source_range.get(cmd_id.as_ref()).cloned().ok_or_else(|| {
 | 
			
		||||
                    KclError::Engine(KclErrorDetails::new(
 | 
			
		||||
                    KclError::new_engine(KclErrorDetails::new(
 | 
			
		||||
                        format!("Failed to get source range for command ID: {:?}", cmd_id),
 | 
			
		||||
                        vec![],
 | 
			
		||||
                    ))
 | 
			
		||||
@ -620,7 +620,7 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
 | 
			
		||||
                    .await?;
 | 
			
		||||
                self.parse_websocket_response(ws_resp, source_range)
 | 
			
		||||
            }
 | 
			
		||||
            _ => Err(KclError::Engine(KclErrorDetails::new(
 | 
			
		||||
            _ => Err(KclError::new_engine(KclErrorDetails::new(
 | 
			
		||||
                format!("The final request is not a modeling command: {:?}", final_req),
 | 
			
		||||
                vec![source_range],
 | 
			
		||||
            ))),
 | 
			
		||||
@ -729,7 +729,7 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
 | 
			
		||||
        for (name, plane_id, color) in plane_settings {
 | 
			
		||||
            let info = DEFAULT_PLANE_INFO.get(&name).ok_or_else(|| {
 | 
			
		||||
                // We should never get here.
 | 
			
		||||
                KclError::Engine(KclErrorDetails::new(
 | 
			
		||||
                KclError::new_engine(KclErrorDetails::new(
 | 
			
		||||
                    format!("Failed to get default plane info for: {:?}", name),
 | 
			
		||||
                    vec![source_range],
 | 
			
		||||
                ))
 | 
			
		||||
@ -763,7 +763,7 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
 | 
			
		||||
            WebSocketResponse::Success(success) => Ok(success.resp),
 | 
			
		||||
            WebSocketResponse::Failure(fail) => {
 | 
			
		||||
                let _request_id = fail.request_id;
 | 
			
		||||
                Err(KclError::Engine(KclErrorDetails::new(
 | 
			
		||||
                Err(KclError::new_engine(KclErrorDetails::new(
 | 
			
		||||
                    fail.errors
 | 
			
		||||
                        .iter()
 | 
			
		||||
                        .map(|e| e.message.clone())
 | 
			
		||||
@ -805,12 +805,12 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
 | 
			
		||||
                BatchResponse::Failure { errors } => {
 | 
			
		||||
                    // Get the source range for the command.
 | 
			
		||||
                    let source_range = id_to_source_range.get(cmd_id).cloned().ok_or_else(|| {
 | 
			
		||||
                        KclError::Engine(KclErrorDetails::new(
 | 
			
		||||
                        KclError::new_engine(KclErrorDetails::new(
 | 
			
		||||
                            format!("Failed to get source range for command ID: {:?}", cmd_id),
 | 
			
		||||
                            vec![],
 | 
			
		||||
                        ))
 | 
			
		||||
                    })?;
 | 
			
		||||
                    return Err(KclError::Engine(KclErrorDetails::new(
 | 
			
		||||
                    return Err(KclError::new_engine(KclErrorDetails::new(
 | 
			
		||||
                        errors.iter().map(|e| e.message.clone()).collect::<Vec<_>>().join("\n"),
 | 
			
		||||
                        vec![source_range],
 | 
			
		||||
                    )));
 | 
			
		||||
@ -820,7 +820,7 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
 | 
			
		||||
 | 
			
		||||
        // Return an error that we did not get an error or the response we wanted.
 | 
			
		||||
        // This should never happen but who knows.
 | 
			
		||||
        Err(KclError::Engine(KclErrorDetails::new(
 | 
			
		||||
        Err(KclError::new_engine(KclErrorDetails::new(
 | 
			
		||||
            format!("Failed to find response for command ID: {:?}", id),
 | 
			
		||||
            vec![],
 | 
			
		||||
        )))
 | 
			
		||||
 | 
			
		||||
@ -91,30 +91,30 @@ pub enum ConnectionError {
 | 
			
		||||
#[ts(export)]
 | 
			
		||||
#[serde(tag = "kind", rename_all = "snake_case")]
 | 
			
		||||
pub enum KclError {
 | 
			
		||||
    #[error("lexical: {0:?}")]
 | 
			
		||||
    Lexical(KclErrorDetails),
 | 
			
		||||
    #[error("syntax: {0:?}")]
 | 
			
		||||
    Syntax(KclErrorDetails),
 | 
			
		||||
    #[error("semantic: {0:?}")]
 | 
			
		||||
    Semantic(KclErrorDetails),
 | 
			
		||||
    #[error("import cycle: {0:?}")]
 | 
			
		||||
    ImportCycle(KclErrorDetails),
 | 
			
		||||
    #[error("type: {0:?}")]
 | 
			
		||||
    Type(KclErrorDetails),
 | 
			
		||||
    #[error("i/o: {0:?}")]
 | 
			
		||||
    Io(KclErrorDetails),
 | 
			
		||||
    #[error("unexpected: {0:?}")]
 | 
			
		||||
    Unexpected(KclErrorDetails),
 | 
			
		||||
    #[error("value already defined: {0:?}")]
 | 
			
		||||
    ValueAlreadyDefined(KclErrorDetails),
 | 
			
		||||
    #[error("undefined value: {0:?}")]
 | 
			
		||||
    UndefinedValue(KclErrorDetails),
 | 
			
		||||
    #[error("invalid expression: {0:?}")]
 | 
			
		||||
    InvalidExpression(KclErrorDetails),
 | 
			
		||||
    #[error("engine: {0:?}")]
 | 
			
		||||
    Engine(KclErrorDetails),
 | 
			
		||||
    #[error("internal error, please report to KittyCAD team: {0:?}")]
 | 
			
		||||
    Internal(KclErrorDetails),
 | 
			
		||||
    #[error("lexical: {details:?}")]
 | 
			
		||||
    Lexical { details: KclErrorDetails },
 | 
			
		||||
    #[error("syntax: {details:?}")]
 | 
			
		||||
    Syntax { details: KclErrorDetails },
 | 
			
		||||
    #[error("semantic: {details:?}")]
 | 
			
		||||
    Semantic { details: KclErrorDetails },
 | 
			
		||||
    #[error("import cycle: {details:?}")]
 | 
			
		||||
    ImportCycle { details: KclErrorDetails },
 | 
			
		||||
    #[error("type: {details:?}")]
 | 
			
		||||
    Type { details: KclErrorDetails },
 | 
			
		||||
    #[error("i/o: {details:?}")]
 | 
			
		||||
    Io { details: KclErrorDetails },
 | 
			
		||||
    #[error("unexpected: {details:?}")]
 | 
			
		||||
    Unexpected { details: KclErrorDetails },
 | 
			
		||||
    #[error("value already defined: {details:?}")]
 | 
			
		||||
    ValueAlreadyDefined { details: KclErrorDetails },
 | 
			
		||||
    #[error("undefined value: {details:?}")]
 | 
			
		||||
    UndefinedValue { details: KclErrorDetails },
 | 
			
		||||
    #[error("invalid expression: {details:?}")]
 | 
			
		||||
    InvalidExpression { details: KclErrorDetails },
 | 
			
		||||
    #[error("engine: {details:?}")]
 | 
			
		||||
    Engine { details: KclErrorDetails },
 | 
			
		||||
    #[error("internal error, please report to KittyCAD team: {details:?}")]
 | 
			
		||||
    Internal { details: KclErrorDetails },
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<KclErrorWithOutputs> for KclError {
 | 
			
		||||
@ -296,18 +296,18 @@ pub struct ReportWithOutputs {
 | 
			
		||||
impl miette::Diagnostic for ReportWithOutputs {
 | 
			
		||||
    fn code<'a>(&'a self) -> Option<Box<dyn std::fmt::Display + 'a>> {
 | 
			
		||||
        let family = match self.error.error {
 | 
			
		||||
            KclError::Lexical(_) => "Lexical",
 | 
			
		||||
            KclError::Syntax(_) => "Syntax",
 | 
			
		||||
            KclError::Semantic(_) => "Semantic",
 | 
			
		||||
            KclError::ImportCycle(_) => "ImportCycle",
 | 
			
		||||
            KclError::Type(_) => "Type",
 | 
			
		||||
            KclError::Io(_) => "I/O",
 | 
			
		||||
            KclError::Unexpected(_) => "Unexpected",
 | 
			
		||||
            KclError::ValueAlreadyDefined(_) => "ValueAlreadyDefined",
 | 
			
		||||
            KclError::UndefinedValue(_) => "UndefinedValue",
 | 
			
		||||
            KclError::InvalidExpression(_) => "InvalidExpression",
 | 
			
		||||
            KclError::Engine(_) => "Engine",
 | 
			
		||||
            KclError::Internal(_) => "Internal",
 | 
			
		||||
            KclError::Lexical { .. } => "Lexical",
 | 
			
		||||
            KclError::Syntax { .. } => "Syntax",
 | 
			
		||||
            KclError::Semantic { .. } => "Semantic",
 | 
			
		||||
            KclError::ImportCycle { .. } => "ImportCycle",
 | 
			
		||||
            KclError::Type { .. } => "Type",
 | 
			
		||||
            KclError::Io { .. } => "I/O",
 | 
			
		||||
            KclError::Unexpected { .. } => "Unexpected",
 | 
			
		||||
            KclError::ValueAlreadyDefined { .. } => "ValueAlreadyDefined",
 | 
			
		||||
            KclError::UndefinedValue { .. } => "UndefinedValue",
 | 
			
		||||
            KclError::InvalidExpression { .. } => "InvalidExpression",
 | 
			
		||||
            KclError::Engine { .. } => "Engine",
 | 
			
		||||
            KclError::Internal { .. } => "Internal",
 | 
			
		||||
        };
 | 
			
		||||
        let error_string = format!("KCL {family} error");
 | 
			
		||||
        Some(Box::new(error_string))
 | 
			
		||||
@ -346,18 +346,18 @@ pub struct Report {
 | 
			
		||||
impl miette::Diagnostic for Report {
 | 
			
		||||
    fn code<'a>(&'a self) -> Option<Box<dyn std::fmt::Display + 'a>> {
 | 
			
		||||
        let family = match self.error {
 | 
			
		||||
            KclError::Lexical(_) => "Lexical",
 | 
			
		||||
            KclError::Syntax(_) => "Syntax",
 | 
			
		||||
            KclError::Semantic(_) => "Semantic",
 | 
			
		||||
            KclError::ImportCycle(_) => "ImportCycle",
 | 
			
		||||
            KclError::Type(_) => "Type",
 | 
			
		||||
            KclError::Io(_) => "I/O",
 | 
			
		||||
            KclError::Unexpected(_) => "Unexpected",
 | 
			
		||||
            KclError::ValueAlreadyDefined(_) => "ValueAlreadyDefined",
 | 
			
		||||
            KclError::UndefinedValue(_) => "UndefinedValue",
 | 
			
		||||
            KclError::InvalidExpression(_) => "InvalidExpression",
 | 
			
		||||
            KclError::Engine(_) => "Engine",
 | 
			
		||||
            KclError::Internal(_) => "Internal",
 | 
			
		||||
            KclError::Lexical { .. } => "Lexical",
 | 
			
		||||
            KclError::Syntax { .. } => "Syntax",
 | 
			
		||||
            KclError::Semantic { .. } => "Semantic",
 | 
			
		||||
            KclError::ImportCycle { .. } => "ImportCycle",
 | 
			
		||||
            KclError::Type { .. } => "Type",
 | 
			
		||||
            KclError::Io { .. } => "I/O",
 | 
			
		||||
            KclError::Unexpected { .. } => "Unexpected",
 | 
			
		||||
            KclError::ValueAlreadyDefined { .. } => "ValueAlreadyDefined",
 | 
			
		||||
            KclError::UndefinedValue { .. } => "UndefinedValue",
 | 
			
		||||
            KclError::InvalidExpression { .. } => "InvalidExpression",
 | 
			
		||||
            KclError::Engine { .. } => "Engine",
 | 
			
		||||
            KclError::Internal { .. } => "Internal",
 | 
			
		||||
        };
 | 
			
		||||
        let error_string = format!("KCL {family} error");
 | 
			
		||||
        Some(Box::new(error_string))
 | 
			
		||||
@ -410,11 +410,53 @@ impl KclErrorDetails {
 | 
			
		||||
 | 
			
		||||
impl KclError {
 | 
			
		||||
    pub fn internal(message: String) -> KclError {
 | 
			
		||||
        KclError::Internal(KclErrorDetails {
 | 
			
		||||
            source_ranges: Default::default(),
 | 
			
		||||
            backtrace: Default::default(),
 | 
			
		||||
            message,
 | 
			
		||||
        })
 | 
			
		||||
        KclError::Internal {
 | 
			
		||||
            details: KclErrorDetails {
 | 
			
		||||
                source_ranges: Default::default(),
 | 
			
		||||
                backtrace: Default::default(),
 | 
			
		||||
                message,
 | 
			
		||||
            },
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn new_internal(details: KclErrorDetails) -> KclError {
 | 
			
		||||
        KclError::Internal { details }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn new_import_cycle(details: KclErrorDetails) -> KclError {
 | 
			
		||||
        KclError::ImportCycle { details }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn new_semantic(details: KclErrorDetails) -> KclError {
 | 
			
		||||
        KclError::Semantic { details }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn new_value_already_defined(details: KclErrorDetails) -> KclError {
 | 
			
		||||
        KclError::ValueAlreadyDefined { details }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn new_syntax(details: KclErrorDetails) -> KclError {
 | 
			
		||||
        KclError::Syntax { details }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn new_io(details: KclErrorDetails) -> KclError {
 | 
			
		||||
        KclError::Io { details }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn new_engine(details: KclErrorDetails) -> KclError {
 | 
			
		||||
        KclError::Engine { details }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn new_lexical(details: KclErrorDetails) -> KclError {
 | 
			
		||||
        KclError::Lexical { details }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn new_undefined_value(details: KclErrorDetails) -> KclError {
 | 
			
		||||
        KclError::UndefinedValue { details }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn new_type(details: KclErrorDetails) -> KclError {
 | 
			
		||||
        KclError::Type { details }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Get the error message.
 | 
			
		||||
@ -424,88 +466,88 @@ impl KclError {
 | 
			
		||||
 | 
			
		||||
    pub fn error_type(&self) -> &'static str {
 | 
			
		||||
        match self {
 | 
			
		||||
            KclError::Lexical(_) => "lexical",
 | 
			
		||||
            KclError::Syntax(_) => "syntax",
 | 
			
		||||
            KclError::Semantic(_) => "semantic",
 | 
			
		||||
            KclError::ImportCycle(_) => "import cycle",
 | 
			
		||||
            KclError::Type(_) => "type",
 | 
			
		||||
            KclError::Io(_) => "i/o",
 | 
			
		||||
            KclError::Unexpected(_) => "unexpected",
 | 
			
		||||
            KclError::ValueAlreadyDefined(_) => "value already defined",
 | 
			
		||||
            KclError::UndefinedValue(_) => "undefined value",
 | 
			
		||||
            KclError::InvalidExpression(_) => "invalid expression",
 | 
			
		||||
            KclError::Engine(_) => "engine",
 | 
			
		||||
            KclError::Internal(_) => "internal",
 | 
			
		||||
            KclError::Lexical { .. } => "lexical",
 | 
			
		||||
            KclError::Syntax { .. } => "syntax",
 | 
			
		||||
            KclError::Semantic { .. } => "semantic",
 | 
			
		||||
            KclError::ImportCycle { .. } => "import cycle",
 | 
			
		||||
            KclError::Type { .. } => "type",
 | 
			
		||||
            KclError::Io { .. } => "i/o",
 | 
			
		||||
            KclError::Unexpected { .. } => "unexpected",
 | 
			
		||||
            KclError::ValueAlreadyDefined { .. } => "value already defined",
 | 
			
		||||
            KclError::UndefinedValue { .. } => "undefined value",
 | 
			
		||||
            KclError::InvalidExpression { .. } => "invalid expression",
 | 
			
		||||
            KclError::Engine { .. } => "engine",
 | 
			
		||||
            KclError::Internal { .. } => "internal",
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn source_ranges(&self) -> Vec<SourceRange> {
 | 
			
		||||
        match &self {
 | 
			
		||||
            KclError::Lexical(e) => e.source_ranges.clone(),
 | 
			
		||||
            KclError::Syntax(e) => e.source_ranges.clone(),
 | 
			
		||||
            KclError::Semantic(e) => e.source_ranges.clone(),
 | 
			
		||||
            KclError::ImportCycle(e) => e.source_ranges.clone(),
 | 
			
		||||
            KclError::Type(e) => e.source_ranges.clone(),
 | 
			
		||||
            KclError::Io(e) => e.source_ranges.clone(),
 | 
			
		||||
            KclError::Unexpected(e) => e.source_ranges.clone(),
 | 
			
		||||
            KclError::ValueAlreadyDefined(e) => e.source_ranges.clone(),
 | 
			
		||||
            KclError::UndefinedValue(e) => e.source_ranges.clone(),
 | 
			
		||||
            KclError::InvalidExpression(e) => e.source_ranges.clone(),
 | 
			
		||||
            KclError::Engine(e) => e.source_ranges.clone(),
 | 
			
		||||
            KclError::Internal(e) => e.source_ranges.clone(),
 | 
			
		||||
            KclError::Lexical { details: e } => e.source_ranges.clone(),
 | 
			
		||||
            KclError::Syntax { details: e } => e.source_ranges.clone(),
 | 
			
		||||
            KclError::Semantic { details: e } => e.source_ranges.clone(),
 | 
			
		||||
            KclError::ImportCycle { details: e } => e.source_ranges.clone(),
 | 
			
		||||
            KclError::Type { details: e } => e.source_ranges.clone(),
 | 
			
		||||
            KclError::Io { details: e } => e.source_ranges.clone(),
 | 
			
		||||
            KclError::Unexpected { details: e } => e.source_ranges.clone(),
 | 
			
		||||
            KclError::ValueAlreadyDefined { details: e } => e.source_ranges.clone(),
 | 
			
		||||
            KclError::UndefinedValue { details: e } => e.source_ranges.clone(),
 | 
			
		||||
            KclError::InvalidExpression { details: e } => e.source_ranges.clone(),
 | 
			
		||||
            KclError::Engine { details: e } => e.source_ranges.clone(),
 | 
			
		||||
            KclError::Internal { details: e } => e.source_ranges.clone(),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Get the inner error message.
 | 
			
		||||
    pub fn message(&self) -> &str {
 | 
			
		||||
        match &self {
 | 
			
		||||
            KclError::Lexical(e) => &e.message,
 | 
			
		||||
            KclError::Syntax(e) => &e.message,
 | 
			
		||||
            KclError::Semantic(e) => &e.message,
 | 
			
		||||
            KclError::ImportCycle(e) => &e.message,
 | 
			
		||||
            KclError::Type(e) => &e.message,
 | 
			
		||||
            KclError::Io(e) => &e.message,
 | 
			
		||||
            KclError::Unexpected(e) => &e.message,
 | 
			
		||||
            KclError::ValueAlreadyDefined(e) => &e.message,
 | 
			
		||||
            KclError::UndefinedValue(e) => &e.message,
 | 
			
		||||
            KclError::InvalidExpression(e) => &e.message,
 | 
			
		||||
            KclError::Engine(e) => &e.message,
 | 
			
		||||
            KclError::Internal(e) => &e.message,
 | 
			
		||||
            KclError::Lexical { details: e } => &e.message,
 | 
			
		||||
            KclError::Syntax { details: e } => &e.message,
 | 
			
		||||
            KclError::Semantic { details: e } => &e.message,
 | 
			
		||||
            KclError::ImportCycle { details: e } => &e.message,
 | 
			
		||||
            KclError::Type { details: e } => &e.message,
 | 
			
		||||
            KclError::Io { details: e } => &e.message,
 | 
			
		||||
            KclError::Unexpected { details: e } => &e.message,
 | 
			
		||||
            KclError::ValueAlreadyDefined { details: e } => &e.message,
 | 
			
		||||
            KclError::UndefinedValue { details: e } => &e.message,
 | 
			
		||||
            KclError::InvalidExpression { details: e } => &e.message,
 | 
			
		||||
            KclError::Engine { details: e } => &e.message,
 | 
			
		||||
            KclError::Internal { details: e } => &e.message,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn backtrace(&self) -> Vec<BacktraceItem> {
 | 
			
		||||
        match self {
 | 
			
		||||
            KclError::Lexical(e)
 | 
			
		||||
            | KclError::Syntax(e)
 | 
			
		||||
            | KclError::Semantic(e)
 | 
			
		||||
            | KclError::ImportCycle(e)
 | 
			
		||||
            | KclError::Type(e)
 | 
			
		||||
            | KclError::Io(e)
 | 
			
		||||
            | KclError::Unexpected(e)
 | 
			
		||||
            | KclError::ValueAlreadyDefined(e)
 | 
			
		||||
            | KclError::UndefinedValue(e)
 | 
			
		||||
            | KclError::InvalidExpression(e)
 | 
			
		||||
            | KclError::Engine(e)
 | 
			
		||||
            | KclError::Internal(e) => e.backtrace.clone(),
 | 
			
		||||
            KclError::Lexical { details: e }
 | 
			
		||||
            | KclError::Syntax { details: e }
 | 
			
		||||
            | KclError::Semantic { details: e }
 | 
			
		||||
            | KclError::ImportCycle { details: e }
 | 
			
		||||
            | KclError::Type { details: e }
 | 
			
		||||
            | KclError::Io { details: e }
 | 
			
		||||
            | KclError::Unexpected { details: e }
 | 
			
		||||
            | KclError::ValueAlreadyDefined { details: e }
 | 
			
		||||
            | KclError::UndefinedValue { details: e }
 | 
			
		||||
            | KclError::InvalidExpression { details: e }
 | 
			
		||||
            | KclError::Engine { details: e }
 | 
			
		||||
            | KclError::Internal { details: e } => e.backtrace.clone(),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub(crate) fn override_source_ranges(&self, source_ranges: Vec<SourceRange>) -> Self {
 | 
			
		||||
        let mut new = self.clone();
 | 
			
		||||
        match &mut new {
 | 
			
		||||
            KclError::Lexical(e)
 | 
			
		||||
            | KclError::Syntax(e)
 | 
			
		||||
            | KclError::Semantic(e)
 | 
			
		||||
            | KclError::ImportCycle(e)
 | 
			
		||||
            | KclError::Type(e)
 | 
			
		||||
            | KclError::Io(e)
 | 
			
		||||
            | KclError::Unexpected(e)
 | 
			
		||||
            | KclError::ValueAlreadyDefined(e)
 | 
			
		||||
            | KclError::UndefinedValue(e)
 | 
			
		||||
            | KclError::InvalidExpression(e)
 | 
			
		||||
            | KclError::Engine(e)
 | 
			
		||||
            | KclError::Internal(e) => {
 | 
			
		||||
            KclError::Lexical { details: e }
 | 
			
		||||
            | KclError::Syntax { details: e }
 | 
			
		||||
            | KclError::Semantic { details: e }
 | 
			
		||||
            | KclError::ImportCycle { details: e }
 | 
			
		||||
            | KclError::Type { details: e }
 | 
			
		||||
            | KclError::Io { details: e }
 | 
			
		||||
            | KclError::Unexpected { details: e }
 | 
			
		||||
            | KclError::ValueAlreadyDefined { details: e }
 | 
			
		||||
            | KclError::UndefinedValue { details: e }
 | 
			
		||||
            | KclError::InvalidExpression { details: e }
 | 
			
		||||
            | KclError::Engine { details: e }
 | 
			
		||||
            | KclError::Internal { details: e } => {
 | 
			
		||||
                e.backtrace = source_ranges
 | 
			
		||||
                    .iter()
 | 
			
		||||
                    .map(|s| BacktraceItem {
 | 
			
		||||
@ -523,18 +565,18 @@ impl KclError {
 | 
			
		||||
    pub(crate) fn set_last_backtrace_fn_name(&self, last_fn_name: Option<String>) -> Self {
 | 
			
		||||
        let mut new = self.clone();
 | 
			
		||||
        match &mut new {
 | 
			
		||||
            KclError::Lexical(e)
 | 
			
		||||
            | KclError::Syntax(e)
 | 
			
		||||
            | KclError::Semantic(e)
 | 
			
		||||
            | KclError::ImportCycle(e)
 | 
			
		||||
            | KclError::Type(e)
 | 
			
		||||
            | KclError::Io(e)
 | 
			
		||||
            | KclError::Unexpected(e)
 | 
			
		||||
            | KclError::ValueAlreadyDefined(e)
 | 
			
		||||
            | KclError::UndefinedValue(e)
 | 
			
		||||
            | KclError::InvalidExpression(e)
 | 
			
		||||
            | KclError::Engine(e)
 | 
			
		||||
            | KclError::Internal(e) => {
 | 
			
		||||
            KclError::Lexical { details: e }
 | 
			
		||||
            | KclError::Syntax { details: e }
 | 
			
		||||
            | KclError::Semantic { details: e }
 | 
			
		||||
            | KclError::ImportCycle { details: e }
 | 
			
		||||
            | KclError::Type { details: e }
 | 
			
		||||
            | KclError::Io { details: e }
 | 
			
		||||
            | KclError::Unexpected { details: e }
 | 
			
		||||
            | KclError::ValueAlreadyDefined { details: e }
 | 
			
		||||
            | KclError::UndefinedValue { details: e }
 | 
			
		||||
            | KclError::InvalidExpression { details: e }
 | 
			
		||||
            | KclError::Engine { details: e }
 | 
			
		||||
            | KclError::Internal { details: e } => {
 | 
			
		||||
                if let Some(item) = e.backtrace.last_mut() {
 | 
			
		||||
                    item.fn_name = last_fn_name;
 | 
			
		||||
                }
 | 
			
		||||
@ -547,18 +589,18 @@ impl KclError {
 | 
			
		||||
    pub(crate) fn add_unwind_location(&self, last_fn_name: Option<String>, source_range: SourceRange) -> Self {
 | 
			
		||||
        let mut new = self.clone();
 | 
			
		||||
        match &mut new {
 | 
			
		||||
            KclError::Lexical(e)
 | 
			
		||||
            | KclError::Syntax(e)
 | 
			
		||||
            | KclError::Semantic(e)
 | 
			
		||||
            | KclError::ImportCycle(e)
 | 
			
		||||
            | KclError::Type(e)
 | 
			
		||||
            | KclError::Io(e)
 | 
			
		||||
            | KclError::Unexpected(e)
 | 
			
		||||
            | KclError::ValueAlreadyDefined(e)
 | 
			
		||||
            | KclError::UndefinedValue(e)
 | 
			
		||||
            | KclError::InvalidExpression(e)
 | 
			
		||||
            | KclError::Engine(e)
 | 
			
		||||
            | KclError::Internal(e) => {
 | 
			
		||||
            KclError::Lexical { details: e }
 | 
			
		||||
            | KclError::Syntax { details: e }
 | 
			
		||||
            | KclError::Semantic { details: e }
 | 
			
		||||
            | KclError::ImportCycle { details: e }
 | 
			
		||||
            | KclError::Type { details: e }
 | 
			
		||||
            | KclError::Io { details: e }
 | 
			
		||||
            | KclError::Unexpected { details: e }
 | 
			
		||||
            | KclError::ValueAlreadyDefined { details: e }
 | 
			
		||||
            | KclError::UndefinedValue { details: e }
 | 
			
		||||
            | KclError::InvalidExpression { details: e }
 | 
			
		||||
            | KclError::Engine { details: e }
 | 
			
		||||
            | KclError::Internal { details: e } => {
 | 
			
		||||
                if let Some(item) = e.backtrace.last_mut() {
 | 
			
		||||
                    item.fn_name = last_fn_name;
 | 
			
		||||
                }
 | 
			
		||||
@ -645,7 +687,7 @@ impl From<String> for KclError {
 | 
			
		||||
#[cfg(feature = "pyo3")]
 | 
			
		||||
impl From<pyo3::PyErr> for KclError {
 | 
			
		||||
    fn from(error: pyo3::PyErr) -> Self {
 | 
			
		||||
        KclError::Internal(KclErrorDetails {
 | 
			
		||||
        KclError::new_internal(KclErrorDetails {
 | 
			
		||||
            source_ranges: vec![],
 | 
			
		||||
            backtrace: Default::default(),
 | 
			
		||||
            message: error.to_string(),
 | 
			
		||||
 | 
			
		||||
@ -70,7 +70,7 @@ pub(super) fn expect_properties<'a>(
 | 
			
		||||
) -> Result<&'a [Node<ObjectProperty>], KclError> {
 | 
			
		||||
    assert_eq!(annotation.name().unwrap(), for_key);
 | 
			
		||||
    Ok(&**annotation.properties.as_ref().ok_or_else(|| {
 | 
			
		||||
        KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
        KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
            format!("Empty `{for_key}` annotation"),
 | 
			
		||||
            vec![annotation.as_source_range()],
 | 
			
		||||
        ))
 | 
			
		||||
@ -84,7 +84,7 @@ pub(super) fn expect_ident(expr: &Expr) -> Result<&str, KclError> {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Err(KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
    Err(KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
        "Unexpected settings value, expected a simple name, e.g., `mm`".to_owned(),
 | 
			
		||||
        vec![expr.into()],
 | 
			
		||||
    )))
 | 
			
		||||
@ -98,7 +98,7 @@ pub(super) fn expect_number(expr: &Expr) -> Result<String, KclError> {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Err(KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
    Err(KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
        "Unexpected settings value, expected a number, e.g., `1.0`".to_owned(),
 | 
			
		||||
        vec![expr.into()],
 | 
			
		||||
    )))
 | 
			
		||||
@ -113,7 +113,7 @@ pub(super) fn get_impl(annotations: &[Node<Annotation>], source_range: SourceRan
 | 
			
		||||
            if &*p.key.name == IMPL {
 | 
			
		||||
                if let Some(s) = p.value.ident_name() {
 | 
			
		||||
                    return Impl::from_str(s).map(Some).map_err(|_| {
 | 
			
		||||
                        KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
                        KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
                            format!(
 | 
			
		||||
                                "Invalid value for {} attribute, expected one of: {}",
 | 
			
		||||
                                IMPL,
 | 
			
		||||
@ -139,7 +139,7 @@ impl UnitLen {
 | 
			
		||||
            "inch" | "in" => Ok(UnitLen::Inches),
 | 
			
		||||
            "ft" => Ok(UnitLen::Feet),
 | 
			
		||||
            "yd" => Ok(UnitLen::Yards),
 | 
			
		||||
            value => Err(KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
            value => Err(KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
                format!(
 | 
			
		||||
                    "Unexpected value for length units: `{value}`; expected one of `mm`, `cm`, `m`, `in`, `ft`, `yd`"
 | 
			
		||||
                ),
 | 
			
		||||
@ -154,7 +154,7 @@ impl UnitAngle {
 | 
			
		||||
        match s {
 | 
			
		||||
            "deg" => Ok(UnitAngle::Degrees),
 | 
			
		||||
            "rad" => Ok(UnitAngle::Radians),
 | 
			
		||||
            value => Err(KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
            value => Err(KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
                format!("Unexpected value for angle units: `{value}`; expected one of `deg`, `rad`"),
 | 
			
		||||
                vec![source_range],
 | 
			
		||||
            ))),
 | 
			
		||||
 | 
			
		||||
@ -24,7 +24,7 @@ macro_rules! internal_error {
 | 
			
		||||
    ($range:expr, $($rest:tt)*) => {{
 | 
			
		||||
        let message = format!($($rest)*);
 | 
			
		||||
        debug_assert!(false, "{}", &message);
 | 
			
		||||
        return Err(KclError::Internal(KclErrorDetails::new(message, vec![$range])));
 | 
			
		||||
        return Err(KclError::new_internal(KclErrorDetails::new(message, vec![$range])));
 | 
			
		||||
    }};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -949,7 +949,7 @@ fn artifacts_to_update(
 | 
			
		||||
        ModelingCmd::StartPath(_) => {
 | 
			
		||||
            let mut return_arr = Vec::new();
 | 
			
		||||
            let current_plane_id = path_to_plane_id_map.get(&artifact_command.cmd_id).ok_or_else(|| {
 | 
			
		||||
                KclError::Internal(KclErrorDetails::new(
 | 
			
		||||
                KclError::new_internal(KclErrorDetails::new(
 | 
			
		||||
                    format!("Expected a current plane ID when processing StartPath command, but we have none: {id:?}"),
 | 
			
		||||
                    vec![range],
 | 
			
		||||
                ))
 | 
			
		||||
@ -1137,7 +1137,7 @@ fn artifacts_to_update(
 | 
			
		||||
                // TODO: Using the first one.  Make sure to revisit this
 | 
			
		||||
                // choice, don't think it matters for now.
 | 
			
		||||
                path_id: ArtifactId::new(*loft_cmd.section_ids.first().ok_or_else(|| {
 | 
			
		||||
                    KclError::Internal(KclErrorDetails::new(
 | 
			
		||||
                    KclError::new_internal(KclErrorDetails::new(
 | 
			
		||||
                        format!("Expected at least one section ID in Loft command: {id:?}; cmd={cmd:?}"),
 | 
			
		||||
                        vec![range],
 | 
			
		||||
                    ))
 | 
			
		||||
@ -1180,7 +1180,7 @@ fn artifacts_to_update(
 | 
			
		||||
                };
 | 
			
		||||
                last_path = Some(path);
 | 
			
		||||
                let path_sweep_id = path.sweep_id.ok_or_else(|| {
 | 
			
		||||
                    KclError::Internal(KclErrorDetails::new(
 | 
			
		||||
                    KclError::new_internal(KclErrorDetails::new(
 | 
			
		||||
                        format!(
 | 
			
		||||
                            "Expected a sweep ID on the path when processing Solid3dGetExtrusionFaceInfo command, but we have none: {id:?}, {path:?}"
 | 
			
		||||
                        ),
 | 
			
		||||
@ -1234,7 +1234,7 @@ fn artifacts_to_update(
 | 
			
		||||
                        continue;
 | 
			
		||||
                    };
 | 
			
		||||
                    let path_sweep_id = path.sweep_id.ok_or_else(|| {
 | 
			
		||||
                        KclError::Internal(KclErrorDetails::new(
 | 
			
		||||
                        KclError::new_internal(KclErrorDetails::new(
 | 
			
		||||
                            format!(
 | 
			
		||||
                                "Expected a sweep ID on the path when processing last path's Solid3dGetExtrusionFaceInfo command, but we have none: {id:?}, {path:?}"
 | 
			
		||||
                            ),
 | 
			
		||||
 | 
			
		||||
@ -131,7 +131,7 @@ impl ExecutorContext {
 | 
			
		||||
            match statement {
 | 
			
		||||
                BodyItem::ImportStatement(import_stmt) => {
 | 
			
		||||
                    if !matches!(body_type, BodyType::Root) {
 | 
			
		||||
                        return Err(KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
                        return Err(KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
                            "Imports are only supported at the top-level of a file.".to_owned(),
 | 
			
		||||
                            vec![import_stmt.into()],
 | 
			
		||||
                        )));
 | 
			
		||||
@ -164,7 +164,7 @@ impl ExecutorContext {
 | 
			
		||||
                                let mut mod_value = mem.get_from(&mod_name, env_ref, import_item.into(), 0).cloned();
 | 
			
		||||
 | 
			
		||||
                                if value.is_err() && ty.is_err() && mod_value.is_err() {
 | 
			
		||||
                                    return Err(KclError::UndefinedValue(KclErrorDetails::new(
 | 
			
		||||
                                    return Err(KclError::new_undefined_value(KclErrorDetails::new(
 | 
			
		||||
                                        format!("{} is not defined in module", import_item.name.name),
 | 
			
		||||
                                        vec![SourceRange::from(&import_item.name)],
 | 
			
		||||
                                    )));
 | 
			
		||||
@ -172,7 +172,7 @@ impl ExecutorContext {
 | 
			
		||||
 | 
			
		||||
                                // 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::Semantic(KclErrorDetails::new(
 | 
			
		||||
                                    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
 | 
			
		||||
@ -182,7 +182,7 @@ impl ExecutorContext {
 | 
			
		||||
                                }
 | 
			
		||||
 | 
			
		||||
                                if ty.is_ok() && !module_exports.contains(&ty_name) {
 | 
			
		||||
                                    ty = Err(KclError::Semantic(KclErrorDetails::new(format!(
 | 
			
		||||
                                    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
 | 
			
		||||
                                    ),
 | 
			
		||||
@ -190,7 +190,7 @@ impl ExecutorContext {
 | 
			
		||||
                                }
 | 
			
		||||
 | 
			
		||||
                                if mod_value.is_ok() && !module_exports.contains(&mod_name) {
 | 
			
		||||
                                    mod_value = Err(KclError::Semantic(KclErrorDetails::new(format!(
 | 
			
		||||
                                    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
 | 
			
		||||
                                    ),
 | 
			
		||||
@ -253,7 +253,7 @@ impl ExecutorContext {
 | 
			
		||||
                                    .memory
 | 
			
		||||
                                    .get_from(name, env_ref, source_range, 0)
 | 
			
		||||
                                    .map_err(|_err| {
 | 
			
		||||
                                        KclError::Internal(KclErrorDetails::new(
 | 
			
		||||
                                        KclError::new_internal(KclErrorDetails::new(
 | 
			
		||||
                                            format!("{} is not defined in module (but was exported?)", name),
 | 
			
		||||
                                            vec![source_range],
 | 
			
		||||
                                        ))
 | 
			
		||||
@ -336,7 +336,7 @@ impl ExecutorContext {
 | 
			
		||||
                            let std_path = match &exec_state.mod_local.path {
 | 
			
		||||
                                ModulePath::Std { value } => value,
 | 
			
		||||
                                ModulePath::Local { .. } | ModulePath::Main => {
 | 
			
		||||
                                    return Err(KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
                                    return Err(KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
                                        "User-defined types are not yet supported.".to_owned(),
 | 
			
		||||
                                        vec![metadata.source_range],
 | 
			
		||||
                                    )));
 | 
			
		||||
@ -352,7 +352,7 @@ impl ExecutorContext {
 | 
			
		||||
                                .mut_stack()
 | 
			
		||||
                                .add(name_in_mem.clone(), value, metadata.source_range)
 | 
			
		||||
                                .map_err(|_| {
 | 
			
		||||
                                    KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
                                    KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
                                        format!("Redefinition of type {}.", ty.name.name),
 | 
			
		||||
                                        vec![metadata.source_range],
 | 
			
		||||
                                    ))
 | 
			
		||||
@ -373,7 +373,7 @@ impl ExecutorContext {
 | 
			
		||||
                                            exec_state,
 | 
			
		||||
                                            metadata.source_range,
 | 
			
		||||
                                        )
 | 
			
		||||
                                        .map_err(|e| KclError::Semantic(e.into()))?,
 | 
			
		||||
                                        .map_err(|e| KclError::new_semantic(e.into()))?,
 | 
			
		||||
                                    ),
 | 
			
		||||
                                    meta: vec![metadata],
 | 
			
		||||
                                };
 | 
			
		||||
@ -382,7 +382,7 @@ impl ExecutorContext {
 | 
			
		||||
                                    .mut_stack()
 | 
			
		||||
                                    .add(name_in_mem.clone(), value, metadata.source_range)
 | 
			
		||||
                                    .map_err(|_| {
 | 
			
		||||
                                        KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
                                        KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
                                            format!("Redefinition of type {}.", ty.name.name),
 | 
			
		||||
                                            vec![metadata.source_range],
 | 
			
		||||
                                        ))
 | 
			
		||||
@ -393,7 +393,7 @@ impl ExecutorContext {
 | 
			
		||||
                                }
 | 
			
		||||
                            }
 | 
			
		||||
                            None => {
 | 
			
		||||
                                return Err(KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
                                return Err(KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
                                    "User-defined types are not yet supported.".to_owned(),
 | 
			
		||||
                                    vec![metadata.source_range],
 | 
			
		||||
                                )))
 | 
			
		||||
@ -407,7 +407,7 @@ impl ExecutorContext {
 | 
			
		||||
                    let metadata = Metadata::from(return_statement);
 | 
			
		||||
 | 
			
		||||
                    if matches!(body_type, BodyType::Root) {
 | 
			
		||||
                        return Err(KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
                        return Err(KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
                            "Cannot return from outside a function.".to_owned(),
 | 
			
		||||
                            vec![metadata.source_range],
 | 
			
		||||
                        )));
 | 
			
		||||
@ -426,7 +426,7 @@ impl ExecutorContext {
 | 
			
		||||
                        .mut_stack()
 | 
			
		||||
                        .add(memory::RETURN_NAME.to_owned(), value, metadata.source_range)
 | 
			
		||||
                        .map_err(|_| {
 | 
			
		||||
                            KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
                            KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
                                "Multiple returns from a single function.".to_owned(),
 | 
			
		||||
                                vec![metadata.source_range],
 | 
			
		||||
                            ))
 | 
			
		||||
@ -531,7 +531,7 @@ impl ExecutorContext {
 | 
			
		||||
                    *cache = Some((val, er, items.clone()));
 | 
			
		||||
                    (er, items)
 | 
			
		||||
                }),
 | 
			
		||||
            ModuleRepr::Foreign(geom, _) => Err(KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
            ModuleRepr::Foreign(geom, _) => Err(KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
                "Cannot import items from foreign modules".to_owned(),
 | 
			
		||||
                vec![geom.source_range],
 | 
			
		||||
            ))),
 | 
			
		||||
@ -605,12 +605,12 @@ impl ExecutorContext {
 | 
			
		||||
        exec_state.global.mod_loader.leave_module(path);
 | 
			
		||||
 | 
			
		||||
        result.map_err(|err| {
 | 
			
		||||
            if let KclError::ImportCycle(_) = err {
 | 
			
		||||
            if let KclError::ImportCycle { .. } = err {
 | 
			
		||||
                // It was an import cycle.  Keep the original message.
 | 
			
		||||
                err.override_source_ranges(vec![source_range])
 | 
			
		||||
            } else {
 | 
			
		||||
                // TODO would be great to have line/column for the underlying error here
 | 
			
		||||
                KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
                KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
                    format!(
 | 
			
		||||
                        "Error loading imported file ({path}). Open it to view more details.\n  {}",
 | 
			
		||||
                        err.message()
 | 
			
		||||
@ -677,7 +677,7 @@ impl ExecutorContext {
 | 
			
		||||
                            meta: vec![metadata.to_owned()],
 | 
			
		||||
                        }
 | 
			
		||||
                    } else {
 | 
			
		||||
                        return Err(KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
                        return Err(KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
                            "Rust implementation of functions is restricted to the standard library".to_owned(),
 | 
			
		||||
                            vec![metadata.source_range],
 | 
			
		||||
                        )));
 | 
			
		||||
@ -704,7 +704,7 @@ impl ExecutorContext {
 | 
			
		||||
                        "you cannot declare variable {name} as %, because % can only be used in function calls"
 | 
			
		||||
                    );
 | 
			
		||||
 | 
			
		||||
                    return Err(KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
                    return Err(KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
                        message,
 | 
			
		||||
                        vec![pipe_substitution.into()],
 | 
			
		||||
                    )));
 | 
			
		||||
@ -712,7 +712,7 @@ impl ExecutorContext {
 | 
			
		||||
                StatementKind::Expression => match exec_state.mod_local.pipe_value.clone() {
 | 
			
		||||
                    Some(x) => x,
 | 
			
		||||
                    None => {
 | 
			
		||||
                        return Err(KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
                        return Err(KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
                            "cannot use % outside a pipe expression".to_owned(),
 | 
			
		||||
                            vec![pipe_substitution.into()],
 | 
			
		||||
                        )));
 | 
			
		||||
@ -761,7 +761,7 @@ fn apply_ascription(
 | 
			
		||||
    source_range: SourceRange,
 | 
			
		||||
) -> Result<KclValue, KclError> {
 | 
			
		||||
    let ty = RuntimeType::from_parsed(ty.inner.clone(), exec_state, value.into())
 | 
			
		||||
        .map_err(|e| KclError::Semantic(e.into()))?;
 | 
			
		||||
        .map_err(|e| KclError::new_semantic(e.into()))?;
 | 
			
		||||
 | 
			
		||||
    value.coerce(&ty, false, exec_state).map_err(|_| {
 | 
			
		||||
        let suggestion = if ty == RuntimeType::length() {
 | 
			
		||||
@ -771,7 +771,7 @@ fn apply_ascription(
 | 
			
		||||
        } else {
 | 
			
		||||
            ""
 | 
			
		||||
        };
 | 
			
		||||
        KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
        KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
            format!(
 | 
			
		||||
                "could not coerce value of type {} to type {ty}{suggestion}",
 | 
			
		||||
                value.human_friendly_type()
 | 
			
		||||
@ -804,7 +804,7 @@ impl Node<Name> {
 | 
			
		||||
        ctx: &ExecutorContext,
 | 
			
		||||
    ) -> Result<&'a KclValue, KclError> {
 | 
			
		||||
        if self.abs_path {
 | 
			
		||||
            return Err(KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
            return Err(KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
                "Absolute paths (names beginning with `::` are not yet supported)".to_owned(),
 | 
			
		||||
                self.as_source_ranges(),
 | 
			
		||||
            )));
 | 
			
		||||
@ -825,7 +825,7 @@ impl Node<Name> {
 | 
			
		||||
            let value = match mem_spec {
 | 
			
		||||
                Some((env, exports)) => {
 | 
			
		||||
                    if !exports.contains(&p.name) {
 | 
			
		||||
                        return Err(KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
                        return Err(KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
                            format!("Item {} not found in module's exported items", p.name),
 | 
			
		||||
                            p.as_source_ranges(),
 | 
			
		||||
                        )));
 | 
			
		||||
@ -842,7 +842,7 @@ impl Node<Name> {
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            let KclValue::Module { value: module_id, .. } = value else {
 | 
			
		||||
                return Err(KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
                return Err(KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
                    format!(
 | 
			
		||||
                        "Identifier in path must refer to a module, found {}",
 | 
			
		||||
                        value.human_friendly_type()
 | 
			
		||||
@ -888,7 +888,7 @@ impl Node<Name> {
 | 
			
		||||
 | 
			
		||||
        // 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::Semantic(KclErrorDetails::new(
 | 
			
		||||
        Err(KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
            format!("Item {} not found in module's exported items", self.name.name),
 | 
			
		||||
            self.name.as_source_ranges(),
 | 
			
		||||
        )))
 | 
			
		||||
@ -913,14 +913,14 @@ impl Node<MemberExpression> {
 | 
			
		||||
                if let Some(value) = map.get(&property) {
 | 
			
		||||
                    Ok(value.to_owned())
 | 
			
		||||
                } else {
 | 
			
		||||
                    Err(KclError::UndefinedValue(KclErrorDetails::new(
 | 
			
		||||
                    Err(KclError::new_undefined_value(KclErrorDetails::new(
 | 
			
		||||
                        format!("Property '{property}' not found in object"),
 | 
			
		||||
                        vec![self.clone().into()],
 | 
			
		||||
                    )))
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            (KclValue::Object { .. }, Property::String(property), true) => {
 | 
			
		||||
                Err(KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
                Err(KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
                    format!("Cannot index object with string; use dot notation instead, e.g. `obj.{property}`"),
 | 
			
		||||
                    vec![self.clone().into()],
 | 
			
		||||
                )))
 | 
			
		||||
@ -928,7 +928,7 @@ impl Node<MemberExpression> {
 | 
			
		||||
            (KclValue::Object { .. }, p, _) => {
 | 
			
		||||
                let t = p.type_name();
 | 
			
		||||
                let article = article_for(t);
 | 
			
		||||
                Err(KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
                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()],
 | 
			
		||||
                )))
 | 
			
		||||
@ -938,7 +938,7 @@ impl Node<MemberExpression> {
 | 
			
		||||
                if let Some(value) = value_of_arr {
 | 
			
		||||
                    Ok(value.to_owned())
 | 
			
		||||
                } else {
 | 
			
		||||
                    Err(KclError::UndefinedValue(KclErrorDetails::new(
 | 
			
		||||
                    Err(KclError::new_undefined_value(KclErrorDetails::new(
 | 
			
		||||
                        format!("The array doesn't have any item at index {index}"),
 | 
			
		||||
                        vec![self.clone().into()],
 | 
			
		||||
                    )))
 | 
			
		||||
@ -950,7 +950,7 @@ impl Node<MemberExpression> {
 | 
			
		||||
            (KclValue::HomArray { .. }, p, _) => {
 | 
			
		||||
                let t = p.type_name();
 | 
			
		||||
                let article = article_for(t);
 | 
			
		||||
                Err(KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
                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()],
 | 
			
		||||
                )))
 | 
			
		||||
@ -971,7 +971,7 @@ impl Node<MemberExpression> {
 | 
			
		||||
            (being_indexed, _, _) => {
 | 
			
		||||
                let t = being_indexed.human_friendly_type();
 | 
			
		||||
                let article = article_for(&t);
 | 
			
		||||
                Err(KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
                Err(KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
                    format!("Only arrays can be indexed, but you're trying to index {article} {t}"),
 | 
			
		||||
                    vec![self.clone().into()],
 | 
			
		||||
                )))
 | 
			
		||||
@ -1049,7 +1049,7 @@ impl Node<BinaryExpression> {
 | 
			
		||||
                meta: _,
 | 
			
		||||
            } = left_value
 | 
			
		||||
            else {
 | 
			
		||||
                return Err(KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
                return Err(KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
                    format!(
 | 
			
		||||
                        "Cannot apply logical operator to non-boolean value: {}",
 | 
			
		||||
                        left_value.human_friendly_type()
 | 
			
		||||
@ -1062,7 +1062,7 @@ impl Node<BinaryExpression> {
 | 
			
		||||
                meta: _,
 | 
			
		||||
            } = right_value
 | 
			
		||||
            else {
 | 
			
		||||
                return Err(KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
                return Err(KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
                    format!(
 | 
			
		||||
                        "Cannot apply logical operator to non-boolean value: {}",
 | 
			
		||||
                        right_value.human_friendly_type()
 | 
			
		||||
@ -1168,7 +1168,7 @@ impl Node<UnaryExpression> {
 | 
			
		||||
                meta: _,
 | 
			
		||||
            } = value
 | 
			
		||||
            else {
 | 
			
		||||
                return Err(KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
                return Err(KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
                    format!(
 | 
			
		||||
                        "Cannot apply unary operator ! to non-boolean value: {}",
 | 
			
		||||
                        value.human_friendly_type()
 | 
			
		||||
@ -1189,7 +1189,7 @@ impl Node<UnaryExpression> {
 | 
			
		||||
 | 
			
		||||
        let value = &self.argument.get_result(exec_state, ctx).await?;
 | 
			
		||||
        let err = || {
 | 
			
		||||
            KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
            KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
                format!(
 | 
			
		||||
                    "You can only negate numbers, planes, or lines, but this is a {}",
 | 
			
		||||
                    value.human_friendly_type()
 | 
			
		||||
@ -1292,7 +1292,7 @@ pub(crate) async fn execute_pipe_body(
 | 
			
		||||
    ctx: &ExecutorContext,
 | 
			
		||||
) -> Result<KclValue, KclError> {
 | 
			
		||||
    let Some((first, body)) = body.split_first() else {
 | 
			
		||||
        return Err(KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
        return Err(KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
            "Pipe expressions cannot be empty".to_owned(),
 | 
			
		||||
            vec![source_range],
 | 
			
		||||
        )));
 | 
			
		||||
@ -1330,7 +1330,7 @@ async fn inner_execute_pipe_body(
 | 
			
		||||
) -> Result<KclValue, KclError> {
 | 
			
		||||
    for expression in body {
 | 
			
		||||
        if let Expr::TagDeclarator(_) = expression {
 | 
			
		||||
            return Err(KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
            return Err(KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
                format!("This cannot be in a PipeExpression: {:?}", expression),
 | 
			
		||||
                vec![expression.into()],
 | 
			
		||||
            )));
 | 
			
		||||
@ -1404,7 +1404,7 @@ impl Node<ArrayRangeExpression> {
 | 
			
		||||
            .await?;
 | 
			
		||||
        let (start, start_ty) = start_val
 | 
			
		||||
            .as_int_with_ty()
 | 
			
		||||
            .ok_or(KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
            .ok_or(KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
                format!("Expected int but found {}", start_val.human_friendly_type()),
 | 
			
		||||
                vec![self.into()],
 | 
			
		||||
            )))?;
 | 
			
		||||
@ -1412,24 +1412,26 @@ impl Node<ArrayRangeExpression> {
 | 
			
		||||
        let end_val = ctx
 | 
			
		||||
            .execute_expr(&self.end_element, exec_state, &metadata, &[], StatementKind::Expression)
 | 
			
		||||
            .await?;
 | 
			
		||||
        let (end, end_ty) = end_val.as_int_with_ty().ok_or(KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
            format!("Expected int but found {}", end_val.human_friendly_type()),
 | 
			
		||||
            vec![self.into()],
 | 
			
		||||
        )))?;
 | 
			
		||||
        let (end, end_ty) = end_val
 | 
			
		||||
            .as_int_with_ty()
 | 
			
		||||
            .ok_or(KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
                format!("Expected int but found {}", end_val.human_friendly_type()),
 | 
			
		||||
                vec![self.into()],
 | 
			
		||||
            )))?;
 | 
			
		||||
 | 
			
		||||
        if start_ty != end_ty {
 | 
			
		||||
            let start = start_val.as_ty_f64().unwrap_or(TyF64 { n: 0.0, ty: start_ty });
 | 
			
		||||
            let start = fmt::human_display_number(start.n, start.ty);
 | 
			
		||||
            let end = end_val.as_ty_f64().unwrap_or(TyF64 { n: 0.0, ty: end_ty });
 | 
			
		||||
            let end = fmt::human_display_number(end.n, end.ty);
 | 
			
		||||
            return Err(KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
            return Err(KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
                format!("Range start and end must be of the same type, but found {start} and {end}"),
 | 
			
		||||
                vec![self.into()],
 | 
			
		||||
            )));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if end < start {
 | 
			
		||||
            return Err(KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
            return Err(KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
                format!("Range start is greater than range end: {start} .. {end}"),
 | 
			
		||||
                vec![self.into()],
 | 
			
		||||
            )));
 | 
			
		||||
@ -1493,7 +1495,7 @@ fn article_for<S: AsRef<str>>(s: S) -> &'static str {
 | 
			
		||||
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::Semantic(KclErrorDetails::new(
 | 
			
		||||
        KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
            format!("Expected a number, but found {actual_type}",),
 | 
			
		||||
            vec![source_range],
 | 
			
		||||
        ))
 | 
			
		||||
@ -1585,13 +1587,13 @@ impl Property {
 | 
			
		||||
                        if let Some(x) = crate::try_f64_to_usize(value) {
 | 
			
		||||
                            Ok(Property::UInt(x))
 | 
			
		||||
                        } else {
 | 
			
		||||
                            Err(KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
                            Err(KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
                                format!("{value} is not a valid index, indices must be whole numbers >= 0"),
 | 
			
		||||
                                property_sr,
 | 
			
		||||
                            )))
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    _ => Err(KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
                    _ => Err(KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
                        "Only numbers (>= 0) can be indexes".to_owned(),
 | 
			
		||||
                        vec![sr],
 | 
			
		||||
                    ))),
 | 
			
		||||
@ -1602,7 +1604,8 @@ impl Property {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn jvalue_to_prop(value: &KclValue, property_sr: Vec<SourceRange>, name: &str) -> Result<Property, KclError> {
 | 
			
		||||
    let make_err = |message: String| Err::<Property, _>(KclError::Semantic(KclErrorDetails::new(message, property_sr)));
 | 
			
		||||
    let make_err =
 | 
			
		||||
        |message: String| Err::<Property, _>(KclError::new_semantic(KclErrorDetails::new(message, property_sr)));
 | 
			
		||||
    match value {
 | 
			
		||||
        KclValue::Number{value: num, .. } => {
 | 
			
		||||
            let num = *num;
 | 
			
		||||
@ -1846,7 +1849,7 @@ d = b + c
 | 
			
		||||
                crate::engine::conn_mock::EngineConnection::new()
 | 
			
		||||
                    .await
 | 
			
		||||
                    .map_err(|err| {
 | 
			
		||||
                        KclError::Internal(KclErrorDetails::new(
 | 
			
		||||
                        KclError::new_internal(KclErrorDetails::new(
 | 
			
		||||
                            format!("Failed to create mock engine connection: {}", err),
 | 
			
		||||
                            vec![SourceRange::default()],
 | 
			
		||||
                        ))
 | 
			
		||||
 | 
			
		||||
@ -295,7 +295,7 @@ impl Node<CallExpressionKw> {
 | 
			
		||||
                let func = fn_name.get_result(exec_state, ctx).await?.clone();
 | 
			
		||||
 | 
			
		||||
                let Some(fn_src) = func.as_function() else {
 | 
			
		||||
                    return Err(KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
                    return Err(KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
                        "cannot call this because it isn't a function".to_string(),
 | 
			
		||||
                        vec![callsite],
 | 
			
		||||
                    )));
 | 
			
		||||
@ -318,7 +318,7 @@ impl Node<CallExpressionKw> {
 | 
			
		||||
                    if let KclValue::Function { meta, .. } = func {
 | 
			
		||||
                        source_ranges = meta.iter().map(|m| m.source_range).collect();
 | 
			
		||||
                    };
 | 
			
		||||
                    KclError::UndefinedValue(KclErrorDetails::new(
 | 
			
		||||
                    KclError::new_undefined_value(KclErrorDetails::new(
 | 
			
		||||
                        format!("Result of user-defined function {} is undefined", fn_name),
 | 
			
		||||
                        source_ranges,
 | 
			
		||||
                    ))
 | 
			
		||||
@ -500,7 +500,7 @@ fn update_memory_for_tags_of_geometry(result: &mut KclValue, exec_state: &mut Ex
 | 
			
		||||
                    let tag_id = if let Some(t) = value.sketch.tags.get(&tag.name) {
 | 
			
		||||
                        let mut t = t.clone();
 | 
			
		||||
                        let Some(info) = t.get_cur_info() else {
 | 
			
		||||
                            return Err(KclError::Internal(KclErrorDetails::new(
 | 
			
		||||
                            return Err(KclError::new_internal(KclErrorDetails::new(
 | 
			
		||||
                                format!("Tag {} does not have path info", tag.name),
 | 
			
		||||
                                vec![tag.into()],
 | 
			
		||||
                            )));
 | 
			
		||||
@ -605,7 +605,7 @@ fn type_check_params_kw(
 | 
			
		||||
                    arg.value = arg
 | 
			
		||||
                        .value
 | 
			
		||||
                        .coerce(
 | 
			
		||||
                            &RuntimeType::from_parsed(ty.clone(), exec_state, arg.source_range).map_err(|e| KclError::Semantic(e.into()))?,
 | 
			
		||||
                            &RuntimeType::from_parsed(ty.clone(), exec_state, arg.source_range).map_err(|e| KclError::new_semantic(e.into()))?,
 | 
			
		||||
                            true,
 | 
			
		||||
                            exec_state,
 | 
			
		||||
                        )
 | 
			
		||||
@ -619,7 +619,7 @@ fn type_check_params_kw(
 | 
			
		||||
                                // TODO if we have access to the AST for the argument we could choose which example to suggest.
 | 
			
		||||
                                message = format!("{message}\n\nYou may need to add information about the type of the argument, for example:\n  using a numeric suffix: `42{ty}`\n  or using type ascription: `foo(): number({ty})`");
 | 
			
		||||
                            }
 | 
			
		||||
                            KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
                            KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
                                message,
 | 
			
		||||
                                vec![arg.source_range],
 | 
			
		||||
                            ))
 | 
			
		||||
@ -670,7 +670,7 @@ fn type_check_params_kw(
 | 
			
		||||
        let first = errors.next().unwrap();
 | 
			
		||||
        errors.for_each(|e| exec_state.err(e));
 | 
			
		||||
 | 
			
		||||
        return Err(KclError::Semantic(first.into()));
 | 
			
		||||
        return Err(KclError::new_semantic(first.into()));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if let Some(arg) = &mut args.unlabeled {
 | 
			
		||||
@ -680,12 +680,12 @@ fn type_check_params_kw(
 | 
			
		||||
                .value
 | 
			
		||||
                .coerce(
 | 
			
		||||
                    &RuntimeType::from_parsed(ty.clone(), exec_state, arg.1.source_range)
 | 
			
		||||
                        .map_err(|e| KclError::Semantic(e.into()))?,
 | 
			
		||||
                        .map_err(|e| KclError::new_semantic(e.into()))?,
 | 
			
		||||
                    true,
 | 
			
		||||
                    exec_state,
 | 
			
		||||
                )
 | 
			
		||||
                .map_err(|_| {
 | 
			
		||||
                    KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
                    KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
                        format!(
 | 
			
		||||
                            "The input argument of {} requires a value with type `{}`, but found {}",
 | 
			
		||||
                            fn_name
 | 
			
		||||
@ -742,7 +742,7 @@ fn assign_args_to_params_kw(
 | 
			
		||||
                        .add(name.clone(), value, default_val.source_range())?;
 | 
			
		||||
                }
 | 
			
		||||
                None => {
 | 
			
		||||
                    return Err(KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
                    return Err(KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
                        format!(
 | 
			
		||||
                            "This function requires a parameter {}, but you haven't passed it one.",
 | 
			
		||||
                            name
 | 
			
		||||
@ -759,12 +759,12 @@ fn assign_args_to_params_kw(
 | 
			
		||||
 | 
			
		||||
        let Some(unlabeled) = unlabelled else {
 | 
			
		||||
            return Err(if args.kw_args.labeled.contains_key(param_name) {
 | 
			
		||||
                KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
                KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
                    format!("The function does declare a parameter named '{param_name}', but this parameter doesn't use a label. Try removing the `{param_name}:`"),
 | 
			
		||||
                    source_ranges,
 | 
			
		||||
                ))
 | 
			
		||||
            } else {
 | 
			
		||||
                KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
                KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
                    "This function expects an unlabeled first parameter, but you haven't passed it one.".to_owned(),
 | 
			
		||||
                    source_ranges,
 | 
			
		||||
                ))
 | 
			
		||||
@ -788,9 +788,9 @@ fn coerce_result_type(
 | 
			
		||||
    if let Ok(Some(val)) = result {
 | 
			
		||||
        if let Some(ret_ty) = &fn_def.return_type {
 | 
			
		||||
            let ty = RuntimeType::from_parsed(ret_ty.inner.clone(), exec_state, ret_ty.as_source_range())
 | 
			
		||||
                .map_err(|e| KclError::Semantic(e.into()))?;
 | 
			
		||||
                .map_err(|e| KclError::new_semantic(e.into()))?;
 | 
			
		||||
            let val = val.coerce(&ty, true, exec_state).map_err(|_| {
 | 
			
		||||
                KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
                KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
                    format!(
 | 
			
		||||
                        "This function requires its result to be of type `{}`, but found {}",
 | 
			
		||||
                        ty.human_friendly_type(),
 | 
			
		||||
@ -874,7 +874,7 @@ mod test {
 | 
			
		||||
                "all params required, none given, should error",
 | 
			
		||||
                vec![req_param("x")],
 | 
			
		||||
                vec![],
 | 
			
		||||
                Err(KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
                Err(KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
                    "This function requires a parameter x, but you haven't passed it one.".to_owned(),
 | 
			
		||||
                    vec![SourceRange::default()],
 | 
			
		||||
                ))),
 | 
			
		||||
@ -889,7 +889,7 @@ mod test {
 | 
			
		||||
                "mixed params, too few given",
 | 
			
		||||
                vec![req_param("x"), opt_param("y")],
 | 
			
		||||
                vec![],
 | 
			
		||||
                Err(KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
                Err(KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
                    "This function requires a parameter x, but you haven't passed it one.".to_owned(),
 | 
			
		||||
                    vec![SourceRange::default()],
 | 
			
		||||
                ))),
 | 
			
		||||
 | 
			
		||||
@ -469,7 +469,7 @@ impl TryFrom<PlaneData> for PlaneInfo {
 | 
			
		||||
            PlaneData::NegYZ => PlaneName::NegYz,
 | 
			
		||||
            PlaneData::Plane(_) => {
 | 
			
		||||
                // We will never get here since we already checked for PlaneData::Plane.
 | 
			
		||||
                return Err(KclError::Internal(KclErrorDetails::new(
 | 
			
		||||
                return Err(KclError::new_internal(KclErrorDetails::new(
 | 
			
		||||
                    format!("PlaneData {:?} not found", value),
 | 
			
		||||
                    Default::default(),
 | 
			
		||||
                )));
 | 
			
		||||
@ -477,7 +477,7 @@ impl TryFrom<PlaneData> for PlaneInfo {
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        let info = DEFAULT_PLANE_INFO.get(&name).ok_or_else(|| {
 | 
			
		||||
            KclError::Internal(KclErrorDetails::new(
 | 
			
		||||
            KclError::new_internal(KclErrorDetails::new(
 | 
			
		||||
                format!("Plane {} not found", name),
 | 
			
		||||
                Default::default(),
 | 
			
		||||
            ))
 | 
			
		||||
 | 
			
		||||
@ -37,25 +37,25 @@ pub async fn import_foreign(
 | 
			
		||||
) -> Result<PreImportedGeometry, KclError> {
 | 
			
		||||
    // Make sure the file exists.
 | 
			
		||||
    if !ctxt.fs.exists(file_path, source_range).await? {
 | 
			
		||||
        return Err(KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
        return Err(KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
            format!("File `{}` does not exist.", file_path.display()),
 | 
			
		||||
            vec![source_range],
 | 
			
		||||
        )));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let ext_format = get_import_format_from_extension(file_path.extension().ok_or_else(|| {
 | 
			
		||||
        KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
        KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
            format!("No file extension found for `{}`", file_path.display()),
 | 
			
		||||
            vec![source_range],
 | 
			
		||||
        ))
 | 
			
		||||
    })?)
 | 
			
		||||
    .map_err(|e| KclError::Semantic(KclErrorDetails::new(e.to_string(), vec![source_range])))?;
 | 
			
		||||
    .map_err(|e| KclError::new_semantic(KclErrorDetails::new(e.to_string(), vec![source_range])))?;
 | 
			
		||||
 | 
			
		||||
    // Get the format type from the extension of the file.
 | 
			
		||||
    let format = if let Some(format) = format {
 | 
			
		||||
        // Validate the given format with the extension format.
 | 
			
		||||
        validate_extension_format(ext_format, format.clone())
 | 
			
		||||
            .map_err(|e| KclError::Semantic(KclErrorDetails::new(e.to_string(), vec![source_range])))?;
 | 
			
		||||
            .map_err(|e| KclError::new_semantic(KclErrorDetails::new(e.to_string(), vec![source_range])))?;
 | 
			
		||||
        format
 | 
			
		||||
    } else {
 | 
			
		||||
        ext_format
 | 
			
		||||
@ -66,11 +66,11 @@ pub async fn import_foreign(
 | 
			
		||||
        .fs
 | 
			
		||||
        .read(file_path, source_range)
 | 
			
		||||
        .await
 | 
			
		||||
        .map_err(|e| KclError::Semantic(KclErrorDetails::new(e.to_string(), vec![source_range])))?;
 | 
			
		||||
        .map_err(|e| KclError::new_semantic(KclErrorDetails::new(e.to_string(), vec![source_range])))?;
 | 
			
		||||
 | 
			
		||||
    // We want the file_path to be without the parent.
 | 
			
		||||
    let file_name = file_path.file_name().map(|p| p.to_string()).ok_or_else(|| {
 | 
			
		||||
        KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
        KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
            format!("Could not get the file name from the path `{}`", file_path.display()),
 | 
			
		||||
            vec![source_range],
 | 
			
		||||
        ))
 | 
			
		||||
@ -87,7 +87,7 @@ pub async fn import_foreign(
 | 
			
		||||
        // file.
 | 
			
		||||
        if !file_contents.starts_with(b"glTF") {
 | 
			
		||||
            let json = gltf_json::Root::from_slice(&file_contents)
 | 
			
		||||
                .map_err(|e| KclError::Semantic(KclErrorDetails::new(e.to_string(), vec![source_range])))?;
 | 
			
		||||
                .map_err(|e| KclError::new_semantic(KclErrorDetails::new(e.to_string(), vec![source_range])))?;
 | 
			
		||||
 | 
			
		||||
            // Read the gltf file and check if there is a bin file.
 | 
			
		||||
            for buffer in json.buffers.iter() {
 | 
			
		||||
@ -95,16 +95,15 @@ pub async fn import_foreign(
 | 
			
		||||
                    if !uri.starts_with("data:") {
 | 
			
		||||
                        // We want this path relative to the file_path given.
 | 
			
		||||
                        let bin_path = file_path.parent().map(|p| p.join(uri)).ok_or_else(|| {
 | 
			
		||||
                            KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
                            KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
                                format!("Could not get the parent path of the file `{}`", file_path.display()),
 | 
			
		||||
                                vec![source_range],
 | 
			
		||||
                            ))
 | 
			
		||||
                        })?;
 | 
			
		||||
 | 
			
		||||
                        let bin_contents =
 | 
			
		||||
                            ctxt.fs.read(&bin_path, source_range).await.map_err(|e| {
 | 
			
		||||
                                KclError::Semantic(KclErrorDetails::new(e.to_string(), vec![source_range]))
 | 
			
		||||
                            })?;
 | 
			
		||||
                        let bin_contents = ctxt.fs.read(&bin_path, source_range).await.map_err(|e| {
 | 
			
		||||
                            KclError::new_semantic(KclErrorDetails::new(e.to_string(), vec![source_range]))
 | 
			
		||||
                        })?;
 | 
			
		||||
 | 
			
		||||
                        import_files.push(ImportFile {
 | 
			
		||||
                            path: uri.to_string(),
 | 
			
		||||
@ -141,7 +140,7 @@ pub(super) fn format_from_annotations(
 | 
			
		||||
        if p.key.name == annotations::IMPORT_FORMAT {
 | 
			
		||||
            result = Some(
 | 
			
		||||
                get_import_format_from_extension(annotations::expect_ident(&p.value)?).map_err(|_| {
 | 
			
		||||
                    KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
                    KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
                        format!(
 | 
			
		||||
                            "Unknown format for import, expected one of: {}",
 | 
			
		||||
                            crate::IMPORT_FILE_EXTENSIONS.join(", ")
 | 
			
		||||
@ -159,7 +158,7 @@ pub(super) fn format_from_annotations(
 | 
			
		||||
            path.extension()
 | 
			
		||||
                .and_then(|ext| get_import_format_from_extension(ext).ok())
 | 
			
		||||
        })
 | 
			
		||||
        .ok_or(KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
        .ok_or(KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
            "Unknown or missing extension, and no specified format for imported file".to_owned(),
 | 
			
		||||
            vec![import_source_range],
 | 
			
		||||
        )))?;
 | 
			
		||||
@ -174,7 +173,7 @@ pub(super) fn format_from_annotations(
 | 
			
		||||
            }
 | 
			
		||||
            annotations::IMPORT_FORMAT => {}
 | 
			
		||||
            _ => {
 | 
			
		||||
                return Err(KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
                return Err(KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
                    format!(
 | 
			
		||||
                        "Unexpected annotation for import, expected one of: {}, {}, {}",
 | 
			
		||||
                        annotations::IMPORT_FORMAT,
 | 
			
		||||
@ -199,7 +198,7 @@ fn set_coords(fmt: &mut InputFormat3d, coords_str: &str, source_range: SourceRan
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let Some(coords) = coords else {
 | 
			
		||||
        return Err(KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
        return Err(KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
            format!(
 | 
			
		||||
                "Unknown coordinate system: {coords_str}, expected one of: {}",
 | 
			
		||||
                annotations::IMPORT_COORDS_VALUES
 | 
			
		||||
@ -217,7 +216,7 @@ fn set_coords(fmt: &mut InputFormat3d, coords_str: &str, source_range: SourceRan
 | 
			
		||||
        InputFormat3d::Ply(opts) => opts.coords = coords,
 | 
			
		||||
        InputFormat3d::Stl(opts) => opts.coords = coords,
 | 
			
		||||
        _ => {
 | 
			
		||||
            return Err(KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
            return Err(KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
                format!(
 | 
			
		||||
                    "`{}` option cannot be applied to the specified format",
 | 
			
		||||
                    annotations::IMPORT_COORDS
 | 
			
		||||
@ -238,7 +237,7 @@ fn set_length_unit(fmt: &mut InputFormat3d, units_str: &str, source_range: Sourc
 | 
			
		||||
        InputFormat3d::Ply(opts) => opts.units = units.into(),
 | 
			
		||||
        InputFormat3d::Stl(opts) => opts.units = units.into(),
 | 
			
		||||
        _ => {
 | 
			
		||||
            return Err(KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
            return Err(KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
                format!(
 | 
			
		||||
                    "`{}` option cannot be applied to the specified format",
 | 
			
		||||
                    annotations::IMPORT_LENGTH_UNIT
 | 
			
		||||
 | 
			
		||||
@ -574,7 +574,7 @@ impl KclValue {
 | 
			
		||||
    pub fn get_tag_identifier(&self) -> Result<TagIdentifier, KclError> {
 | 
			
		||||
        match self {
 | 
			
		||||
            KclValue::TagIdentifier(t) => Ok(*t.clone()),
 | 
			
		||||
            _ => Err(KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
            _ => Err(KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
                format!("Not a tag identifier: {:?}", self),
 | 
			
		||||
                self.clone().into(),
 | 
			
		||||
            ))),
 | 
			
		||||
@ -585,7 +585,7 @@ impl KclValue {
 | 
			
		||||
    pub fn get_tag_declarator(&self) -> Result<TagNode, KclError> {
 | 
			
		||||
        match self {
 | 
			
		||||
            KclValue::TagDeclarator(t) => Ok((**t).clone()),
 | 
			
		||||
            _ => Err(KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
            _ => Err(KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
                format!("Not a tag declarator: {:?}", self),
 | 
			
		||||
                self.clone().into(),
 | 
			
		||||
            ))),
 | 
			
		||||
@ -595,7 +595,7 @@ impl KclValue {
 | 
			
		||||
    /// If this KCL value is a bool, retrieve it.
 | 
			
		||||
    pub fn get_bool(&self) -> Result<bool, KclError> {
 | 
			
		||||
        self.as_bool().ok_or_else(|| {
 | 
			
		||||
            KclError::Type(KclErrorDetails::new(
 | 
			
		||||
            KclError::new_type(KclErrorDetails::new(
 | 
			
		||||
                format!("Expected bool, found {}", self.human_friendly_type()),
 | 
			
		||||
                self.into(),
 | 
			
		||||
            ))
 | 
			
		||||
 | 
			
		||||
@ -367,7 +367,7 @@ impl ProgramMemory {
 | 
			
		||||
 | 
			
		||||
        let name = var.trim_start_matches(TYPE_PREFIX).trim_start_matches(MODULE_PREFIX);
 | 
			
		||||
 | 
			
		||||
        Err(KclError::UndefinedValue(KclErrorDetails::new(
 | 
			
		||||
        Err(KclError::new_undefined_value(KclErrorDetails::new(
 | 
			
		||||
            format!("`{name}` is not defined"),
 | 
			
		||||
            vec![source_range],
 | 
			
		||||
        )))
 | 
			
		||||
@ -488,7 +488,7 @@ impl ProgramMemory {
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Err(KclError::UndefinedValue(KclErrorDetails::new(
 | 
			
		||||
        Err(KclError::new_undefined_value(KclErrorDetails::new(
 | 
			
		||||
            format!("`{}` is not defined", var),
 | 
			
		||||
            vec![],
 | 
			
		||||
        )))
 | 
			
		||||
@ -646,7 +646,7 @@ impl Stack {
 | 
			
		||||
    pub fn add(&mut self, key: String, value: KclValue, source_range: SourceRange) -> Result<(), KclError> {
 | 
			
		||||
        let env = self.memory.get_env(self.current_env.index());
 | 
			
		||||
        if env.contains_key(&key) {
 | 
			
		||||
            return Err(KclError::ValueAlreadyDefined(KclErrorDetails::new(
 | 
			
		||||
            return Err(KclError::new_value_already_defined(KclErrorDetails::new(
 | 
			
		||||
                format!("Cannot redefine `{}`", key),
 | 
			
		||||
                vec![source_range],
 | 
			
		||||
            )));
 | 
			
		||||
 | 
			
		||||
@ -858,7 +858,7 @@ impl ExecutorContext {
 | 
			
		||||
 | 
			
		||||
            for module in modules {
 | 
			
		||||
                let Some((import_stmt, module_id, module_path, repr)) = universe.get(&module) else {
 | 
			
		||||
                    return Err(KclErrorWithOutputs::no_outputs(KclError::Internal(
 | 
			
		||||
                    return Err(KclErrorWithOutputs::no_outputs(KclError::new_internal(
 | 
			
		||||
                        KclErrorDetails::new(format!("Module {module} not found in universe"), Default::default()),
 | 
			
		||||
                    )));
 | 
			
		||||
                };
 | 
			
		||||
@ -920,7 +920,7 @@ impl ExecutorContext {
 | 
			
		||||
 | 
			
		||||
                            result.map(|val| ModuleRepr::Foreign(geom.clone(), val))
 | 
			
		||||
                        }
 | 
			
		||||
                        ModuleRepr::Dummy | ModuleRepr::Root => Err(KclError::Internal(KclErrorDetails::new(
 | 
			
		||||
                        ModuleRepr::Dummy | ModuleRepr::Root => Err(KclError::new_internal(KclErrorDetails::new(
 | 
			
		||||
                            format!("Module {module_path} not found in universe"),
 | 
			
		||||
                            vec![source_range],
 | 
			
		||||
                        ))),
 | 
			
		||||
@ -1283,7 +1283,7 @@ impl ExecutorContext {
 | 
			
		||||
            .await?;
 | 
			
		||||
 | 
			
		||||
        let kittycad_modeling_cmds::websocket::OkWebSocketResponseData::Export { files } = resp else {
 | 
			
		||||
            return Err(KclError::Internal(crate::errors::KclErrorDetails::new(
 | 
			
		||||
            return Err(KclError::new_internal(crate::errors::KclErrorDetails::new(
 | 
			
		||||
                format!("Expected Export response, got {resp:?}",),
 | 
			
		||||
                vec![SourceRange::default()],
 | 
			
		||||
            )));
 | 
			
		||||
@ -1303,7 +1303,7 @@ impl ExecutorContext {
 | 
			
		||||
                    coords: *kittycad_modeling_cmds::coord::KITTYCAD,
 | 
			
		||||
                    created: if deterministic_time {
 | 
			
		||||
                        Some("2021-01-01T00:00:00Z".parse().map_err(|e| {
 | 
			
		||||
                            KclError::Internal(crate::errors::KclErrorDetails::new(
 | 
			
		||||
                            KclError::new_internal(crate::errors::KclErrorDetails::new(
 | 
			
		||||
                                format!("Failed to parse date: {}", e),
 | 
			
		||||
                                vec![SourceRange::default()],
 | 
			
		||||
                            ))
 | 
			
		||||
@ -1383,7 +1383,7 @@ pub(crate) async fn parse_execute_with_project_dir(
 | 
			
		||||
    let exec_ctxt = ExecutorContext {
 | 
			
		||||
        engine: Arc::new(Box::new(
 | 
			
		||||
            crate::engine::conn_mock::EngineConnection::new().await.map_err(|err| {
 | 
			
		||||
                KclError::Internal(crate::errors::KclErrorDetails::new(
 | 
			
		||||
                KclError::new_internal(crate::errors::KclErrorDetails::new(
 | 
			
		||||
                    format!("Failed to create mock engine connection: {}", err),
 | 
			
		||||
                    vec![SourceRange::default()],
 | 
			
		||||
                ))
 | 
			
		||||
@ -1799,7 +1799,7 @@ foo
 | 
			
		||||
        let err = result.unwrap_err();
 | 
			
		||||
        assert_eq!(
 | 
			
		||||
            err,
 | 
			
		||||
            KclError::Syntax(KclErrorDetails::new(
 | 
			
		||||
            KclError::new_syntax(KclErrorDetails::new(
 | 
			
		||||
                "Unexpected token: #".to_owned(),
 | 
			
		||||
                vec![SourceRange::new(14, 15, ModuleId::default())],
 | 
			
		||||
            )),
 | 
			
		||||
@ -2058,7 +2058,7 @@ notTagIdentifier = !myTag";
 | 
			
		||||
            // TODO: We don't currently parse this, but we should.  It should be
 | 
			
		||||
            // a runtime error instead.
 | 
			
		||||
            parse_execute(code10).await.unwrap_err(),
 | 
			
		||||
            KclError::Syntax(KclErrorDetails::new(
 | 
			
		||||
            KclError::new_syntax(KclErrorDetails::new(
 | 
			
		||||
                "Unexpected token: !".to_owned(),
 | 
			
		||||
                vec![SourceRange::new(10, 11, ModuleId::default())],
 | 
			
		||||
            ))
 | 
			
		||||
@ -2071,7 +2071,7 @@ notPipeSub = 1 |> identity(!%))";
 | 
			
		||||
            // TODO: We don't currently parse this, but we should.  It should be
 | 
			
		||||
            // a runtime error instead.
 | 
			
		||||
            parse_execute(code11).await.unwrap_err(),
 | 
			
		||||
            KclError::Syntax(KclErrorDetails::new(
 | 
			
		||||
            KclError::new_syntax(KclErrorDetails::new(
 | 
			
		||||
                "There was an unexpected !. Try removing it.".to_owned(),
 | 
			
		||||
                vec![SourceRange::new(56, 57, ModuleId::default())],
 | 
			
		||||
            ))
 | 
			
		||||
 | 
			
		||||
@ -276,7 +276,7 @@ impl ExecState {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub(super) fn circular_import_error(&self, path: &ModulePath, source_range: SourceRange) -> KclError {
 | 
			
		||||
        KclError::ImportCycle(KclErrorDetails::new(
 | 
			
		||||
        KclError::new_import_cycle(KclErrorDetails::new(
 | 
			
		||||
            format!(
 | 
			
		||||
                "circular import of modules is not allowed: {} -> {}",
 | 
			
		||||
                self.global
 | 
			
		||||
@ -389,7 +389,7 @@ impl MetaSettings {
 | 
			
		||||
                    self.kcl_version = value;
 | 
			
		||||
                }
 | 
			
		||||
                name => {
 | 
			
		||||
                    return Err(KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
                    return Err(KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
                        format!(
 | 
			
		||||
                            "Unexpected settings key: `{name}`; expected one of `{}`, `{}`",
 | 
			
		||||
                            annotations::SETTINGS_UNIT_LENGTH,
 | 
			
		||||
 | 
			
		||||
@ -28,7 +28,7 @@ impl Default for FileManager {
 | 
			
		||||
impl FileSystem for FileManager {
 | 
			
		||||
    async fn read(&self, path: &TypedPath, source_range: SourceRange) -> Result<Vec<u8>, KclError> {
 | 
			
		||||
        tokio::fs::read(&path.0).await.map_err(|e| {
 | 
			
		||||
            KclError::Io(KclErrorDetails::new(
 | 
			
		||||
            KclError::new_io(KclErrorDetails::new(
 | 
			
		||||
                format!("Failed to read file `{}`: {}", path.display(), e),
 | 
			
		||||
                vec![source_range],
 | 
			
		||||
            ))
 | 
			
		||||
@ -37,7 +37,7 @@ impl FileSystem for FileManager {
 | 
			
		||||
 | 
			
		||||
    async fn read_to_string(&self, path: &TypedPath, source_range: SourceRange) -> Result<String, KclError> {
 | 
			
		||||
        tokio::fs::read_to_string(&path.0).await.map_err(|e| {
 | 
			
		||||
            KclError::Io(KclErrorDetails::new(
 | 
			
		||||
            KclError::new_io(KclErrorDetails::new(
 | 
			
		||||
                format!("Failed to read file `{}`: {}", path.display(), e),
 | 
			
		||||
                vec![source_range],
 | 
			
		||||
            ))
 | 
			
		||||
@ -49,7 +49,7 @@ impl FileSystem for FileManager {
 | 
			
		||||
            if e.kind() == std::io::ErrorKind::NotFound {
 | 
			
		||||
                Ok(false)
 | 
			
		||||
            } else {
 | 
			
		||||
                Err(KclError::Io(KclErrorDetails::new(
 | 
			
		||||
                Err(KclError::new_io(KclErrorDetails::new(
 | 
			
		||||
                    format!("Failed to check if file `{}` exists: {}", path.display(), e),
 | 
			
		||||
                    vec![source_range],
 | 
			
		||||
                )))
 | 
			
		||||
@ -71,7 +71,7 @@ impl FileSystem for FileManager {
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            let mut read_dir = tokio::fs::read_dir(&path).await.map_err(|e| {
 | 
			
		||||
                KclError::Io(KclErrorDetails::new(
 | 
			
		||||
                KclError::new_io(KclErrorDetails::new(
 | 
			
		||||
                    format!("Failed to read directory `{}`: {}", path.display(), e),
 | 
			
		||||
                    vec![source_range],
 | 
			
		||||
                ))
 | 
			
		||||
 | 
			
		||||
@ -49,10 +49,10 @@ impl FileSystem for FileManager {
 | 
			
		||||
        let promise = self
 | 
			
		||||
            .manager
 | 
			
		||||
            .read_file(path.to_string_lossy())
 | 
			
		||||
            .map_err(|e| KclError::Engine(KclErrorDetails::new(e.to_string().into(), vec![source_range])))?;
 | 
			
		||||
            .map_err(|e| KclError::new_engine(KclErrorDetails::new(e.to_string().into(), vec![source_range])))?;
 | 
			
		||||
 | 
			
		||||
        let value = JsFuture::from(promise).await.map_err(|e| {
 | 
			
		||||
            KclError::Engine(KclErrorDetails::new(
 | 
			
		||||
            KclError::new_engine(KclErrorDetails::new(
 | 
			
		||||
                format!("Failed to wait for promise from engine: {:?}", e),
 | 
			
		||||
                vec![source_range],
 | 
			
		||||
            ))
 | 
			
		||||
@ -67,7 +67,7 @@ impl FileSystem for FileManager {
 | 
			
		||||
    async fn read_to_string(&self, path: &TypedPath, source_range: SourceRange) -> Result<String, KclError> {
 | 
			
		||||
        let bytes = self.read(path, source_range).await?;
 | 
			
		||||
        let string = String::from_utf8(bytes).map_err(|e| {
 | 
			
		||||
            KclError::Engine(KclErrorDetails::new(
 | 
			
		||||
            KclError::new_engine(KclErrorDetails::new(
 | 
			
		||||
                format!("Failed to convert bytes to string: {:?}", e),
 | 
			
		||||
                vec![source_range],
 | 
			
		||||
            ))
 | 
			
		||||
@ -80,17 +80,17 @@ impl FileSystem for FileManager {
 | 
			
		||||
        let promise = self
 | 
			
		||||
            .manager
 | 
			
		||||
            .exists(path.to_string_lossy())
 | 
			
		||||
            .map_err(|e| KclError::Engine(KclErrorDetails::new(e.to_string().into(), vec![source_range])))?;
 | 
			
		||||
            .map_err(|e| KclError::new_engine(KclErrorDetails::new(e.to_string().into(), vec![source_range])))?;
 | 
			
		||||
 | 
			
		||||
        let value = JsFuture::from(promise).await.map_err(|e| {
 | 
			
		||||
            KclError::Engine(KclErrorDetails::new(
 | 
			
		||||
            KclError::new_engine(KclErrorDetails::new(
 | 
			
		||||
                format!("Failed to wait for promise from engine: {:?}", e),
 | 
			
		||||
                vec![source_range],
 | 
			
		||||
            ))
 | 
			
		||||
        })?;
 | 
			
		||||
 | 
			
		||||
        let it_exists = value.as_bool().ok_or_else(|| {
 | 
			
		||||
            KclError::Engine(KclErrorDetails::new(
 | 
			
		||||
            KclError::new_engine(KclErrorDetails::new(
 | 
			
		||||
                "Failed to convert value to bool".to_string(),
 | 
			
		||||
                vec![source_range],
 | 
			
		||||
            ))
 | 
			
		||||
@ -107,24 +107,24 @@ impl FileSystem for FileManager {
 | 
			
		||||
        let promise = self
 | 
			
		||||
            .manager
 | 
			
		||||
            .get_all_files(path.to_string_lossy())
 | 
			
		||||
            .map_err(|e| KclError::Engine(KclErrorDetails::new(e.to_string().into(), vec![source_range])))?;
 | 
			
		||||
            .map_err(|e| KclError::new_engine(KclErrorDetails::new(e.to_string().into(), vec![source_range])))?;
 | 
			
		||||
 | 
			
		||||
        let value = JsFuture::from(promise).await.map_err(|e| {
 | 
			
		||||
            KclError::Engine(KclErrorDetails::new(
 | 
			
		||||
            KclError::new_engine(KclErrorDetails::new(
 | 
			
		||||
                format!("Failed to wait for promise from javascript: {:?}", e),
 | 
			
		||||
                vec![source_range],
 | 
			
		||||
            ))
 | 
			
		||||
        })?;
 | 
			
		||||
 | 
			
		||||
        let s = value.as_string().ok_or_else(|| {
 | 
			
		||||
            KclError::Engine(KclErrorDetails::new(
 | 
			
		||||
            KclError::new_engine(KclErrorDetails::new(
 | 
			
		||||
                format!("Failed to get string from response from javascript: `{:?}`", value),
 | 
			
		||||
                vec![source_range],
 | 
			
		||||
            ))
 | 
			
		||||
        })?;
 | 
			
		||||
 | 
			
		||||
        let files: Vec<String> = serde_json::from_str(&s).map_err(|e| {
 | 
			
		||||
            KclError::Engine(KclErrorDetails::new(
 | 
			
		||||
            KclError::new_engine(KclErrorDetails::new(
 | 
			
		||||
                format!("Failed to parse json from javascript: `{}` `{:?}`", s, e),
 | 
			
		||||
                vec![source_range],
 | 
			
		||||
            ))
 | 
			
		||||
 | 
			
		||||
@ -58,7 +58,7 @@ impl ModuleLoader {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub(crate) fn import_cycle_error(&self, path: &ModulePath, source_range: SourceRange) -> KclError {
 | 
			
		||||
        KclError::ImportCycle(KclErrorDetails::new(
 | 
			
		||||
        KclError::new_import_cycle(KclErrorDetails::new(
 | 
			
		||||
            format!(
 | 
			
		||||
                "circular import of modules is not allowed: {} -> {}",
 | 
			
		||||
                self.import_stack
 | 
			
		||||
@ -163,7 +163,7 @@ impl ModulePath {
 | 
			
		||||
            ModulePath::Std { value: name } => Ok(ModuleSource {
 | 
			
		||||
                source: read_std(name)
 | 
			
		||||
                    .ok_or_else(|| {
 | 
			
		||||
                        KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
                        KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
                            format!("Cannot find standard library module to import: std::{name}."),
 | 
			
		||||
                            vec![source_range],
 | 
			
		||||
                        ))
 | 
			
		||||
@ -202,7 +202,7 @@ impl ModulePath {
 | 
			
		||||
                    ModulePath::Std { .. } => {
 | 
			
		||||
                        let message = format!("Cannot import a non-std KCL file from std: {path}.");
 | 
			
		||||
                        debug_assert!(false, "{}", &message);
 | 
			
		||||
                        return Err(KclError::Internal(KclErrorDetails::new(message, vec![])));
 | 
			
		||||
                        return Err(KclError::new_internal(KclErrorDetails::new(message, vec![])));
 | 
			
		||||
                    }
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
@ -217,7 +217,7 @@ impl ModulePath {
 | 
			
		||||
        if path.len() != 2 || path[0] != "std" {
 | 
			
		||||
            let message = format!("Invalid std import path: {path:?}.");
 | 
			
		||||
            debug_assert!(false, "{}", &message);
 | 
			
		||||
            return Err(KclError::Internal(KclErrorDetails::new(message, vec![])));
 | 
			
		||||
            return Err(KclError::new_internal(KclErrorDetails::new(message, vec![])));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Ok(ModulePath::Std { value: path[1].clone() })
 | 
			
		||||
 | 
			
		||||
@ -51,7 +51,7 @@ pub fn parse_tokens(mut tokens: TokenStream) -> ParseResult {
 | 
			
		||||
        } else {
 | 
			
		||||
            format!("found unknown tokens [{}]", token_list.join(", "))
 | 
			
		||||
        };
 | 
			
		||||
        return KclError::Lexical(KclErrorDetails::new(message, source_ranges)).into();
 | 
			
		||||
        return KclError::new_lexical(KclErrorDetails::new(message, source_ranges)).into();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Important, to not call this before the unknown tokens check.
 | 
			
		||||
@ -110,7 +110,7 @@ impl ParseResult {
 | 
			
		||||
        let (p, errs) = self.0?;
 | 
			
		||||
 | 
			
		||||
        if let Some(err) = errs.iter().find(|e| e.severity.is_err()) {
 | 
			
		||||
            return Err(KclError::Syntax(err.clone().into()));
 | 
			
		||||
            return Err(KclError::new_syntax(err.clone().into()));
 | 
			
		||||
        }
 | 
			
		||||
        match p {
 | 
			
		||||
            Some(p) => Ok(p),
 | 
			
		||||
 | 
			
		||||
@ -4412,7 +4412,7 @@ secondExtrude = startSketchOn(XY)
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn test_parse_parens_unicode() {
 | 
			
		||||
        let result = crate::parsing::top_level_parse("(ޜ");
 | 
			
		||||
        let KclError::Lexical(details) = result.0.unwrap_err() else {
 | 
			
		||||
        let KclError::Lexical { details } = result.0.unwrap_err() else {
 | 
			
		||||
            panic!();
 | 
			
		||||
        };
 | 
			
		||||
        // TODO: Better errors when program cannot tokenize.
 | 
			
		||||
 | 
			
		||||
@ -597,7 +597,7 @@ impl From<ParseError<Input<'_>, winnow::error::ContextError>> for KclError {
 | 
			
		||||
            // This is an offset, not an index, and may point to
 | 
			
		||||
            // the end of input (input.len()) on eof errors.
 | 
			
		||||
 | 
			
		||||
            return KclError::Lexical(crate::errors::KclErrorDetails::new(
 | 
			
		||||
            return KclError::new_lexical(crate::errors::KclErrorDetails::new(
 | 
			
		||||
                "unexpected EOF while parsing".to_owned(),
 | 
			
		||||
                vec![SourceRange::new(offset, offset, module_id)],
 | 
			
		||||
            ));
 | 
			
		||||
@ -608,7 +608,7 @@ impl From<ParseError<Input<'_>, winnow::error::ContextError>> for KclError {
 | 
			
		||||
        let bad_token = &input[offset];
 | 
			
		||||
        // TODO: Add the Winnow parser context to the error.
 | 
			
		||||
        // See https://github.com/KittyCAD/modeling-app/issues/784
 | 
			
		||||
        KclError::Lexical(crate::errors::KclErrorDetails::new(
 | 
			
		||||
        KclError::new_lexical(crate::errors::KclErrorDetails::new(
 | 
			
		||||
            format!("found unknown token '{}'", bad_token),
 | 
			
		||||
            vec![SourceRange::new(offset, offset + 1, module_id)],
 | 
			
		||||
        ))
 | 
			
		||||
 | 
			
		||||
@ -30,7 +30,7 @@ pub async fn hex_string(exec_state: &mut ExecState, args: Args) -> Result<KclVal
 | 
			
		||||
 | 
			
		||||
    // Make sure the color if set is valid.
 | 
			
		||||
    if let Some(component) = rgb.iter().find(|component| component.n < 0.0 || component.n > 255.0) {
 | 
			
		||||
        return Err(KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
        return Err(KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
            format!("Colors are given between 0 and 255, so {} is invalid", component.n),
 | 
			
		||||
            vec![args.source_range],
 | 
			
		||||
        )));
 | 
			
		||||
@ -62,7 +62,7 @@ pub async fn appearance(exec_state: &mut ExecState, args: Args) -> Result<KclVal
 | 
			
		||||
 | 
			
		||||
    // Make sure the color if set is valid.
 | 
			
		||||
    if !HEX_REGEX.is_match(&color) {
 | 
			
		||||
        return Err(KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
        return Err(KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
            format!("Invalid hex color (`{}`), try something like `#fff000`", color),
 | 
			
		||||
            vec![args.source_range],
 | 
			
		||||
        )));
 | 
			
		||||
@ -93,7 +93,7 @@ async fn inner_appearance(
 | 
			
		||||
    for solid_id in solids.ids(&args.ctx).await? {
 | 
			
		||||
        // Set the material properties.
 | 
			
		||||
        let rgb = rgba_simple::RGB::<f32>::from_hex(&color).map_err(|err| {
 | 
			
		||||
            KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
            KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
                format!("Invalid hex color (`{color}`): {err}"),
 | 
			
		||||
                vec![args.source_range],
 | 
			
		||||
            ))
 | 
			
		||||
 | 
			
		||||
@ -123,7 +123,7 @@ impl Args {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        T::from_kcl_val(&arg.value).map(Some).ok_or_else(|| {
 | 
			
		||||
            KclError::Type(KclErrorDetails::new(
 | 
			
		||||
            KclError::new_type(KclErrorDetails::new(
 | 
			
		||||
                format!(
 | 
			
		||||
                    "The arg {label} was given, but it was the wrong type. It should be type {} but it was {}",
 | 
			
		||||
                    tynm::type_name::<T>(),
 | 
			
		||||
@ -156,7 +156,7 @@ impl Args {
 | 
			
		||||
        T: FromKclValue<'a>,
 | 
			
		||||
    {
 | 
			
		||||
        self.get_kw_arg_opt(label)?.ok_or_else(|| {
 | 
			
		||||
            KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
            KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
                format!("This function requires a keyword argument '{label}'"),
 | 
			
		||||
                vec![self.source_range],
 | 
			
		||||
            ))
 | 
			
		||||
@ -173,7 +173,7 @@ impl Args {
 | 
			
		||||
        T: for<'a> FromKclValue<'a>,
 | 
			
		||||
    {
 | 
			
		||||
        let Some(arg) = self.kw_args.labeled.get(label) else {
 | 
			
		||||
            return Err(KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
            return Err(KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
                format!("This function requires a keyword argument '{label}'"),
 | 
			
		||||
                vec![self.source_range],
 | 
			
		||||
            )));
 | 
			
		||||
@ -207,7 +207,7 @@ impl Args {
 | 
			
		||||
            if message.contains("one or more Solids or imported geometry but it's actually of type Sketch") {
 | 
			
		||||
                message = format!("{message}. {ERROR_STRING_SKETCH_TO_SOLID_HELPER}");
 | 
			
		||||
            }
 | 
			
		||||
            KclError::Semantic(KclErrorDetails::new(message, arg.source_ranges()))
 | 
			
		||||
            KclError::new_semantic(KclErrorDetails::new(message, arg.source_ranges()))
 | 
			
		||||
        })?;
 | 
			
		||||
 | 
			
		||||
        // TODO unnecessary cloning
 | 
			
		||||
@ -221,7 +221,7 @@ impl Args {
 | 
			
		||||
        label: &str,
 | 
			
		||||
    ) -> Result<Vec<(EdgeReference, SourceRange)>, KclError> {
 | 
			
		||||
        let Some(arg) = self.kw_args.labeled.get(label) else {
 | 
			
		||||
            let err = KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
            let err = KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
                format!("This function requires a keyword argument '{label}'"),
 | 
			
		||||
                vec![self.source_range],
 | 
			
		||||
            ));
 | 
			
		||||
@ -234,7 +234,7 @@ impl Args {
 | 
			
		||||
            .map(|item| {
 | 
			
		||||
                let source = SourceRange::from(item);
 | 
			
		||||
                let val = FromKclValue::from_kcl_val(item).ok_or_else(|| {
 | 
			
		||||
                    KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
                    KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
                        format!("Expected an Edge but found {}", arg.value.human_friendly_type()),
 | 
			
		||||
                        arg.source_ranges(),
 | 
			
		||||
                    ))
 | 
			
		||||
@ -270,7 +270,7 @@ impl Args {
 | 
			
		||||
    {
 | 
			
		||||
        let arg = self
 | 
			
		||||
            .unlabeled_kw_arg_unconverted()
 | 
			
		||||
            .ok_or(KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
            .ok_or(KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
                format!("This function requires a value for the special unlabeled first parameter, '{label}'"),
 | 
			
		||||
                vec![self.source_range],
 | 
			
		||||
            )))?;
 | 
			
		||||
@ -304,11 +304,11 @@ impl Args {
 | 
			
		||||
            if message.contains("one or more Solids or imported geometry but it's actually of type Sketch") {
 | 
			
		||||
                message = format!("{message}. {ERROR_STRING_SKETCH_TO_SOLID_HELPER}");
 | 
			
		||||
            }
 | 
			
		||||
            KclError::Semantic(KclErrorDetails::new(message, arg.source_ranges()))
 | 
			
		||||
            KclError::new_semantic(KclErrorDetails::new(message, arg.source_ranges()))
 | 
			
		||||
        })?;
 | 
			
		||||
 | 
			
		||||
        T::from_kcl_val(&arg).ok_or_else(|| {
 | 
			
		||||
            KclError::Internal(KclErrorDetails::new(
 | 
			
		||||
            KclError::new_internal(KclErrorDetails::new(
 | 
			
		||||
                format!("Mismatch between type coercion and value extraction (this isn't your fault).\nTo assist in bug-reporting, expected type: {ty:?}; actual value: {arg:?}"),
 | 
			
		||||
                vec![self.source_range],
 | 
			
		||||
           ))
 | 
			
		||||
@ -354,14 +354,14 @@ impl Args {
 | 
			
		||||
            exec_state.stack().get_from_call_stack(&tag.value, self.source_range)?
 | 
			
		||||
        {
 | 
			
		||||
            let info = t.get_info(epoch).ok_or_else(|| {
 | 
			
		||||
                KclError::Type(KclErrorDetails::new(
 | 
			
		||||
                KclError::new_type(KclErrorDetails::new(
 | 
			
		||||
                    format!("Tag `{}` does not have engine info", tag.value),
 | 
			
		||||
                    vec![self.source_range],
 | 
			
		||||
                ))
 | 
			
		||||
            })?;
 | 
			
		||||
            Ok(info)
 | 
			
		||||
        } else {
 | 
			
		||||
            Err(KclError::Type(KclErrorDetails::new(
 | 
			
		||||
            Err(KclError::new_type(KclErrorDetails::new(
 | 
			
		||||
                format!("Tag `{}` does not exist", tag.value),
 | 
			
		||||
                vec![self.source_range],
 | 
			
		||||
            )))
 | 
			
		||||
@ -493,7 +493,7 @@ impl Args {
 | 
			
		||||
        must_be_planar: bool,
 | 
			
		||||
    ) -> Result<uuid::Uuid, KclError> {
 | 
			
		||||
        if tag.value.is_empty() {
 | 
			
		||||
            return Err(KclError::Type(KclErrorDetails::new(
 | 
			
		||||
            return Err(KclError::new_type(KclErrorDetails::new(
 | 
			
		||||
                "Expected a non-empty tag for the face".to_string(),
 | 
			
		||||
                vec![self.source_range],
 | 
			
		||||
            )));
 | 
			
		||||
@ -502,7 +502,7 @@ impl Args {
 | 
			
		||||
        let engine_info = self.get_tag_engine_info_check_surface(exec_state, tag)?;
 | 
			
		||||
 | 
			
		||||
        let surface = engine_info.surface.as_ref().ok_or_else(|| {
 | 
			
		||||
            KclError::Type(KclErrorDetails::new(
 | 
			
		||||
            KclError::new_type(KclErrorDetails::new(
 | 
			
		||||
                format!("Tag `{}` does not have a surface", tag.value),
 | 
			
		||||
                vec![self.source_range],
 | 
			
		||||
            ))
 | 
			
		||||
@ -521,7 +521,7 @@ impl Args {
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            // The must be planar check must be called before the arc check.
 | 
			
		||||
            ExtrudeSurface::ExtrudeArc(_) if must_be_planar => Some(Err(KclError::Type(KclErrorDetails::new(
 | 
			
		||||
            ExtrudeSurface::ExtrudeArc(_) if must_be_planar => Some(Err(KclError::new_type(KclErrorDetails::new(
 | 
			
		||||
                format!("Tag `{}` is a non-planar surface", tag.value),
 | 
			
		||||
                vec![self.source_range],
 | 
			
		||||
            )))),
 | 
			
		||||
@ -548,7 +548,7 @@ impl Args {
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            // The must be planar check must be called before the fillet check.
 | 
			
		||||
            ExtrudeSurface::Fillet(_) if must_be_planar => Some(Err(KclError::Type(KclErrorDetails::new(
 | 
			
		||||
            ExtrudeSurface::Fillet(_) if must_be_planar => Some(Err(KclError::new_type(KclErrorDetails::new(
 | 
			
		||||
                format!("Tag `{}` is a non-planar surface", tag.value),
 | 
			
		||||
                vec![self.source_range],
 | 
			
		||||
            )))),
 | 
			
		||||
@ -568,7 +568,7 @@ impl Args {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // If we still haven't found the face, return an error.
 | 
			
		||||
        Err(KclError::Type(KclErrorDetails::new(
 | 
			
		||||
        Err(KclError::new_type(KclErrorDetails::new(
 | 
			
		||||
            format!("Expected a face with the tag `{}`", tag.value),
 | 
			
		||||
            vec![self.source_range],
 | 
			
		||||
        )))
 | 
			
		||||
@ -593,13 +593,13 @@ where
 | 
			
		||||
{
 | 
			
		||||
    fn from_args(args: &'a Args, i: usize) -> Result<Self, KclError> {
 | 
			
		||||
        let Some(arg) = args.args.get(i) else {
 | 
			
		||||
            return Err(KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
            return Err(KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
                format!("Expected an argument at index {i}"),
 | 
			
		||||
                vec![args.source_range],
 | 
			
		||||
            )));
 | 
			
		||||
        };
 | 
			
		||||
        let Some(val) = T::from_kcl_val(&arg.value) else {
 | 
			
		||||
            return Err(KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
            return Err(KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
                format!(
 | 
			
		||||
                    "Argument at index {i} was supposed to be type {} but found {}",
 | 
			
		||||
                    tynm::type_name::<T>(),
 | 
			
		||||
@ -622,7 +622,7 @@ where
 | 
			
		||||
            return Ok(None);
 | 
			
		||||
        }
 | 
			
		||||
        let Some(val) = T::from_kcl_val(&arg.value) else {
 | 
			
		||||
            return Err(KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
            return Err(KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
                format!(
 | 
			
		||||
                    "Argument at index {i} was supposed to be type Option<{}> but found {}",
 | 
			
		||||
                    tynm::type_name::<T>(),
 | 
			
		||||
 | 
			
		||||
@ -58,7 +58,7 @@ async fn call_map_closure(
 | 
			
		||||
    let output = map_fn.call_kw(None, exec_state, ctxt, args, source_range).await?;
 | 
			
		||||
    let source_ranges = vec![source_range];
 | 
			
		||||
    let output = output.ok_or_else(|| {
 | 
			
		||||
        KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
        KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
            "Map function must return a value".to_owned(),
 | 
			
		||||
            source_ranges,
 | 
			
		||||
        ))
 | 
			
		||||
@ -118,7 +118,7 @@ async fn call_reduce_closure(
 | 
			
		||||
    // Unpack the returned transform object.
 | 
			
		||||
    let source_ranges = vec![source_range];
 | 
			
		||||
    let out = transform_fn_return.ok_or_else(|| {
 | 
			
		||||
        KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
        KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
            "Reducer function must return a value".to_string(),
 | 
			
		||||
            source_ranges.clone(),
 | 
			
		||||
        ))
 | 
			
		||||
@ -138,7 +138,7 @@ pub async fn push(exec_state: &mut ExecState, args: Args) -> Result<KclValue, Kc
 | 
			
		||||
pub async fn pop(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
 | 
			
		||||
    let (mut array, ty) = args.get_unlabeled_kw_arg_array_and_type("array", exec_state)?;
 | 
			
		||||
    if array.is_empty() {
 | 
			
		||||
        return Err(KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
        return Err(KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
            "Cannot pop from an empty array".to_string(),
 | 
			
		||||
            vec![args.source_range],
 | 
			
		||||
        )));
 | 
			
		||||
 | 
			
		||||
@ -11,7 +11,7 @@ use crate::{
 | 
			
		||||
 | 
			
		||||
async fn _assert(value: bool, message: &str, args: &Args) -> Result<(), KclError> {
 | 
			
		||||
    if !value {
 | 
			
		||||
        return Err(KclError::Type(KclErrorDetails::new(
 | 
			
		||||
        return Err(KclError::new_type(KclErrorDetails::new(
 | 
			
		||||
            format!("assert failed: {}", message),
 | 
			
		||||
            vec![args.source_range],
 | 
			
		||||
        )));
 | 
			
		||||
@ -72,14 +72,14 @@ async fn inner_assert(
 | 
			
		||||
    .iter()
 | 
			
		||||
    .all(|cond| cond.is_none());
 | 
			
		||||
    if no_condition_given {
 | 
			
		||||
        return Err(KclError::Type(KclErrorDetails::new(
 | 
			
		||||
        return Err(KclError::new_type(KclErrorDetails::new(
 | 
			
		||||
            "You must provide at least one condition in this assert (for example, isEqualTo)".to_owned(),
 | 
			
		||||
            vec![args.source_range],
 | 
			
		||||
        )));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if tolerance.is_some() && is_equal_to.is_none() {
 | 
			
		||||
        return Err(KclError::Type(KclErrorDetails::new(
 | 
			
		||||
        return Err(KclError::new_type(KclErrorDetails::new(
 | 
			
		||||
            "The `tolerance` arg is only used with `isEqualTo`. Either remove `tolerance` or add an `isEqualTo` arg."
 | 
			
		||||
                .to_owned(),
 | 
			
		||||
            vec![args.source_range],
 | 
			
		||||
 | 
			
		||||
@ -41,7 +41,7 @@ async fn inner_chamfer(
 | 
			
		||||
    // If you try and tag multiple edges with a tagged chamfer, we want to return an
 | 
			
		||||
    // error to the user that they can only tag one edge at a time.
 | 
			
		||||
    if tag.is_some() && tags.len() > 1 {
 | 
			
		||||
        return Err(KclError::Type(KclErrorDetails::new(
 | 
			
		||||
        return Err(KclError::new_type(KclErrorDetails::new(
 | 
			
		||||
            "You can only tag one edge at a time with a tagged chamfer. Either delete the tag for the chamfer fn if you don't need it OR separate into individual chamfer functions for each tag.".to_string(),
 | 
			
		||||
            vec![args.source_range],
 | 
			
		||||
        )));
 | 
			
		||||
 | 
			
		||||
@ -84,7 +84,7 @@ async fn inner_clone(
 | 
			
		||||
    fix_tags_and_references(&mut new_geometry, old_id, exec_state, &args)
 | 
			
		||||
        .await
 | 
			
		||||
        .map_err(|e| {
 | 
			
		||||
            KclError::Internal(KclErrorDetails::new(
 | 
			
		||||
            KclError::new_internal(KclErrorDetails::new(
 | 
			
		||||
                format!("failed to fix tags and references: {:?}", e),
 | 
			
		||||
                vec![args.source_range],
 | 
			
		||||
            ))
 | 
			
		||||
 | 
			
		||||
@ -23,7 +23,7 @@ pub async fn union(exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
 | 
			
		||||
    let tolerance: Option<TyF64> = args.get_kw_arg_opt_typed("tolerance", &RuntimeType::length(), exec_state)?;
 | 
			
		||||
 | 
			
		||||
    if solids.len() < 2 {
 | 
			
		||||
        return Err(KclError::UndefinedValue(KclErrorDetails::new(
 | 
			
		||||
        return Err(KclError::new_undefined_value(KclErrorDetails::new(
 | 
			
		||||
            "At least two solids are required for a union operation.".to_string(),
 | 
			
		||||
            vec![args.source_range],
 | 
			
		||||
        )));
 | 
			
		||||
@ -66,7 +66,7 @@ pub(crate) async fn inner_union(
 | 
			
		||||
        modeling_response: OkModelingCmdResponse::BooleanUnion(BooleanUnion { extra_solid_ids }),
 | 
			
		||||
    } = result
 | 
			
		||||
    else {
 | 
			
		||||
        return Err(KclError::Internal(KclErrorDetails::new(
 | 
			
		||||
        return Err(KclError::new_internal(KclErrorDetails::new(
 | 
			
		||||
            "Failed to get the result of the union operation.".to_string(),
 | 
			
		||||
            vec![args.source_range],
 | 
			
		||||
        )));
 | 
			
		||||
@ -88,7 +88,7 @@ pub async fn intersect(exec_state: &mut ExecState, args: Args) -> Result<KclValu
 | 
			
		||||
    let tolerance: Option<TyF64> = args.get_kw_arg_opt_typed("tolerance", &RuntimeType::length(), exec_state)?;
 | 
			
		||||
 | 
			
		||||
    if solids.len() < 2 {
 | 
			
		||||
        return Err(KclError::UndefinedValue(KclErrorDetails::new(
 | 
			
		||||
        return Err(KclError::new_undefined_value(KclErrorDetails::new(
 | 
			
		||||
            "At least two solids are required for an intersect operation.".to_string(),
 | 
			
		||||
            vec![args.source_range],
 | 
			
		||||
        )));
 | 
			
		||||
@ -131,7 +131,7 @@ pub(crate) async fn inner_intersect(
 | 
			
		||||
        modeling_response: OkModelingCmdResponse::BooleanIntersection(BooleanIntersection { extra_solid_ids }),
 | 
			
		||||
    } = result
 | 
			
		||||
    else {
 | 
			
		||||
        return Err(KclError::Internal(KclErrorDetails::new(
 | 
			
		||||
        return Err(KclError::new_internal(KclErrorDetails::new(
 | 
			
		||||
            "Failed to get the result of the intersection operation.".to_string(),
 | 
			
		||||
            vec![args.source_range],
 | 
			
		||||
        )));
 | 
			
		||||
@ -193,7 +193,7 @@ pub(crate) async fn inner_subtract(
 | 
			
		||||
        modeling_response: OkModelingCmdResponse::BooleanSubtract(BooleanSubtract { extra_solid_ids }),
 | 
			
		||||
    } = result
 | 
			
		||||
    else {
 | 
			
		||||
        return Err(KclError::Internal(KclErrorDetails::new(
 | 
			
		||||
        return Err(KclError::new_internal(KclErrorDetails::new(
 | 
			
		||||
            "Failed to get the result of the subtract operation.".to_string(),
 | 
			
		||||
            vec![args.source_range],
 | 
			
		||||
        )));
 | 
			
		||||
 | 
			
		||||
@ -52,7 +52,7 @@ async fn inner_get_opposite_edge(
 | 
			
		||||
        modeling_response: OkModelingCmdResponse::Solid3dGetOppositeEdge(opposite_edge),
 | 
			
		||||
    } = &resp
 | 
			
		||||
    else {
 | 
			
		||||
        return Err(KclError::Engine(KclErrorDetails::new(
 | 
			
		||||
        return Err(KclError::new_engine(KclErrorDetails::new(
 | 
			
		||||
            format!("mcmd::Solid3dGetOppositeEdge response was not as expected: {:?}", resp),
 | 
			
		||||
            vec![args.source_range],
 | 
			
		||||
        )));
 | 
			
		||||
@ -100,7 +100,7 @@ async fn inner_get_next_adjacent_edge(
 | 
			
		||||
        modeling_response: OkModelingCmdResponse::Solid3dGetNextAdjacentEdge(adjacent_edge),
 | 
			
		||||
    } = &resp
 | 
			
		||||
    else {
 | 
			
		||||
        return Err(KclError::Engine(KclErrorDetails::new(
 | 
			
		||||
        return Err(KclError::new_engine(KclErrorDetails::new(
 | 
			
		||||
            format!(
 | 
			
		||||
                "mcmd::Solid3dGetNextAdjacentEdge response was not as expected: {:?}",
 | 
			
		||||
                resp
 | 
			
		||||
@ -110,7 +110,7 @@ async fn inner_get_next_adjacent_edge(
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    adjacent_edge.edge.ok_or_else(|| {
 | 
			
		||||
        KclError::Type(KclErrorDetails::new(
 | 
			
		||||
        KclError::new_type(KclErrorDetails::new(
 | 
			
		||||
            format!("No edge found next adjacent to tag: `{}`", edge.value),
 | 
			
		||||
            vec![args.source_range],
 | 
			
		||||
        ))
 | 
			
		||||
@ -155,7 +155,7 @@ async fn inner_get_previous_adjacent_edge(
 | 
			
		||||
        modeling_response: OkModelingCmdResponse::Solid3dGetPrevAdjacentEdge(adjacent_edge),
 | 
			
		||||
    } = &resp
 | 
			
		||||
    else {
 | 
			
		||||
        return Err(KclError::Engine(KclErrorDetails::new(
 | 
			
		||||
        return Err(KclError::new_engine(KclErrorDetails::new(
 | 
			
		||||
            format!(
 | 
			
		||||
                "mcmd::Solid3dGetPrevAdjacentEdge response was not as expected: {:?}",
 | 
			
		||||
                resp
 | 
			
		||||
@ -165,7 +165,7 @@ async fn inner_get_previous_adjacent_edge(
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    adjacent_edge.edge.ok_or_else(|| {
 | 
			
		||||
        KclError::Type(KclErrorDetails::new(
 | 
			
		||||
        KclError::new_type(KclErrorDetails::new(
 | 
			
		||||
            format!("No edge found previous adjacent to tag: `{}`", edge.value),
 | 
			
		||||
            vec![args.source_range],
 | 
			
		||||
        ))
 | 
			
		||||
@ -198,7 +198,7 @@ async fn inner_get_common_edge(
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if faces.len() != 2 {
 | 
			
		||||
        return Err(KclError::Type(KclErrorDetails::new(
 | 
			
		||||
        return Err(KclError::new_type(KclErrorDetails::new(
 | 
			
		||||
            "getCommonEdge requires exactly two tags for faces".to_string(),
 | 
			
		||||
            vec![args.source_range],
 | 
			
		||||
        )));
 | 
			
		||||
@ -210,7 +210,7 @@ async fn inner_get_common_edge(
 | 
			
		||||
    let second_tagged_path = args.get_tag_engine_info(exec_state, &faces[1])?;
 | 
			
		||||
 | 
			
		||||
    if first_tagged_path.sketch != second_tagged_path.sketch {
 | 
			
		||||
        return Err(KclError::Type(KclErrorDetails::new(
 | 
			
		||||
        return Err(KclError::new_type(KclErrorDetails::new(
 | 
			
		||||
            "getCommonEdge requires the faces to be in the same original sketch".to_string(),
 | 
			
		||||
            vec![args.source_range],
 | 
			
		||||
        )));
 | 
			
		||||
@ -239,14 +239,14 @@ async fn inner_get_common_edge(
 | 
			
		||||
        modeling_response: OkModelingCmdResponse::Solid3dGetCommonEdge(common_edge),
 | 
			
		||||
    } = &resp
 | 
			
		||||
    else {
 | 
			
		||||
        return Err(KclError::Engine(KclErrorDetails::new(
 | 
			
		||||
        return Err(KclError::new_engine(KclErrorDetails::new(
 | 
			
		||||
            format!("mcmd::Solid3dGetCommonEdge response was not as expected: {:?}", resp),
 | 
			
		||||
            vec![args.source_range],
 | 
			
		||||
        )));
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    common_edge.edge.ok_or_else(|| {
 | 
			
		||||
        KclError::Type(KclErrorDetails::new(
 | 
			
		||||
        KclError::new_type(KclErrorDetails::new(
 | 
			
		||||
            format!(
 | 
			
		||||
                "No common edge was found between `{}` and `{}`",
 | 
			
		||||
                faces[0].value, faces[1].value
 | 
			
		||||
 | 
			
		||||
@ -66,7 +66,7 @@ async fn inner_extrude(
 | 
			
		||||
    let mut solids = Vec::new();
 | 
			
		||||
 | 
			
		||||
    if symmetric.unwrap_or(false) && bidirectional_length.is_some() {
 | 
			
		||||
        return Err(KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
        return Err(KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
            "You cannot give both `symmetric` and `bidirectional` params, you have to choose one or the other"
 | 
			
		||||
                .to_owned(),
 | 
			
		||||
            vec![args.source_range],
 | 
			
		||||
@ -153,7 +153,7 @@ pub(crate) async fn do_post_extrude<'a>(
 | 
			
		||||
        // The "get extrusion face info" API call requires *any* edge on the sketch being extruded.
 | 
			
		||||
        // So, let's just use the first one.
 | 
			
		||||
        let Some(any_edge_id) = sketch.paths.first().map(|edge| edge.get_base().geo_meta.id) else {
 | 
			
		||||
            return Err(KclError::Type(KclErrorDetails::new(
 | 
			
		||||
            return Err(KclError::new_type(KclErrorDetails::new(
 | 
			
		||||
                "Expected a non-empty sketch".to_owned(),
 | 
			
		||||
                vec![args.source_range],
 | 
			
		||||
            )));
 | 
			
		||||
@ -278,7 +278,7 @@ pub(crate) async fn do_post_extrude<'a>(
 | 
			
		||||
    // Add the tags for the start or end caps.
 | 
			
		||||
    if let Some(tag_start) = named_cap_tags.start {
 | 
			
		||||
        let Some(start_cap_id) = start_cap_id else {
 | 
			
		||||
            return Err(KclError::Type(KclErrorDetails::new(
 | 
			
		||||
            return Err(KclError::new_type(KclErrorDetails::new(
 | 
			
		||||
                format!(
 | 
			
		||||
                    "Expected a start cap ID for tag `{}` for extrusion of sketch {:?}",
 | 
			
		||||
                    tag_start.name, sketch.id
 | 
			
		||||
@ -298,7 +298,7 @@ pub(crate) async fn do_post_extrude<'a>(
 | 
			
		||||
    }
 | 
			
		||||
    if let Some(tag_end) = named_cap_tags.end {
 | 
			
		||||
        let Some(end_cap_id) = end_cap_id else {
 | 
			
		||||
            return Err(KclError::Type(KclErrorDetails::new(
 | 
			
		||||
            return Err(KclError::new_type(KclErrorDetails::new(
 | 
			
		||||
                format!(
 | 
			
		||||
                    "Expected an end cap ID for tag `{}` for extrusion of sketch {:?}",
 | 
			
		||||
                    tag_end.name, sketch.id
 | 
			
		||||
 | 
			
		||||
@ -49,7 +49,7 @@ pub(super) fn validate_unique<T: Eq + std::hash::Hash>(tags: &[(T, SourceRange)]
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    if !duplicate_tags_source.is_empty() {
 | 
			
		||||
        return Err(KclError::Type(KclErrorDetails::new(
 | 
			
		||||
        return Err(KclError::new_type(KclErrorDetails::new(
 | 
			
		||||
            "The same edge ID is being referenced multiple times, which is not allowed. Please select a different edge"
 | 
			
		||||
                .to_string(),
 | 
			
		||||
            duplicate_tags_source,
 | 
			
		||||
@ -85,14 +85,14 @@ async fn inner_fillet(
 | 
			
		||||
    // If you try and tag multiple edges with a tagged fillet, we want to return an
 | 
			
		||||
    // error to the user that they can only tag one edge at a time.
 | 
			
		||||
    if tag.is_some() && tags.len() > 1 {
 | 
			
		||||
        return Err(KclError::Type(KclErrorDetails {
 | 
			
		||||
        return Err(KclError::new_type(KclErrorDetails {
 | 
			
		||||
            message: "You can only tag one edge at a time with a tagged fillet. Either delete the tag for the fillet fn if you don't need it OR separate into individual fillet functions for each tag.".to_string(),
 | 
			
		||||
            source_ranges: vec![args.source_range],
 | 
			
		||||
            backtrace: Default::default(),
 | 
			
		||||
        }));
 | 
			
		||||
    }
 | 
			
		||||
    if tags.is_empty() {
 | 
			
		||||
        return Err(KclError::Semantic(KclErrorDetails {
 | 
			
		||||
        return Err(KclError::new_semantic(KclErrorDetails {
 | 
			
		||||
            source_ranges: vec![args.source_range],
 | 
			
		||||
            message: "You must fillet at least one tag".to_owned(),
 | 
			
		||||
            backtrace: Default::default(),
 | 
			
		||||
 | 
			
		||||
@ -33,7 +33,7 @@ pub async fn helix(exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
 | 
			
		||||
 | 
			
		||||
    // Make sure we have a radius if we don't have a cylinder.
 | 
			
		||||
    if radius.is_none() && cylinder.is_none() {
 | 
			
		||||
        return Err(KclError::Semantic(crate::errors::KclErrorDetails::new(
 | 
			
		||||
        return Err(KclError::new_semantic(crate::errors::KclErrorDetails::new(
 | 
			
		||||
            "Radius is required when creating a helix without a cylinder.".to_string(),
 | 
			
		||||
            vec![args.source_range],
 | 
			
		||||
        )));
 | 
			
		||||
@ -41,7 +41,7 @@ pub async fn helix(exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
 | 
			
		||||
 | 
			
		||||
    // Make sure we don't have a radius if we have a cylinder.
 | 
			
		||||
    if radius.is_some() && cylinder.is_some() {
 | 
			
		||||
        return Err(KclError::Semantic(crate::errors::KclErrorDetails::new(
 | 
			
		||||
        return Err(KclError::new_semantic(crate::errors::KclErrorDetails::new(
 | 
			
		||||
            "Radius is not allowed when creating a helix with a cylinder.".to_string(),
 | 
			
		||||
            vec![args.source_range],
 | 
			
		||||
        )));
 | 
			
		||||
@ -49,7 +49,7 @@ pub async fn helix(exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
 | 
			
		||||
 | 
			
		||||
    // Make sure we have an axis if we don't have a cylinder.
 | 
			
		||||
    if axis.is_none() && cylinder.is_none() {
 | 
			
		||||
        return Err(KclError::Semantic(crate::errors::KclErrorDetails::new(
 | 
			
		||||
        return Err(KclError::new_semantic(crate::errors::KclErrorDetails::new(
 | 
			
		||||
            "Axis is required when creating a helix without a cylinder.".to_string(),
 | 
			
		||||
            vec![args.source_range],
 | 
			
		||||
        )));
 | 
			
		||||
@ -57,7 +57,7 @@ pub async fn helix(exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
 | 
			
		||||
 | 
			
		||||
    // Make sure we don't have an axis if we have a cylinder.
 | 
			
		||||
    if axis.is_some() && cylinder.is_some() {
 | 
			
		||||
        return Err(KclError::Semantic(crate::errors::KclErrorDetails::new(
 | 
			
		||||
        return Err(KclError::new_semantic(crate::errors::KclErrorDetails::new(
 | 
			
		||||
            "Axis is not allowed when creating a helix with a cylinder.".to_string(),
 | 
			
		||||
            vec![args.source_range],
 | 
			
		||||
        )));
 | 
			
		||||
@ -65,7 +65,7 @@ pub async fn helix(exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
 | 
			
		||||
 | 
			
		||||
    // Make sure we have a radius if we have an axis.
 | 
			
		||||
    if radius.is_none() && axis.is_some() {
 | 
			
		||||
        return Err(KclError::Semantic(crate::errors::KclErrorDetails::new(
 | 
			
		||||
        return Err(KclError::new_semantic(crate::errors::KclErrorDetails::new(
 | 
			
		||||
            "Radius is required when creating a helix around an axis.".to_string(),
 | 
			
		||||
            vec![args.source_range],
 | 
			
		||||
        )));
 | 
			
		||||
@ -73,7 +73,7 @@ pub async fn helix(exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
 | 
			
		||||
 | 
			
		||||
    // Make sure we have an axis if we have a radius.
 | 
			
		||||
    if axis.is_none() && radius.is_some() {
 | 
			
		||||
        return Err(KclError::Semantic(crate::errors::KclErrorDetails::new(
 | 
			
		||||
        return Err(KclError::new_semantic(crate::errors::KclErrorDetails::new(
 | 
			
		||||
            "Axis is required when creating a helix around an axis.".to_string(),
 | 
			
		||||
            vec![args.source_range],
 | 
			
		||||
        )));
 | 
			
		||||
@ -140,7 +140,7 @@ async fn inner_helix(
 | 
			
		||||
            Axis3dOrEdgeReference::Axis { direction, origin } => {
 | 
			
		||||
                // Make sure they gave us a length.
 | 
			
		||||
                let Some(length) = length else {
 | 
			
		||||
                    return Err(KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
                    return Err(KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
                        "Length is required when creating a helix around an axis.".to_owned(),
 | 
			
		||||
                        vec![args.source_range],
 | 
			
		||||
                    )));
 | 
			
		||||
 | 
			
		||||
@ -68,7 +68,7 @@ async fn inner_loft(
 | 
			
		||||
) -> Result<Box<Solid>, KclError> {
 | 
			
		||||
    // Make sure we have at least two sketches.
 | 
			
		||||
    if sketches.len() < 2 {
 | 
			
		||||
        return Err(KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
        return Err(KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
            format!(
 | 
			
		||||
                "Loft requires at least two sketches, but only {} were provided.",
 | 
			
		||||
                sketches.len()
 | 
			
		||||
 | 
			
		||||
@ -56,7 +56,7 @@ pub async fn sqrt(exec_state: &mut ExecState, args: Args) -> Result<KclValue, Kc
 | 
			
		||||
    let input: TyF64 = args.get_unlabeled_kw_arg_typed("input", &RuntimeType::num_any(), exec_state)?;
 | 
			
		||||
 | 
			
		||||
    if input.n < 0.0 {
 | 
			
		||||
        return Err(KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
        return Err(KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
            format!(
 | 
			
		||||
                "Attempt to take square root (`sqrt`) of a number less than zero ({})",
 | 
			
		||||
                input.n
 | 
			
		||||
 | 
			
		||||
@ -101,7 +101,7 @@ async fn inner_mirror_2d(
 | 
			
		||||
                OkModelingCmdResponse::EntityGetAllChildUuids(EntityGetAllChildUuids { entity_ids: child_ids }),
 | 
			
		||||
        } = response
 | 
			
		||||
        else {
 | 
			
		||||
            return Err(KclError::Internal(KclErrorDetails::new(
 | 
			
		||||
            return Err(KclError::new_internal(KclErrorDetails::new(
 | 
			
		||||
                "Expected a successful response from EntityGetAllChildUuids".to_string(),
 | 
			
		||||
                vec![args.source_range],
 | 
			
		||||
            )));
 | 
			
		||||
@ -112,7 +112,7 @@ async fn inner_mirror_2d(
 | 
			
		||||
            let child_id = child_ids[1];
 | 
			
		||||
            sketch.mirror = Some(child_id);
 | 
			
		||||
        } else {
 | 
			
		||||
            return Err(KclError::Type(KclErrorDetails::new(
 | 
			
		||||
            return Err(KclError::new_type(KclErrorDetails::new(
 | 
			
		||||
                "Expected child uuids to be >= 2".to_string(),
 | 
			
		||||
                vec![args.source_range],
 | 
			
		||||
            )));
 | 
			
		||||
 | 
			
		||||
@ -66,7 +66,7 @@ async fn inner_pattern_transform<'a>(
 | 
			
		||||
    // Build the vec of transforms, one for each repetition.
 | 
			
		||||
    let mut transform_vec = Vec::with_capacity(usize::try_from(instances).unwrap());
 | 
			
		||||
    if instances < 1 {
 | 
			
		||||
        return Err(KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
        return Err(KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
            MUST_HAVE_ONE_INSTANCE.to_owned(),
 | 
			
		||||
            vec![args.source_range],
 | 
			
		||||
        )));
 | 
			
		||||
@ -96,7 +96,7 @@ async fn inner_pattern_transform_2d<'a>(
 | 
			
		||||
    // Build the vec of transforms, one for each repetition.
 | 
			
		||||
    let mut transform_vec = Vec::with_capacity(usize::try_from(instances).unwrap());
 | 
			
		||||
    if instances < 1 {
 | 
			
		||||
        return Err(KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
        return Err(KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
            MUST_HAVE_ONE_INSTANCE.to_owned(),
 | 
			
		||||
            vec![args.source_range],
 | 
			
		||||
        )));
 | 
			
		||||
@ -176,7 +176,7 @@ async fn send_pattern_transform<T: GeometryTrait>(
 | 
			
		||||
        }
 | 
			
		||||
        &mock_ids
 | 
			
		||||
    } else {
 | 
			
		||||
        return Err(KclError::Engine(KclErrorDetails::new(
 | 
			
		||||
        return Err(KclError::new_engine(KclErrorDetails::new(
 | 
			
		||||
            format!("EntityLinearPattern response was not as expected: {:?}", resp),
 | 
			
		||||
            vec![args.source_range],
 | 
			
		||||
        )));
 | 
			
		||||
@ -222,7 +222,7 @@ async fn make_transform<T: GeometryTrait>(
 | 
			
		||||
    // Unpack the returned transform object.
 | 
			
		||||
    let source_ranges = vec![source_range];
 | 
			
		||||
    let transform_fn_return = transform_fn_return.ok_or_else(|| {
 | 
			
		||||
        KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
        KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
            "Transform function must return a value".to_string(),
 | 
			
		||||
            source_ranges.clone(),
 | 
			
		||||
        ))
 | 
			
		||||
@ -233,7 +233,7 @@ async fn make_transform<T: GeometryTrait>(
 | 
			
		||||
            let transforms: Vec<_> = value
 | 
			
		||||
                .into_iter()
 | 
			
		||||
                .map(|val| {
 | 
			
		||||
                    val.into_object().ok_or(KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
                    val.into_object().ok_or(KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
                        "Transform function must return a transform object".to_string(),
 | 
			
		||||
                        source_ranges.clone(),
 | 
			
		||||
                    )))
 | 
			
		||||
@ -242,7 +242,7 @@ async fn make_transform<T: GeometryTrait>(
 | 
			
		||||
            transforms
 | 
			
		||||
        }
 | 
			
		||||
        _ => {
 | 
			
		||||
            return Err(KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
            return Err(KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
                "Transform function must return a transform object".to_string(),
 | 
			
		||||
                source_ranges.clone(),
 | 
			
		||||
            )))
 | 
			
		||||
@ -265,7 +265,7 @@ fn transform_from_obj_fields<T: GeometryTrait>(
 | 
			
		||||
        Some(KclValue::Bool { value: true, .. }) => true,
 | 
			
		||||
        Some(KclValue::Bool { value: false, .. }) => false,
 | 
			
		||||
        Some(_) => {
 | 
			
		||||
            return Err(KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
            return Err(KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
                "The 'replicate' key must be a bool".to_string(),
 | 
			
		||||
                source_ranges.clone(),
 | 
			
		||||
            )));
 | 
			
		||||
@ -297,7 +297,7 @@ fn transform_from_obj_fields<T: GeometryTrait>(
 | 
			
		||||
    let mut rotation = Rotation::default();
 | 
			
		||||
    if let Some(rot) = transform.get("rotation") {
 | 
			
		||||
        let KclValue::Object { value: rot, meta: _ } = rot else {
 | 
			
		||||
            return Err(KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
            return Err(KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
                "The 'rotation' key must be an object (with optional fields 'angle', 'axis' and 'origin')".to_owned(),
 | 
			
		||||
                source_ranges.clone(),
 | 
			
		||||
            )));
 | 
			
		||||
@ -311,7 +311,7 @@ fn transform_from_obj_fields<T: GeometryTrait>(
 | 
			
		||||
                    rotation.angle = Angle::from_degrees(*number);
 | 
			
		||||
                }
 | 
			
		||||
                _ => {
 | 
			
		||||
                    return Err(KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
                    return Err(KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
                        "The 'rotation.angle' key must be a number (of degrees)".to_owned(),
 | 
			
		||||
                        source_ranges.clone(),
 | 
			
		||||
                    )));
 | 
			
		||||
@ -345,7 +345,7 @@ fn array_to_point3d(
 | 
			
		||||
) -> Result<[TyF64; 3], KclError> {
 | 
			
		||||
    val.coerce(&RuntimeType::point3d(), true, exec_state)
 | 
			
		||||
        .map_err(|e| {
 | 
			
		||||
            KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
            KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
                format!(
 | 
			
		||||
                    "Expected an array of 3 numbers (i.e., a 3D point), found {}",
 | 
			
		||||
                    e.found
 | 
			
		||||
@ -365,7 +365,7 @@ fn array_to_point2d(
 | 
			
		||||
) -> Result<[TyF64; 2], KclError> {
 | 
			
		||||
    val.coerce(&RuntimeType::point2d(), true, exec_state)
 | 
			
		||||
        .map_err(|e| {
 | 
			
		||||
            KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
            KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
                format!(
 | 
			
		||||
                    "Expected an array of 2 numbers (i.e., a 2D point), found {}",
 | 
			
		||||
                    e.found
 | 
			
		||||
@ -534,7 +534,7 @@ pub async fn pattern_linear_2d(exec_state: &mut ExecState, args: Args) -> Result
 | 
			
		||||
 | 
			
		||||
    let axis = axis.to_point2d();
 | 
			
		||||
    if axis[0].n == 0.0 && axis[1].n == 0.0 {
 | 
			
		||||
        return Err(KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
        return Err(KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
            "The axis of the linear pattern cannot be the zero vector. Otherwise they will just duplicate in place."
 | 
			
		||||
                .to_owned(),
 | 
			
		||||
            vec![args.source_range],
 | 
			
		||||
@ -594,7 +594,7 @@ pub async fn pattern_linear_3d(exec_state: &mut ExecState, args: Args) -> Result
 | 
			
		||||
 | 
			
		||||
    let axis = axis.to_point3d();
 | 
			
		||||
    if axis[0].n == 0.0 && axis[1].n == 0.0 && axis[2].n == 0.0 {
 | 
			
		||||
        return Err(KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
        return Err(KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
            "The axis of the linear pattern cannot be the zero vector. Otherwise they will just duplicate in place."
 | 
			
		||||
                .to_owned(),
 | 
			
		||||
            vec![args.source_range],
 | 
			
		||||
@ -803,7 +803,7 @@ async fn inner_pattern_circular_2d(
 | 
			
		||||
        .await?;
 | 
			
		||||
 | 
			
		||||
        let Geometries::Sketches(new_sketches) = geometries else {
 | 
			
		||||
            return Err(KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
            return Err(KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
                "Expected a vec of sketches".to_string(),
 | 
			
		||||
                vec![args.source_range],
 | 
			
		||||
            )));
 | 
			
		||||
@ -901,7 +901,7 @@ async fn inner_pattern_circular_3d(
 | 
			
		||||
        .await?;
 | 
			
		||||
 | 
			
		||||
        let Geometries::Solids(new_solids) = geometries else {
 | 
			
		||||
            return Err(KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
            return Err(KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
                "Expected a vec of solids".to_string(),
 | 
			
		||||
                vec![args.source_range],
 | 
			
		||||
            )));
 | 
			
		||||
@ -926,7 +926,7 @@ async fn pattern_circular(
 | 
			
		||||
            return Ok(Geometries::from(geometry));
 | 
			
		||||
        }
 | 
			
		||||
        RepetitionsNeeded::Invalid => {
 | 
			
		||||
            return Err(KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
            return Err(KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
                MUST_HAVE_ONE_INSTANCE.to_owned(),
 | 
			
		||||
                vec![args.source_range],
 | 
			
		||||
            )));
 | 
			
		||||
@ -971,7 +971,7 @@ async fn pattern_circular(
 | 
			
		||||
        }
 | 
			
		||||
        &mock_ids
 | 
			
		||||
    } else {
 | 
			
		||||
        return Err(KclError::Engine(KclErrorDetails::new(
 | 
			
		||||
        return Err(KclError::new_engine(KclErrorDetails::new(
 | 
			
		||||
            format!("EntityCircularPattern response was not as expected: {:?}", resp),
 | 
			
		||||
            vec![args.source_range],
 | 
			
		||||
        )));
 | 
			
		||||
 | 
			
		||||
@ -75,7 +75,7 @@ async fn inner_revolve(
 | 
			
		||||
        // We don't use validate() here because we want to return a specific error message that is
 | 
			
		||||
        // nice and we use the other data in the docs, so we still need use the derive above for the json schema.
 | 
			
		||||
        if !(-360.0..=360.0).contains(&angle) || angle == 0.0 {
 | 
			
		||||
            return Err(KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
            return Err(KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
                format!("Expected angle to be between -360 and 360 and not 0, found `{}`", angle),
 | 
			
		||||
                vec![args.source_range],
 | 
			
		||||
            )));
 | 
			
		||||
@ -87,7 +87,7 @@ async fn inner_revolve(
 | 
			
		||||
        // We don't use validate() here because we want to return a specific error message that is
 | 
			
		||||
        // nice and we use the other data in the docs, so we still need use the derive above for the json schema.
 | 
			
		||||
        if !(-360.0..=360.0).contains(&bidirectional_angle) || bidirectional_angle == 0.0 {
 | 
			
		||||
            return Err(KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
            return Err(KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
                format!(
 | 
			
		||||
                    "Expected bidirectional angle to be between -360 and 360 and not 0, found `{}`",
 | 
			
		||||
                    bidirectional_angle
 | 
			
		||||
@ -99,7 +99,7 @@ async fn inner_revolve(
 | 
			
		||||
        if let Some(angle) = angle {
 | 
			
		||||
            let ang = angle.signum() * bidirectional_angle + angle;
 | 
			
		||||
            if !(-360.0..=360.0).contains(&ang) {
 | 
			
		||||
                return Err(KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
                return Err(KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
                    format!(
 | 
			
		||||
                        "Combined angle and bidirectional must be between -360 and 360, found '{}'",
 | 
			
		||||
                        ang
 | 
			
		||||
@ -111,7 +111,7 @@ async fn inner_revolve(
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if symmetric.unwrap_or(false) && bidirectional_angle.is_some() {
 | 
			
		||||
        return Err(KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
        return Err(KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
            "You cannot give both `symmetric` and `bidirectional` params, you have to choose one or the other"
 | 
			
		||||
                .to_owned(),
 | 
			
		||||
            vec![args.source_range],
 | 
			
		||||
 | 
			
		||||
@ -58,7 +58,7 @@ pub async fn segment_end(exec_state: &mut ExecState, args: Args) -> Result<KclVa
 | 
			
		||||
fn inner_segment_end(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<[TyF64; 2], KclError> {
 | 
			
		||||
    let line = args.get_tag_engine_info(exec_state, tag)?;
 | 
			
		||||
    let path = line.path.clone().ok_or_else(|| {
 | 
			
		||||
        KclError::Type(KclErrorDetails::new(
 | 
			
		||||
        KclError::new_type(KclErrorDetails::new(
 | 
			
		||||
            format!("Expected a line segment with a path, found `{:?}`", line),
 | 
			
		||||
            vec![args.source_range],
 | 
			
		||||
        ))
 | 
			
		||||
@ -102,7 +102,7 @@ pub async fn segment_end_x(exec_state: &mut ExecState, args: Args) -> Result<Kcl
 | 
			
		||||
fn inner_segment_end_x(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<TyF64, KclError> {
 | 
			
		||||
    let line = args.get_tag_engine_info(exec_state, tag)?;
 | 
			
		||||
    let path = line.path.clone().ok_or_else(|| {
 | 
			
		||||
        KclError::Type(KclErrorDetails::new(
 | 
			
		||||
        KclError::new_type(KclErrorDetails::new(
 | 
			
		||||
            format!("Expected a line segment with a path, found `{:?}`", line),
 | 
			
		||||
            vec![args.source_range],
 | 
			
		||||
        ))
 | 
			
		||||
@ -144,7 +144,7 @@ pub async fn segment_end_y(exec_state: &mut ExecState, args: Args) -> Result<Kcl
 | 
			
		||||
fn inner_segment_end_y(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<TyF64, KclError> {
 | 
			
		||||
    let line = args.get_tag_engine_info(exec_state, tag)?;
 | 
			
		||||
    let path = line.path.clone().ok_or_else(|| {
 | 
			
		||||
        KclError::Type(KclErrorDetails::new(
 | 
			
		||||
        KclError::new_type(KclErrorDetails::new(
 | 
			
		||||
            format!("Expected a line segment with a path, found `{:?}`", line),
 | 
			
		||||
            vec![args.source_range],
 | 
			
		||||
        ))
 | 
			
		||||
@ -197,7 +197,7 @@ pub async fn segment_start(exec_state: &mut ExecState, args: Args) -> Result<Kcl
 | 
			
		||||
fn inner_segment_start(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<[TyF64; 2], KclError> {
 | 
			
		||||
    let line = args.get_tag_engine_info(exec_state, tag)?;
 | 
			
		||||
    let path = line.path.clone().ok_or_else(|| {
 | 
			
		||||
        KclError::Type(KclErrorDetails::new(
 | 
			
		||||
        KclError::new_type(KclErrorDetails::new(
 | 
			
		||||
            format!("Expected a line segment with a path, found `{:?}`", line),
 | 
			
		||||
            vec![args.source_range],
 | 
			
		||||
        ))
 | 
			
		||||
@ -241,7 +241,7 @@ pub async fn segment_start_x(exec_state: &mut ExecState, args: Args) -> Result<K
 | 
			
		||||
fn inner_segment_start_x(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<TyF64, KclError> {
 | 
			
		||||
    let line = args.get_tag_engine_info(exec_state, tag)?;
 | 
			
		||||
    let path = line.path.clone().ok_or_else(|| {
 | 
			
		||||
        KclError::Type(KclErrorDetails::new(
 | 
			
		||||
        KclError::new_type(KclErrorDetails::new(
 | 
			
		||||
            format!("Expected a line segment with a path, found `{:?}`", line),
 | 
			
		||||
            vec![args.source_range],
 | 
			
		||||
        ))
 | 
			
		||||
@ -283,7 +283,7 @@ pub async fn segment_start_y(exec_state: &mut ExecState, args: Args) -> Result<K
 | 
			
		||||
fn inner_segment_start_y(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<TyF64, KclError> {
 | 
			
		||||
    let line = args.get_tag_engine_info(exec_state, tag)?;
 | 
			
		||||
    let path = line.path.clone().ok_or_else(|| {
 | 
			
		||||
        KclError::Type(KclErrorDetails::new(
 | 
			
		||||
        KclError::new_type(KclErrorDetails::new(
 | 
			
		||||
            format!("Expected a line segment with a path, found `{:?}`", line),
 | 
			
		||||
            vec![args.source_range],
 | 
			
		||||
        ))
 | 
			
		||||
@ -327,7 +327,7 @@ fn inner_last_segment_x(sketch: Sketch, args: Args) -> Result<TyF64, KclError> {
 | 
			
		||||
        .paths
 | 
			
		||||
        .last()
 | 
			
		||||
        .ok_or_else(|| {
 | 
			
		||||
            KclError::Type(KclErrorDetails::new(
 | 
			
		||||
            KclError::new_type(KclErrorDetails::new(
 | 
			
		||||
                format!("Expected a Sketch with at least one segment, found `{:?}`", sketch),
 | 
			
		||||
                vec![args.source_range],
 | 
			
		||||
            ))
 | 
			
		||||
@ -373,7 +373,7 @@ fn inner_last_segment_y(sketch: Sketch, args: Args) -> Result<TyF64, KclError> {
 | 
			
		||||
        .paths
 | 
			
		||||
        .last()
 | 
			
		||||
        .ok_or_else(|| {
 | 
			
		||||
            KclError::Type(KclErrorDetails::new(
 | 
			
		||||
            KclError::new_type(KclErrorDetails::new(
 | 
			
		||||
                format!("Expected a Sketch with at least one segment, found `{:?}`", sketch),
 | 
			
		||||
                vec![args.source_range],
 | 
			
		||||
            ))
 | 
			
		||||
@ -420,7 +420,7 @@ pub async fn segment_length(exec_state: &mut ExecState, args: Args) -> Result<Kc
 | 
			
		||||
fn inner_segment_length(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<TyF64, KclError> {
 | 
			
		||||
    let line = args.get_tag_engine_info(exec_state, tag)?;
 | 
			
		||||
    let path = line.path.clone().ok_or_else(|| {
 | 
			
		||||
        KclError::Type(KclErrorDetails::new(
 | 
			
		||||
        KclError::new_type(KclErrorDetails::new(
 | 
			
		||||
            format!("Expected a line segment with a path, found `{:?}`", line),
 | 
			
		||||
            vec![args.source_range],
 | 
			
		||||
        ))
 | 
			
		||||
@ -463,7 +463,7 @@ pub async fn segment_angle(exec_state: &mut ExecState, args: Args) -> Result<Kcl
 | 
			
		||||
fn inner_segment_angle(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<f64, KclError> {
 | 
			
		||||
    let line = args.get_tag_engine_info(exec_state, tag)?;
 | 
			
		||||
    let path = line.path.clone().ok_or_else(|| {
 | 
			
		||||
        KclError::Type(KclErrorDetails::new(
 | 
			
		||||
        KclError::new_type(KclErrorDetails::new(
 | 
			
		||||
            format!("Expected a line segment with a path, found `{:?}`", line),
 | 
			
		||||
            vec![args.source_range],
 | 
			
		||||
        ))
 | 
			
		||||
@ -564,7 +564,7 @@ pub async fn tangent_to_end(exec_state: &mut ExecState, args: Args) -> Result<Kc
 | 
			
		||||
async fn inner_tangent_to_end(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<f64, KclError> {
 | 
			
		||||
    let line = args.get_tag_engine_info(exec_state, tag)?;
 | 
			
		||||
    let path = line.path.clone().ok_or_else(|| {
 | 
			
		||||
        KclError::Type(KclErrorDetails::new(
 | 
			
		||||
        KclError::new_type(KclErrorDetails::new(
 | 
			
		||||
            format!("Expected a line segment with a path, found `{:?}`", line),
 | 
			
		||||
            vec![args.source_range],
 | 
			
		||||
        ))
 | 
			
		||||
 | 
			
		||||
@ -271,14 +271,14 @@ async fn inner_polygon(
 | 
			
		||||
    args: Args,
 | 
			
		||||
) -> Result<Sketch, KclError> {
 | 
			
		||||
    if num_sides < 3 {
 | 
			
		||||
        return Err(KclError::Type(KclErrorDetails::new(
 | 
			
		||||
        return Err(KclError::new_type(KclErrorDetails::new(
 | 
			
		||||
            "Polygon must have at least 3 sides".to_string(),
 | 
			
		||||
            vec![args.source_range],
 | 
			
		||||
        )));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if radius.n <= 0.0 {
 | 
			
		||||
        return Err(KclError::Type(KclErrorDetails::new(
 | 
			
		||||
        return Err(KclError::new_type(KclErrorDetails::new(
 | 
			
		||||
            "Radius must be greater than 0".to_string(),
 | 
			
		||||
            vec![args.source_range],
 | 
			
		||||
        )));
 | 
			
		||||
@ -407,11 +407,11 @@ pub(crate) fn get_radius(
 | 
			
		||||
    match (radius, diameter) {
 | 
			
		||||
        (Some(radius), None) => Ok(radius),
 | 
			
		||||
        (None, Some(diameter)) => Ok(TyF64::new(diameter.n / 2.0, diameter.ty)),
 | 
			
		||||
        (None, None) => Err(KclError::Type(KclErrorDetails::new(
 | 
			
		||||
        (None, None) => Err(KclError::new_type(KclErrorDetails::new(
 | 
			
		||||
            "This function needs either `diameter` or `radius`".to_string(),
 | 
			
		||||
            vec![source_range],
 | 
			
		||||
        ))),
 | 
			
		||||
        (Some(_), Some(_)) => Err(KclError::Type(KclErrorDetails::new(
 | 
			
		||||
        (Some(_), Some(_)) => Err(KclError::new_type(KclErrorDetails::new(
 | 
			
		||||
            "You cannot specify both `diameter` and `radius`, please remove one".to_string(),
 | 
			
		||||
            vec![source_range],
 | 
			
		||||
        ))),
 | 
			
		||||
 | 
			
		||||
@ -36,14 +36,14 @@ async fn inner_shell(
 | 
			
		||||
    args: Args,
 | 
			
		||||
) -> Result<Vec<Solid>, KclError> {
 | 
			
		||||
    if faces.is_empty() {
 | 
			
		||||
        return Err(KclError::Type(KclErrorDetails::new(
 | 
			
		||||
        return Err(KclError::new_type(KclErrorDetails::new(
 | 
			
		||||
            "You must shell at least one face".to_owned(),
 | 
			
		||||
            vec![args.source_range],
 | 
			
		||||
        )));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if solids.is_empty() {
 | 
			
		||||
        return Err(KclError::Type(KclErrorDetails::new(
 | 
			
		||||
        return Err(KclError::new_type(KclErrorDetails::new(
 | 
			
		||||
            "You must shell at least one solid".to_owned(),
 | 
			
		||||
            vec![args.source_range],
 | 
			
		||||
        )));
 | 
			
		||||
@ -63,7 +63,7 @@ async fn inner_shell(
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if face_ids.is_empty() {
 | 
			
		||||
        return Err(KclError::Type(KclErrorDetails::new(
 | 
			
		||||
        return Err(KclError::new_type(KclErrorDetails::new(
 | 
			
		||||
            "Expected at least one valid face".to_owned(),
 | 
			
		||||
            vec![args.source_range],
 | 
			
		||||
        )));
 | 
			
		||||
@ -72,7 +72,7 @@ async fn inner_shell(
 | 
			
		||||
    // Make sure all the solids have the same id, as we are going to shell them all at
 | 
			
		||||
    // once.
 | 
			
		||||
    if !solids.iter().all(|eg| eg.id == solids[0].id) {
 | 
			
		||||
        return Err(KclError::Type(KclErrorDetails::new(
 | 
			
		||||
        return Err(KclError::new_type(KclErrorDetails::new(
 | 
			
		||||
            "All solids stem from the same root object, like multiple sketch on face extrusions, etc.".to_owned(),
 | 
			
		||||
            vec![args.source_range],
 | 
			
		||||
        )));
 | 
			
		||||
 | 
			
		||||
@ -65,13 +65,13 @@ impl FaceTag {
 | 
			
		||||
        match self {
 | 
			
		||||
            FaceTag::Tag(ref t) => args.get_adjacent_face_to_tag(exec_state, t, must_be_planar).await,
 | 
			
		||||
            FaceTag::StartOrEnd(StartOrEnd::Start) => solid.start_cap_id.ok_or_else(|| {
 | 
			
		||||
                KclError::Type(KclErrorDetails::new(
 | 
			
		||||
                KclError::new_type(KclErrorDetails::new(
 | 
			
		||||
                    "Expected a start face".to_string(),
 | 
			
		||||
                    vec![args.source_range],
 | 
			
		||||
                ))
 | 
			
		||||
            }),
 | 
			
		||||
            FaceTag::StartOrEnd(StartOrEnd::End) => solid.end_cap_id.ok_or_else(|| {
 | 
			
		||||
                KclError::Type(KclErrorDetails::new(
 | 
			
		||||
                KclError::new_type(KclErrorDetails::new(
 | 
			
		||||
                    "Expected an end face".to_string(),
 | 
			
		||||
                    vec![args.source_range],
 | 
			
		||||
                ))
 | 
			
		||||
@ -328,7 +328,7 @@ async fn straight_line(
 | 
			
		||||
    let from = sketch.current_pen_position()?;
 | 
			
		||||
    let (point, is_absolute) = match (end_absolute, end) {
 | 
			
		||||
        (Some(_), Some(_)) => {
 | 
			
		||||
            return Err(KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
            return Err(KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
                "You cannot give both `end` and `endAbsolute` params, you have to choose one or the other".to_owned(),
 | 
			
		||||
                vec![args.source_range],
 | 
			
		||||
            )));
 | 
			
		||||
@ -336,7 +336,7 @@ async fn straight_line(
 | 
			
		||||
        (Some(end_absolute), None) => (end_absolute, true),
 | 
			
		||||
        (None, Some(end)) => (end, false),
 | 
			
		||||
        (None, None) => {
 | 
			
		||||
            return Err(KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
            return Err(KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
                format!("You must supply either `{relative_name}` or `endAbsolute` arguments"),
 | 
			
		||||
                vec![args.source_range],
 | 
			
		||||
            )));
 | 
			
		||||
@ -603,7 +603,7 @@ async fn inner_angled_line(
 | 
			
		||||
        .filter(|x| x.is_some())
 | 
			
		||||
        .count();
 | 
			
		||||
    if options_given > 1 {
 | 
			
		||||
        return Err(KclError::Type(KclErrorDetails::new(
 | 
			
		||||
        return Err(KclError::new_type(KclErrorDetails::new(
 | 
			
		||||
            " one of `length`, `lengthX`, `lengthY`, `endAbsoluteX`, `endAbsoluteY` can be given".to_string(),
 | 
			
		||||
            vec![args.source_range],
 | 
			
		||||
        )));
 | 
			
		||||
@ -631,11 +631,11 @@ async fn inner_angled_line(
 | 
			
		||||
        (None, None, None, None, Some(end_absolute_y)) => {
 | 
			
		||||
            inner_angled_line_to_y(angle_degrees, end_absolute_y, sketch, tag, exec_state, args).await
 | 
			
		||||
        }
 | 
			
		||||
        (None, None, None, None, None) => Err(KclError::Type(KclErrorDetails::new(
 | 
			
		||||
        (None, None, None, None, None) => Err(KclError::new_type(KclErrorDetails::new(
 | 
			
		||||
            "One of `length`, `lengthX`, `lengthY`, `endAbsoluteX`, `endAbsoluteY` must be given".to_string(),
 | 
			
		||||
            vec![args.source_range],
 | 
			
		||||
        ))),
 | 
			
		||||
        _ => Err(KclError::Type(KclErrorDetails::new(
 | 
			
		||||
        _ => Err(KclError::new_type(KclErrorDetails::new(
 | 
			
		||||
            "Only One of `length`, `lengthX`, `lengthY`, `endAbsoluteX`, `endAbsoluteY` can be given".to_owned(),
 | 
			
		||||
            vec![args.source_range],
 | 
			
		||||
        ))),
 | 
			
		||||
@ -709,14 +709,14 @@ async fn inner_angled_line_of_x_length(
 | 
			
		||||
    args: Args,
 | 
			
		||||
) -> Result<Sketch, KclError> {
 | 
			
		||||
    if angle_degrees.abs() == 270.0 {
 | 
			
		||||
        return Err(KclError::Type(KclErrorDetails::new(
 | 
			
		||||
        return Err(KclError::new_type(KclErrorDetails::new(
 | 
			
		||||
            "Cannot have an x constrained angle of 270 degrees".to_string(),
 | 
			
		||||
            vec![args.source_range],
 | 
			
		||||
        )));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if angle_degrees.abs() == 90.0 {
 | 
			
		||||
        return Err(KclError::Type(KclErrorDetails::new(
 | 
			
		||||
        return Err(KclError::new_type(KclErrorDetails::new(
 | 
			
		||||
            "Cannot have an x constrained angle of 90 degrees".to_string(),
 | 
			
		||||
            vec![args.source_range],
 | 
			
		||||
        )));
 | 
			
		||||
@ -741,14 +741,14 @@ async fn inner_angled_line_to_x(
 | 
			
		||||
    let from = sketch.current_pen_position()?;
 | 
			
		||||
 | 
			
		||||
    if angle_degrees.abs() == 270.0 {
 | 
			
		||||
        return Err(KclError::Type(KclErrorDetails::new(
 | 
			
		||||
        return Err(KclError::new_type(KclErrorDetails::new(
 | 
			
		||||
            "Cannot have an x constrained angle of 270 degrees".to_string(),
 | 
			
		||||
            vec![args.source_range],
 | 
			
		||||
        )));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if angle_degrees.abs() == 90.0 {
 | 
			
		||||
        return Err(KclError::Type(KclErrorDetails::new(
 | 
			
		||||
        return Err(KclError::new_type(KclErrorDetails::new(
 | 
			
		||||
            "Cannot have an x constrained angle of 90 degrees".to_string(),
 | 
			
		||||
            vec![args.source_range],
 | 
			
		||||
        )));
 | 
			
		||||
@ -776,14 +776,14 @@ async fn inner_angled_line_of_y_length(
 | 
			
		||||
    args: Args,
 | 
			
		||||
) -> Result<Sketch, KclError> {
 | 
			
		||||
    if angle_degrees.abs() == 0.0 {
 | 
			
		||||
        return Err(KclError::Type(KclErrorDetails::new(
 | 
			
		||||
        return Err(KclError::new_type(KclErrorDetails::new(
 | 
			
		||||
            "Cannot have a y constrained angle of 0 degrees".to_string(),
 | 
			
		||||
            vec![args.source_range],
 | 
			
		||||
        )));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if angle_degrees.abs() == 180.0 {
 | 
			
		||||
        return Err(KclError::Type(KclErrorDetails::new(
 | 
			
		||||
        return Err(KclError::new_type(KclErrorDetails::new(
 | 
			
		||||
            "Cannot have a y constrained angle of 180 degrees".to_string(),
 | 
			
		||||
            vec![args.source_range],
 | 
			
		||||
        )));
 | 
			
		||||
@ -808,14 +808,14 @@ async fn inner_angled_line_to_y(
 | 
			
		||||
    let from = sketch.current_pen_position()?;
 | 
			
		||||
 | 
			
		||||
    if angle_degrees.abs() == 0.0 {
 | 
			
		||||
        return Err(KclError::Type(KclErrorDetails::new(
 | 
			
		||||
        return Err(KclError::new_type(KclErrorDetails::new(
 | 
			
		||||
            "Cannot have a y constrained angle of 0 degrees".to_string(),
 | 
			
		||||
            vec![args.source_range],
 | 
			
		||||
        )));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if angle_degrees.abs() == 180.0 {
 | 
			
		||||
        return Err(KclError::Type(KclErrorDetails::new(
 | 
			
		||||
        return Err(KclError::new_type(KclErrorDetails::new(
 | 
			
		||||
            "Cannot have a y constrained angle of 180 degrees".to_string(),
 | 
			
		||||
            vec![args.source_range],
 | 
			
		||||
        )));
 | 
			
		||||
@ -892,7 +892,7 @@ pub async fn inner_angled_line_that_intersects(
 | 
			
		||||
) -> Result<Sketch, KclError> {
 | 
			
		||||
    let intersect_path = args.get_tag_engine_info(exec_state, &intersect_tag)?;
 | 
			
		||||
    let path = intersect_path.path.clone().ok_or_else(|| {
 | 
			
		||||
        KclError::Type(KclErrorDetails::new(
 | 
			
		||||
        KclError::new_type(KclErrorDetails::new(
 | 
			
		||||
            format!("Expected an intersect path with a path, found `{:?}`", intersect_path),
 | 
			
		||||
            vec![args.source_range],
 | 
			
		||||
        ))
 | 
			
		||||
@ -1169,7 +1169,7 @@ async fn inner_start_sketch_on(
 | 
			
		||||
        SketchData::Plane(plane) => {
 | 
			
		||||
            if plane.value == crate::exec::PlaneType::Uninit {
 | 
			
		||||
                if plane.info.origin.units == UnitLen::Unknown {
 | 
			
		||||
                    return Err(KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
                    return Err(KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
                        "Origin of plane has unknown units".to_string(),
 | 
			
		||||
                        vec![args.source_range],
 | 
			
		||||
                    )));
 | 
			
		||||
@ -1193,7 +1193,7 @@ async fn inner_start_sketch_on(
 | 
			
		||||
        }
 | 
			
		||||
        SketchData::Solid(solid) => {
 | 
			
		||||
            let Some(tag) = face else {
 | 
			
		||||
                return Err(KclError::Type(KclErrorDetails::new(
 | 
			
		||||
                return Err(KclError::new_type(KclErrorDetails::new(
 | 
			
		||||
                    "Expected a tag for the face to sketch on".to_string(),
 | 
			
		||||
                    vec![args.source_range],
 | 
			
		||||
                )));
 | 
			
		||||
@ -1717,7 +1717,7 @@ pub(crate) async fn inner_arc(
 | 
			
		||||
            absolute_arc(&args, id, exec_state, sketch, from, interior_absolute, end_absolute, tag).await
 | 
			
		||||
        }
 | 
			
		||||
        _ => {
 | 
			
		||||
            Err(KclError::Type(KclErrorDetails::new(
 | 
			
		||||
            Err(KclError::new_type(KclErrorDetails::new(
 | 
			
		||||
                "Invalid combination of arguments. Either provide (angleStart, angleEnd, radius) or (endAbsolute, interiorAbsolute)".to_owned(),
 | 
			
		||||
                vec![args.source_range],
 | 
			
		||||
            )))
 | 
			
		||||
@ -1804,7 +1804,7 @@ pub async fn relative_arc(
 | 
			
		||||
    let radius = radius.to_length_units(from.units);
 | 
			
		||||
    let (center, end) = arc_center_and_end(from.ignore_units(), a_start, a_end, radius);
 | 
			
		||||
    if a_start == a_end {
 | 
			
		||||
        return Err(KclError::Type(KclErrorDetails::new(
 | 
			
		||||
        return Err(KclError::new_type(KclErrorDetails::new(
 | 
			
		||||
            "Arc start and end angles must be different".to_string(),
 | 
			
		||||
            vec![args.source_range],
 | 
			
		||||
        )));
 | 
			
		||||
@ -1972,11 +1972,11 @@ async fn inner_tangential_arc(
 | 
			
		||||
            let data = TangentialArcData::RadiusAndOffset { radius, offset: angle };
 | 
			
		||||
            inner_tangential_arc_radius_angle(data, sketch, tag, exec_state, args).await
 | 
			
		||||
        }
 | 
			
		||||
        (Some(_), Some(_), None, None, None) => Err(KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
        (Some(_), Some(_), None, None, None) => Err(KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
            "You cannot give both `end` and `endAbsolute` params, you have to choose one or the other".to_owned(),
 | 
			
		||||
            vec![args.source_range],
 | 
			
		||||
        ))),
 | 
			
		||||
        (_, _, _, _, _) => Err(KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
        (_, _, _, _, _) => Err(KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
            "You must supply `end`, `endAbsolute`, or both `angle` and `radius`/`diameter` arguments".to_owned(),
 | 
			
		||||
            vec![args.source_range],
 | 
			
		||||
        ))),
 | 
			
		||||
@ -2130,13 +2130,13 @@ async fn inner_tangential_arc_to_point(
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    if result.center[0].is_infinite() {
 | 
			
		||||
        return Err(KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
        return Err(KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
            "could not sketch tangential arc, because its center would be infinitely far away in the X direction"
 | 
			
		||||
                .to_owned(),
 | 
			
		||||
            vec![args.source_range],
 | 
			
		||||
        )));
 | 
			
		||||
    } else if result.center[1].is_infinite() {
 | 
			
		||||
        return Err(KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
        return Err(KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
            "could not sketch tangential arc, because its center would be infinitely far away in the Y direction"
 | 
			
		||||
                .to_owned(),
 | 
			
		||||
            vec![args.source_range],
 | 
			
		||||
@ -2314,7 +2314,7 @@ async fn inner_bezier_curve(
 | 
			
		||||
            to
 | 
			
		||||
        }
 | 
			
		||||
        _ => {
 | 
			
		||||
            return Err(KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
            return Err(KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
                "You must either give `control1`, `control2` and `end`, or `control1Absolute`, `control2Absolute` and `endAbsolute`.".to_owned(),
 | 
			
		||||
                vec![args.source_range],
 | 
			
		||||
            )));
 | 
			
		||||
 | 
			
		||||
@ -75,7 +75,7 @@ async fn inner_sweep(
 | 
			
		||||
        Some("sketchPlane") => RelativeTo::SketchPlane,
 | 
			
		||||
        Some("trajectoryCurve") | None => RelativeTo::TrajectoryCurve,
 | 
			
		||||
        Some(_) => {
 | 
			
		||||
            return Err(KclError::Syntax(crate::errors::KclErrorDetails::new(
 | 
			
		||||
            return Err(KclError::new_syntax(crate::errors::KclErrorDetails::new(
 | 
			
		||||
                "If you provide relativeTo, it must either be 'sketchPlane' or 'trajectoryCurve'".to_owned(),
 | 
			
		||||
                vec![args.source_range],
 | 
			
		||||
            )))
 | 
			
		||||
 | 
			
		||||
@ -37,7 +37,7 @@ pub async fn scale(exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
 | 
			
		||||
 | 
			
		||||
    // Ensure at least one scale value is provided.
 | 
			
		||||
    if scale_x.is_none() && scale_y.is_none() && scale_z.is_none() {
 | 
			
		||||
        return Err(KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
        return Err(KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
            "Expected `x`, `y`, or `z` to be provided.".to_string(),
 | 
			
		||||
            vec![args.source_range],
 | 
			
		||||
        )));
 | 
			
		||||
@ -119,7 +119,7 @@ pub async fn translate(exec_state: &mut ExecState, args: Args) -> Result<KclValu
 | 
			
		||||
 | 
			
		||||
    // Ensure at least one translation value is provided.
 | 
			
		||||
    if translate_x.is_none() && translate_y.is_none() && translate_z.is_none() {
 | 
			
		||||
        return Err(KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
        return Err(KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
            "Expected `x`, `y`, or `z` to be provided.".to_string(),
 | 
			
		||||
            vec![args.source_range],
 | 
			
		||||
        )));
 | 
			
		||||
@ -202,7 +202,7 @@ pub async fn rotate(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
 | 
			
		||||
 | 
			
		||||
    // Check if no rotation values are provided.
 | 
			
		||||
    if roll.is_none() && pitch.is_none() && yaw.is_none() && axis.is_none() && angle.is_none() {
 | 
			
		||||
        return Err(KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
        return Err(KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
            "Expected `roll`, `pitch`, and `yaw` or `axis` and `angle` to be provided.".to_string(),
 | 
			
		||||
            vec![args.source_range],
 | 
			
		||||
        )));
 | 
			
		||||
@ -212,7 +212,7 @@ pub async fn rotate(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
 | 
			
		||||
    if roll.is_some() || pitch.is_some() || yaw.is_some() {
 | 
			
		||||
        // Ensure they didn't also provide an axis or angle.
 | 
			
		||||
        if axis.is_some() || angle.is_some() {
 | 
			
		||||
            return Err(KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
            return Err(KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
                "Expected `axis` and `angle` to not be provided when `roll`, `pitch`, and `yaw` are provided."
 | 
			
		||||
                    .to_owned(),
 | 
			
		||||
                vec![args.source_range],
 | 
			
		||||
@ -223,13 +223,13 @@ pub async fn rotate(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
 | 
			
		||||
    // If they give us an axis or angle, they must give us both.
 | 
			
		||||
    if axis.is_some() || angle.is_some() {
 | 
			
		||||
        if axis.is_none() {
 | 
			
		||||
            return Err(KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
            return Err(KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
                "Expected `axis` to be provided when `angle` is provided.".to_string(),
 | 
			
		||||
                vec![args.source_range],
 | 
			
		||||
            )));
 | 
			
		||||
        }
 | 
			
		||||
        if angle.is_none() {
 | 
			
		||||
            return Err(KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
            return Err(KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
                "Expected `angle` to be provided when `axis` is provided.".to_string(),
 | 
			
		||||
                vec![args.source_range],
 | 
			
		||||
            )));
 | 
			
		||||
@ -237,7 +237,7 @@ pub async fn rotate(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
 | 
			
		||||
 | 
			
		||||
        // Ensure they didn't also provide a roll, pitch, or yaw.
 | 
			
		||||
        if roll.is_some() || pitch.is_some() || yaw.is_some() {
 | 
			
		||||
            return Err(KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
            return Err(KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
                "Expected `roll`, `pitch`, and `yaw` to not be provided when `axis` and `angle` are provided."
 | 
			
		||||
                    .to_owned(),
 | 
			
		||||
                vec![args.source_range],
 | 
			
		||||
@ -248,7 +248,7 @@ pub async fn rotate(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
 | 
			
		||||
    // Validate the roll, pitch, and yaw values.
 | 
			
		||||
    if let Some(roll) = &roll {
 | 
			
		||||
        if !(-360.0..=360.0).contains(&roll.n) {
 | 
			
		||||
            return Err(KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
            return Err(KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
                format!("Expected roll to be between -360 and 360, found `{}`", roll.n),
 | 
			
		||||
                vec![args.source_range],
 | 
			
		||||
            )));
 | 
			
		||||
@ -256,7 +256,7 @@ pub async fn rotate(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
 | 
			
		||||
    }
 | 
			
		||||
    if let Some(pitch) = &pitch {
 | 
			
		||||
        if !(-360.0..=360.0).contains(&pitch.n) {
 | 
			
		||||
            return Err(KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
            return Err(KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
                format!("Expected pitch to be between -360 and 360, found `{}`", pitch.n),
 | 
			
		||||
                vec![args.source_range],
 | 
			
		||||
            )));
 | 
			
		||||
@ -264,7 +264,7 @@ pub async fn rotate(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
 | 
			
		||||
    }
 | 
			
		||||
    if let Some(yaw) = &yaw {
 | 
			
		||||
        if !(-360.0..=360.0).contains(&yaw.n) {
 | 
			
		||||
            return Err(KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
            return Err(KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
                format!("Expected yaw to be between -360 and 360, found `{}`", yaw.n),
 | 
			
		||||
                vec![args.source_range],
 | 
			
		||||
            )));
 | 
			
		||||
@ -274,7 +274,7 @@ pub async fn rotate(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
 | 
			
		||||
    // Validate the axis and angle values.
 | 
			
		||||
    if let Some(angle) = &angle {
 | 
			
		||||
        if !(-360.0..=360.0).contains(&angle.n) {
 | 
			
		||||
            return Err(KclError::Semantic(KclErrorDetails::new(
 | 
			
		||||
            return Err(KclError::new_semantic(KclErrorDetails::new(
 | 
			
		||||
                format!("Expected angle to be between -360 and 360, found `{}`", angle.n),
 | 
			
		||||
                vec![args.source_range],
 | 
			
		||||
            )));
 | 
			
		||||
 | 
			
		||||
@ -93,7 +93,7 @@ async fn do_execute_and_snapshot(
 | 
			
		||||
    for e in exec_state.errors() {
 | 
			
		||||
        if e.severity.is_err() {
 | 
			
		||||
            return Err(ExecErrorWithState::new(
 | 
			
		||||
                KclErrorWithOutputs::no_outputs(KclError::Semantic(e.clone().into())).into(),
 | 
			
		||||
                KclErrorWithOutputs::no_outputs(KclError::new_semantic(e.clone().into())).into(),
 | 
			
		||||
                exec_state.clone(),
 | 
			
		||||
            ));
 | 
			
		||||
        }
 | 
			
		||||
@ -164,7 +164,7 @@ pub async fn execute_and_export_step(
 | 
			
		||||
    for e in exec_state.errors() {
 | 
			
		||||
        if e.severity.is_err() {
 | 
			
		||||
            return Err(ExecErrorWithState::new(
 | 
			
		||||
                KclErrorWithOutputs::no_outputs(KclError::Semantic(e.clone().into())).into(),
 | 
			
		||||
                KclErrorWithOutputs::no_outputs(KclError::new_semantic(e.clone().into())).into(),
 | 
			
		||||
                exec_state.clone(),
 | 
			
		||||
            ));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -883,7 +883,7 @@ pub async fn walk_dir(dir: &std::path::PathBuf) -> Result<Vec<std::path::PathBuf
 | 
			
		||||
#[cfg(not(target_arch = "wasm32"))]
 | 
			
		||||
pub async fn recast_dir(dir: &std::path::Path, options: &crate::FormatOptions) -> Result<(), anyhow::Error> {
 | 
			
		||||
    let files = walk_dir(&dir.to_path_buf()).await.map_err(|err| {
 | 
			
		||||
        crate::KclError::Internal(crate::errors::KclErrorDetails::new(
 | 
			
		||||
        crate::KclError::new_internal(crate::errors::KclErrorDetails::new(
 | 
			
		||||
            format!("Failed to walk directory `{}`: {:?}", dir.display(), err),
 | 
			
		||||
            vec![crate::SourceRange::default()],
 | 
			
		||||
        ))
 | 
			
		||||
@ -912,7 +912,7 @@ pub async fn recast_dir(dir: &std::path::Path, options: &crate::FormatOptions) -
 | 
			
		||||
                    if ce.severity != crate::errors::Severity::Warning {
 | 
			
		||||
                        let report = crate::Report {
 | 
			
		||||
                            kcl_source: contents.to_string(),
 | 
			
		||||
                            error: crate::KclError::Semantic(ce.clone().into()),
 | 
			
		||||
                            error: crate::KclError::new_semantic(ce.clone().into()),
 | 
			
		||||
                            filename: file.to_string_lossy().to_string(),
 | 
			
		||||
                        };
 | 
			
		||||
                        let report = miette::Report::new(report);
 | 
			
		||||
 | 
			
		||||
@ -96,7 +96,7 @@ fn topsort(all_modules: &[&str], graph: Graph) -> Result<Vec<Vec<String>>, KclEr
 | 
			
		||||
        if stage_modules.is_empty() {
 | 
			
		||||
            waiting_modules.sort();
 | 
			
		||||
 | 
			
		||||
            return Err(KclError::ImportCycle(KclErrorDetails::new(
 | 
			
		||||
            return Err(KclError::new_import_cycle(KclErrorDetails::new(
 | 
			
		||||
                format!("circular import of modules not allowed: {}", waiting_modules.join(", ")),
 | 
			
		||||
                // TODO: we can get the right import lines from the AST, but we don't
 | 
			
		||||
                vec![SourceRange::default()],
 | 
			
		||||
@ -146,7 +146,7 @@ pub(crate) fn import_dependencies(
 | 
			
		||||
                    // This is a bit of a hack, but it works for now.
 | 
			
		||||
                    ret.lock()
 | 
			
		||||
                        .map_err(|err| {
 | 
			
		||||
                            KclError::Internal(KclErrorDetails::new(
 | 
			
		||||
                            KclError::new_internal(KclErrorDetails::new(
 | 
			
		||||
                                format!("Failed to lock mutex: {}", err),
 | 
			
		||||
                                Default::default(),
 | 
			
		||||
                            ))
 | 
			
		||||
@ -156,7 +156,7 @@ pub(crate) fn import_dependencies(
 | 
			
		||||
                ImportPath::Foreign { path } => {
 | 
			
		||||
                    ret.lock()
 | 
			
		||||
                        .map_err(|err| {
 | 
			
		||||
                            KclError::Internal(KclErrorDetails::new(
 | 
			
		||||
                            KclError::new_internal(KclErrorDetails::new(
 | 
			
		||||
                                format!("Failed to lock mutex: {}", err),
 | 
			
		||||
                                Default::default(),
 | 
			
		||||
                            ))
 | 
			
		||||
@ -178,7 +178,7 @@ pub(crate) fn import_dependencies(
 | 
			
		||||
    walk(ret.clone(), prog.into(), path, ctx)?;
 | 
			
		||||
 | 
			
		||||
    let ret = ret.lock().map_err(|err| {
 | 
			
		||||
        KclError::Internal(KclErrorDetails::new(
 | 
			
		||||
        KclError::new_internal(KclErrorDetails::new(
 | 
			
		||||
            format!("Failed to lock mutex: {}", err),
 | 
			
		||||
            Default::default(),
 | 
			
		||||
        ))
 | 
			
		||||
@ -223,7 +223,7 @@ pub(crate) async fn import_universe(
 | 
			
		||||
 | 
			
		||||
        let repr = {
 | 
			
		||||
            let Some(module_info) = exec_state.get_module(module_id) else {
 | 
			
		||||
                return Err(KclError::Internal(KclErrorDetails::new(
 | 
			
		||||
                return Err(KclError::new_internal(KclErrorDetails::new(
 | 
			
		||||
                    format!("Module {} not found", module_id),
 | 
			
		||||
                    vec![import_stmt.into()],
 | 
			
		||||
                )));
 | 
			
		||||
 | 
			
		||||
@ -159,20 +159,20 @@ export function defaultSourceRange(): SourceRange {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function bestSourceRange(error: RustKclError): SourceRange {
 | 
			
		||||
  if (error.sourceRanges.length === 0) {
 | 
			
		||||
  if (error.details.sourceRanges.length === 0) {
 | 
			
		||||
    return defaultSourceRange()
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // When there's an error, the call stack is unwound, and the locations are
 | 
			
		||||
  // built up from deepest location to shallowest. So the deepest call is first.
 | 
			
		||||
  for (const range of error.sourceRanges) {
 | 
			
		||||
  for (const range of error.details.sourceRanges) {
 | 
			
		||||
    // Skip ranges pointing into files that aren't the top-level module.
 | 
			
		||||
    if (isTopLevelModule(range)) {
 | 
			
		||||
      return sourceRangeFromRust(range)
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  // We didn't find a top-level module range, so just use the first one.
 | 
			
		||||
  return sourceRangeFromRust(error.sourceRanges[0])
 | 
			
		||||
  return sourceRangeFromRust(error.details.sourceRanges[0])
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const splitErrors = (
 | 
			
		||||
@ -241,7 +241,7 @@ export const parse = (code: string | Error): ParseResult | Error => {
 | 
			
		||||
    const parsed: RustKclError = JSON.parse(e.toString())
 | 
			
		||||
    return new KCLError(
 | 
			
		||||
      parsed.kind,
 | 
			
		||||
      parsed.msg,
 | 
			
		||||
      parsed.details.msg,
 | 
			
		||||
      bestSourceRange(parsed),
 | 
			
		||||
      [],
 | 
			
		||||
      [],
 | 
			
		||||
@ -392,9 +392,9 @@ export const errFromErrWithOutputs = (e: any): KCLError => {
 | 
			
		||||
  const parsed: KclErrorWithOutputs = JSON.parse(e.toString())
 | 
			
		||||
  return new KCLError(
 | 
			
		||||
    parsed.error.kind,
 | 
			
		||||
    parsed.error.msg,
 | 
			
		||||
    parsed.error.details.msg,
 | 
			
		||||
    bestSourceRange(parsed.error),
 | 
			
		||||
    parsed.error.backtrace,
 | 
			
		||||
    parsed.error.details.backtrace,
 | 
			
		||||
    parsed.nonFatal,
 | 
			
		||||
    parsed.operations,
 | 
			
		||||
    parsed.artifactCommands,
 | 
			
		||||
 | 
			
		||||
@ -141,7 +141,7 @@ export default class RustContext {
 | 
			
		||||
      )
 | 
			
		||||
    } catch (e: any) {
 | 
			
		||||
      const parsed: RustKclError = JSON.parse(e.toString())
 | 
			
		||||
      toast.error(parsed.msg, { id: toastId })
 | 
			
		||||
      toast.error(parsed.details.msg, { id: toastId })
 | 
			
		||||
      return
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user