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:
Adam Chalmers
2025-06-02 13:30:57 -05:00
committed by GitHub
parent b7437e949a
commit e29ee9d1ca
47 changed files with 505 additions and 461 deletions

View File

@ -439,7 +439,7 @@ impl EngineManager for EngineConnection {
request_sent: tx, request_sent: tx,
}) })
.await .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; let _ = rx.await;
Ok(()) Ok(())
@ -474,7 +474,7 @@ impl EngineManager for EngineConnection {
}) })
.await .await
.map_err(|e| { .map_err(|e| {
KclError::Engine(KclErrorDetails::new( KclError::new_engine(KclErrorDetails::new(
format!("Failed to send modeling command: {}", e), format!("Failed to send modeling command: {}", e),
vec![source_range], vec![source_range],
)) ))
@ -483,13 +483,13 @@ impl EngineManager for EngineConnection {
// Wait for the request to be sent. // Wait for the request to be sent.
rx.await rx.await
.map_err(|e| { .map_err(|e| {
KclError::Engine(KclErrorDetails::new( KclError::new_engine(KclErrorDetails::new(
format!("could not send request to the engine actor: {e}"), format!("could not send request to the engine actor: {e}"),
vec![source_range], vec![source_range],
)) ))
})? })?
.map_err(|e| { .map_err(|e| {
KclError::Engine(KclErrorDetails::new( KclError::new_engine(KclErrorDetails::new(
format!("could not send request to the engine: {e}"), format!("could not send request to the engine: {e}"),
vec![source_range], vec![source_range],
)) ))
@ -516,12 +516,12 @@ impl EngineManager for EngineConnection {
// Check if we have any pending errors. // Check if we have any pending errors.
let pe = self.pending_errors.read().await; let pe = self.pending_errors.read().await;
if !pe.is_empty() { if !pe.is_empty() {
return Err(KclError::Engine(KclErrorDetails::new( return Err(KclError::new_engine(KclErrorDetails::new(
pe.join(", ").to_string(), pe.join(", ").to_string(),
vec![source_range], vec![source_range],
))); )));
} else { } else {
return Err(KclError::Engine(KclErrorDetails::new( return Err(KclError::new_engine(KclErrorDetails::new(
"Modeling command failed: websocket closed early".to_string(), "Modeling command failed: websocket closed early".to_string(),
vec![source_range], 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), format!("Modeling command timed out `{}`", id),
vec![source_range], vec![source_range],
))) )))

View File

@ -147,19 +147,19 @@ impl EngineConnection {
id_to_source_range: HashMap<uuid::Uuid, SourceRange>, id_to_source_range: HashMap<uuid::Uuid, SourceRange>,
) -> Result<(), KclError> { ) -> Result<(), KclError> {
let source_range_str = serde_json::to_string(&source_range).map_err(|e| { 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), format!("Failed to serialize source range: {:?}", e),
vec![source_range], vec![source_range],
)) ))
})?; })?;
let cmd_str = serde_json::to_string(&cmd).map_err(|e| { 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), format!("Failed to serialize modeling command: {:?}", e),
vec![source_range], vec![source_range],
)) ))
})?; })?;
let id_to_source_range_str = serde_json::to_string(&id_to_source_range).map_err(|e| { 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), format!("Failed to serialize id to source range: {:?}", e),
vec![source_range], vec![source_range],
)) ))
@ -167,7 +167,7 @@ impl EngineConnection {
self.manager self.manager
.fire_modeling_cmd_from_wasm(id.to_string(), source_range_str, cmd_str, id_to_source_range_str) .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(()) Ok(())
} }
@ -180,19 +180,19 @@ impl EngineConnection {
id_to_source_range: HashMap<uuid::Uuid, SourceRange>, id_to_source_range: HashMap<uuid::Uuid, SourceRange>,
) -> Result<WebSocketResponse, KclError> { ) -> Result<WebSocketResponse, KclError> {
let source_range_str = serde_json::to_string(&source_range).map_err(|e| { 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), format!("Failed to serialize source range: {:?}", e),
vec![source_range], vec![source_range],
)) ))
})?; })?;
let cmd_str = serde_json::to_string(&cmd).map_err(|e| { 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), format!("Failed to serialize modeling command: {:?}", e),
vec![source_range], vec![source_range],
)) ))
})?; })?;
let id_to_source_range_str = serde_json::to_string(&id_to_source_range).map_err(|e| { 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), format!("Failed to serialize id to source range: {:?}", e),
vec![source_range], vec![source_range],
)) ))
@ -201,7 +201,7 @@ impl EngineConnection {
let promise = self let promise = self
.manager .manager
.send_modeling_cmd_from_wasm(id.to_string(), source_range_str, cmd_str, id_to_source_range_str) .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| { let value = crate::wasm::JsFuture::from(promise).await.map_err(|e| {
// Try to parse the error as an engine error. // Try to parse the error as an engine error.
@ -209,7 +209,7 @@ impl EngineConnection {
if let Ok(kittycad_modeling_cmds::websocket::FailureWebSocketResponse { errors, .. }) = if let Ok(kittycad_modeling_cmds::websocket::FailureWebSocketResponse { errors, .. }) =
serde_json::from_str(&err_str) 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"), errors.iter().map(|e| e.message.clone()).collect::<Vec<_>>().join("\n"),
vec![source_range], vec![source_range],
)) ))
@ -218,7 +218,7 @@ impl EngineConnection {
{ {
if let Some(data) = data.first() { if let Some(data) = data.first() {
// It could also be an array of responses. // It could also be an array of responses.
KclError::Engine(KclErrorDetails::new( KclError::new_engine(KclErrorDetails::new(
data.errors data.errors
.iter() .iter()
.map(|e| e.message.clone()) .map(|e| e.message.clone())
@ -227,13 +227,13 @@ impl EngineConnection {
vec![source_range], vec![source_range],
)) ))
} else { } else {
KclError::Engine(KclErrorDetails::new( KclError::new_engine(KclErrorDetails::new(
"Received empty response from engine".into(), "Received empty response from engine".into(),
vec![source_range], vec![source_range],
)) ))
} }
} else { } else {
KclError::Engine(KclErrorDetails::new( KclError::new_engine(KclErrorDetails::new(
format!("Failed to wait for promise from send modeling command: {:?}", e), format!("Failed to wait for promise from send modeling command: {:?}", e),
vec![source_range], vec![source_range],
)) ))
@ -241,7 +241,7 @@ impl EngineConnection {
})?; })?;
if value.is_null() || value.is_undefined() { 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(), "Received null or undefined response from engine".into(),
vec![source_range], vec![source_range],
))); )));
@ -251,7 +251,7 @@ impl EngineConnection {
let data = js_sys::Uint8Array::from(value); let data = js_sys::Uint8Array::from(value);
let ws_result: WebSocketResponse = bson::from_slice(&data.to_vec()).map_err(|e| { 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), format!("Failed to deserialize bson response from engine: {:?}", e),
vec![source_range], vec![source_range],
)) ))
@ -308,10 +308,10 @@ impl crate::engine::EngineManager for EngineConnection {
let promise = self let promise = self
.manager .manager
.start_new_session() .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| { 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), format!("Failed to wait for promise from start new session: {:?}", e),
vec![source_range], vec![source_range],
)) ))

View File

@ -276,7 +276,7 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
{ {
let duration = instant::Duration::from_millis(1); let duration = instant::Duration::from_millis(1);
wasm_timer::Delay::new(duration).await.map_err(|err| { wasm_timer::Delay::new(duration).await.map_err(|err| {
KclError::Internal(KclErrorDetails::new( KclError::new_internal(KclErrorDetails::new(
format!("Failed to sleep: {:?}", err), format!("Failed to sleep: {:?}", err),
vec![source_range], vec![source_range],
)) ))
@ -293,7 +293,7 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
return Ok(response); return Ok(response);
} }
Err(KclError::Engine(KclErrorDetails::new( Err(KclError::new_engine(KclErrorDetails::new(
"async command timed out".to_string(), "async command timed out".to_string(),
vec![source_range], 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); 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), format!("The request is not a modeling command: {:?}", req),
vec![*range], 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) self.parse_batch_responses(last_id.into(), id_to_source_range, responses)
} else { } else {
// We should never get here. // We should never get here.
Err(KclError::Engine(KclErrorDetails::new( Err(KclError::new_engine(KclErrorDetails::new(
format!("Failed to get batch response: {:?}", response), format!("Failed to get batch response: {:?}", response),
vec![source_range], 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 // request so we need the original request source range in case the engine returns
// an error. // an error.
let source_range = id_to_source_range.get(cmd_id.as_ref()).cloned().ok_or_else(|| { 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), format!("Failed to get source range for command ID: {:?}", cmd_id),
vec![], vec![],
)) ))
@ -620,7 +620,7 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
.await?; .await?;
self.parse_websocket_response(ws_resp, source_range) 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), format!("The final request is not a modeling command: {:?}", final_req),
vec![source_range], vec![source_range],
))), ))),
@ -729,7 +729,7 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
for (name, plane_id, color) in plane_settings { for (name, plane_id, color) in plane_settings {
let info = DEFAULT_PLANE_INFO.get(&name).ok_or_else(|| { let info = DEFAULT_PLANE_INFO.get(&name).ok_or_else(|| {
// We should never get here. // We should never get here.
KclError::Engine(KclErrorDetails::new( KclError::new_engine(KclErrorDetails::new(
format!("Failed to get default plane info for: {:?}", name), format!("Failed to get default plane info for: {:?}", name),
vec![source_range], vec![source_range],
)) ))
@ -763,7 +763,7 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
WebSocketResponse::Success(success) => Ok(success.resp), WebSocketResponse::Success(success) => Ok(success.resp),
WebSocketResponse::Failure(fail) => { WebSocketResponse::Failure(fail) => {
let _request_id = fail.request_id; let _request_id = fail.request_id;
Err(KclError::Engine(KclErrorDetails::new( Err(KclError::new_engine(KclErrorDetails::new(
fail.errors fail.errors
.iter() .iter()
.map(|e| e.message.clone()) .map(|e| e.message.clone())
@ -805,12 +805,12 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
BatchResponse::Failure { errors } => { BatchResponse::Failure { errors } => {
// Get the source range for the command. // Get the source range for the command.
let source_range = id_to_source_range.get(cmd_id).cloned().ok_or_else(|| { 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), format!("Failed to get source range for command ID: {:?}", cmd_id),
vec![], 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"), errors.iter().map(|e| e.message.clone()).collect::<Vec<_>>().join("\n"),
vec![source_range], 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. // Return an error that we did not get an error or the response we wanted.
// This should never happen but who knows. // 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), format!("Failed to find response for command ID: {:?}", id),
vec![], vec![],
))) )))

View File

@ -91,30 +91,30 @@ pub enum ConnectionError {
#[ts(export)] #[ts(export)]
#[serde(tag = "kind", rename_all = "snake_case")] #[serde(tag = "kind", rename_all = "snake_case")]
pub enum KclError { pub enum KclError {
#[error("lexical: {0:?}")] #[error("lexical: {details:?}")]
Lexical(KclErrorDetails), Lexical { details: KclErrorDetails },
#[error("syntax: {0:?}")] #[error("syntax: {details:?}")]
Syntax(KclErrorDetails), Syntax { details: KclErrorDetails },
#[error("semantic: {0:?}")] #[error("semantic: {details:?}")]
Semantic(KclErrorDetails), Semantic { details: KclErrorDetails },
#[error("import cycle: {0:?}")] #[error("import cycle: {details:?}")]
ImportCycle(KclErrorDetails), ImportCycle { details: KclErrorDetails },
#[error("type: {0:?}")] #[error("type: {details:?}")]
Type(KclErrorDetails), Type { details: KclErrorDetails },
#[error("i/o: {0:?}")] #[error("i/o: {details:?}")]
Io(KclErrorDetails), Io { details: KclErrorDetails },
#[error("unexpected: {0:?}")] #[error("unexpected: {details:?}")]
Unexpected(KclErrorDetails), Unexpected { details: KclErrorDetails },
#[error("value already defined: {0:?}")] #[error("value already defined: {details:?}")]
ValueAlreadyDefined(KclErrorDetails), ValueAlreadyDefined { details: KclErrorDetails },
#[error("undefined value: {0:?}")] #[error("undefined value: {details:?}")]
UndefinedValue(KclErrorDetails), UndefinedValue { details: KclErrorDetails },
#[error("invalid expression: {0:?}")] #[error("invalid expression: {details:?}")]
InvalidExpression(KclErrorDetails), InvalidExpression { details: KclErrorDetails },
#[error("engine: {0:?}")] #[error("engine: {details:?}")]
Engine(KclErrorDetails), Engine { details: KclErrorDetails },
#[error("internal error, please report to KittyCAD team: {0:?}")] #[error("internal error, please report to KittyCAD team: {details:?}")]
Internal(KclErrorDetails), Internal { details: KclErrorDetails },
} }
impl From<KclErrorWithOutputs> for KclError { impl From<KclErrorWithOutputs> for KclError {
@ -296,18 +296,18 @@ pub struct ReportWithOutputs {
impl miette::Diagnostic for ReportWithOutputs { impl miette::Diagnostic for ReportWithOutputs {
fn code<'a>(&'a self) -> Option<Box<dyn std::fmt::Display + 'a>> { fn code<'a>(&'a self) -> Option<Box<dyn std::fmt::Display + 'a>> {
let family = match self.error.error { let family = match self.error.error {
KclError::Lexical(_) => "Lexical", KclError::Lexical { .. } => "Lexical",
KclError::Syntax(_) => "Syntax", KclError::Syntax { .. } => "Syntax",
KclError::Semantic(_) => "Semantic", KclError::Semantic { .. } => "Semantic",
KclError::ImportCycle(_) => "ImportCycle", KclError::ImportCycle { .. } => "ImportCycle",
KclError::Type(_) => "Type", KclError::Type { .. } => "Type",
KclError::Io(_) => "I/O", KclError::Io { .. } => "I/O",
KclError::Unexpected(_) => "Unexpected", KclError::Unexpected { .. } => "Unexpected",
KclError::ValueAlreadyDefined(_) => "ValueAlreadyDefined", KclError::ValueAlreadyDefined { .. } => "ValueAlreadyDefined",
KclError::UndefinedValue(_) => "UndefinedValue", KclError::UndefinedValue { .. } => "UndefinedValue",
KclError::InvalidExpression(_) => "InvalidExpression", KclError::InvalidExpression { .. } => "InvalidExpression",
KclError::Engine(_) => "Engine", KclError::Engine { .. } => "Engine",
KclError::Internal(_) => "Internal", KclError::Internal { .. } => "Internal",
}; };
let error_string = format!("KCL {family} error"); let error_string = format!("KCL {family} error");
Some(Box::new(error_string)) Some(Box::new(error_string))
@ -346,18 +346,18 @@ pub struct Report {
impl miette::Diagnostic for Report { impl miette::Diagnostic for Report {
fn code<'a>(&'a self) -> Option<Box<dyn std::fmt::Display + 'a>> { fn code<'a>(&'a self) -> Option<Box<dyn std::fmt::Display + 'a>> {
let family = match self.error { let family = match self.error {
KclError::Lexical(_) => "Lexical", KclError::Lexical { .. } => "Lexical",
KclError::Syntax(_) => "Syntax", KclError::Syntax { .. } => "Syntax",
KclError::Semantic(_) => "Semantic", KclError::Semantic { .. } => "Semantic",
KclError::ImportCycle(_) => "ImportCycle", KclError::ImportCycle { .. } => "ImportCycle",
KclError::Type(_) => "Type", KclError::Type { .. } => "Type",
KclError::Io(_) => "I/O", KclError::Io { .. } => "I/O",
KclError::Unexpected(_) => "Unexpected", KclError::Unexpected { .. } => "Unexpected",
KclError::ValueAlreadyDefined(_) => "ValueAlreadyDefined", KclError::ValueAlreadyDefined { .. } => "ValueAlreadyDefined",
KclError::UndefinedValue(_) => "UndefinedValue", KclError::UndefinedValue { .. } => "UndefinedValue",
KclError::InvalidExpression(_) => "InvalidExpression", KclError::InvalidExpression { .. } => "InvalidExpression",
KclError::Engine(_) => "Engine", KclError::Engine { .. } => "Engine",
KclError::Internal(_) => "Internal", KclError::Internal { .. } => "Internal",
}; };
let error_string = format!("KCL {family} error"); let error_string = format!("KCL {family} error");
Some(Box::new(error_string)) Some(Box::new(error_string))
@ -410,11 +410,53 @@ impl KclErrorDetails {
impl KclError { impl KclError {
pub fn internal(message: String) -> KclError { pub fn internal(message: String) -> KclError {
KclError::Internal(KclErrorDetails { KclError::Internal {
source_ranges: Default::default(), details: KclErrorDetails {
backtrace: Default::default(), source_ranges: Default::default(),
message, 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. /// Get the error message.
@ -424,88 +466,88 @@ impl KclError {
pub fn error_type(&self) -> &'static str { pub fn error_type(&self) -> &'static str {
match self { match self {
KclError::Lexical(_) => "lexical", KclError::Lexical { .. } => "lexical",
KclError::Syntax(_) => "syntax", KclError::Syntax { .. } => "syntax",
KclError::Semantic(_) => "semantic", KclError::Semantic { .. } => "semantic",
KclError::ImportCycle(_) => "import cycle", KclError::ImportCycle { .. } => "import cycle",
KclError::Type(_) => "type", KclError::Type { .. } => "type",
KclError::Io(_) => "i/o", KclError::Io { .. } => "i/o",
KclError::Unexpected(_) => "unexpected", KclError::Unexpected { .. } => "unexpected",
KclError::ValueAlreadyDefined(_) => "value already defined", KclError::ValueAlreadyDefined { .. } => "value already defined",
KclError::UndefinedValue(_) => "undefined value", KclError::UndefinedValue { .. } => "undefined value",
KclError::InvalidExpression(_) => "invalid expression", KclError::InvalidExpression { .. } => "invalid expression",
KclError::Engine(_) => "engine", KclError::Engine { .. } => "engine",
KclError::Internal(_) => "internal", KclError::Internal { .. } => "internal",
} }
} }
pub fn source_ranges(&self) -> Vec<SourceRange> { pub fn source_ranges(&self) -> Vec<SourceRange> {
match &self { match &self {
KclError::Lexical(e) => e.source_ranges.clone(), KclError::Lexical { details: e } => e.source_ranges.clone(),
KclError::Syntax(e) => e.source_ranges.clone(), KclError::Syntax { details: e } => e.source_ranges.clone(),
KclError::Semantic(e) => e.source_ranges.clone(), KclError::Semantic { details: e } => e.source_ranges.clone(),
KclError::ImportCycle(e) => e.source_ranges.clone(), KclError::ImportCycle { details: e } => e.source_ranges.clone(),
KclError::Type(e) => e.source_ranges.clone(), KclError::Type { details: e } => e.source_ranges.clone(),
KclError::Io(e) => e.source_ranges.clone(), KclError::Io { details: e } => e.source_ranges.clone(),
KclError::Unexpected(e) => e.source_ranges.clone(), KclError::Unexpected { details: e } => e.source_ranges.clone(),
KclError::ValueAlreadyDefined(e) => e.source_ranges.clone(), KclError::ValueAlreadyDefined { details: e } => e.source_ranges.clone(),
KclError::UndefinedValue(e) => e.source_ranges.clone(), KclError::UndefinedValue { details: e } => e.source_ranges.clone(),
KclError::InvalidExpression(e) => e.source_ranges.clone(), KclError::InvalidExpression { details: e } => e.source_ranges.clone(),
KclError::Engine(e) => e.source_ranges.clone(), KclError::Engine { details: e } => e.source_ranges.clone(),
KclError::Internal(e) => e.source_ranges.clone(), KclError::Internal { details: e } => e.source_ranges.clone(),
} }
} }
/// Get the inner error message. /// Get the inner error message.
pub fn message(&self) -> &str { pub fn message(&self) -> &str {
match &self { match &self {
KclError::Lexical(e) => &e.message, KclError::Lexical { details: e } => &e.message,
KclError::Syntax(e) => &e.message, KclError::Syntax { details: e } => &e.message,
KclError::Semantic(e) => &e.message, KclError::Semantic { details: e } => &e.message,
KclError::ImportCycle(e) => &e.message, KclError::ImportCycle { details: e } => &e.message,
KclError::Type(e) => &e.message, KclError::Type { details: e } => &e.message,
KclError::Io(e) => &e.message, KclError::Io { details: e } => &e.message,
KclError::Unexpected(e) => &e.message, KclError::Unexpected { details: e } => &e.message,
KclError::ValueAlreadyDefined(e) => &e.message, KclError::ValueAlreadyDefined { details: e } => &e.message,
KclError::UndefinedValue(e) => &e.message, KclError::UndefinedValue { details: e } => &e.message,
KclError::InvalidExpression(e) => &e.message, KclError::InvalidExpression { details: e } => &e.message,
KclError::Engine(e) => &e.message, KclError::Engine { details: e } => &e.message,
KclError::Internal(e) => &e.message, KclError::Internal { details: e } => &e.message,
} }
} }
pub fn backtrace(&self) -> Vec<BacktraceItem> { pub fn backtrace(&self) -> Vec<BacktraceItem> {
match self { match self {
KclError::Lexical(e) KclError::Lexical { details: e }
| KclError::Syntax(e) | KclError::Syntax { details: e }
| KclError::Semantic(e) | KclError::Semantic { details: e }
| KclError::ImportCycle(e) | KclError::ImportCycle { details: e }
| KclError::Type(e) | KclError::Type { details: e }
| KclError::Io(e) | KclError::Io { details: e }
| KclError::Unexpected(e) | KclError::Unexpected { details: e }
| KclError::ValueAlreadyDefined(e) | KclError::ValueAlreadyDefined { details: e }
| KclError::UndefinedValue(e) | KclError::UndefinedValue { details: e }
| KclError::InvalidExpression(e) | KclError::InvalidExpression { details: e }
| KclError::Engine(e) | KclError::Engine { details: e }
| KclError::Internal(e) => e.backtrace.clone(), | KclError::Internal { details: e } => e.backtrace.clone(),
} }
} }
pub(crate) fn override_source_ranges(&self, source_ranges: Vec<SourceRange>) -> Self { pub(crate) fn override_source_ranges(&self, source_ranges: Vec<SourceRange>) -> Self {
let mut new = self.clone(); let mut new = self.clone();
match &mut new { match &mut new {
KclError::Lexical(e) KclError::Lexical { details: e }
| KclError::Syntax(e) | KclError::Syntax { details: e }
| KclError::Semantic(e) | KclError::Semantic { details: e }
| KclError::ImportCycle(e) | KclError::ImportCycle { details: e }
| KclError::Type(e) | KclError::Type { details: e }
| KclError::Io(e) | KclError::Io { details: e }
| KclError::Unexpected(e) | KclError::Unexpected { details: e }
| KclError::ValueAlreadyDefined(e) | KclError::ValueAlreadyDefined { details: e }
| KclError::UndefinedValue(e) | KclError::UndefinedValue { details: e }
| KclError::InvalidExpression(e) | KclError::InvalidExpression { details: e }
| KclError::Engine(e) | KclError::Engine { details: e }
| KclError::Internal(e) => { | KclError::Internal { details: e } => {
e.backtrace = source_ranges e.backtrace = source_ranges
.iter() .iter()
.map(|s| BacktraceItem { .map(|s| BacktraceItem {
@ -523,18 +565,18 @@ impl KclError {
pub(crate) fn set_last_backtrace_fn_name(&self, last_fn_name: Option<String>) -> Self { pub(crate) fn set_last_backtrace_fn_name(&self, last_fn_name: Option<String>) -> Self {
let mut new = self.clone(); let mut new = self.clone();
match &mut new { match &mut new {
KclError::Lexical(e) KclError::Lexical { details: e }
| KclError::Syntax(e) | KclError::Syntax { details: e }
| KclError::Semantic(e) | KclError::Semantic { details: e }
| KclError::ImportCycle(e) | KclError::ImportCycle { details: e }
| KclError::Type(e) | KclError::Type { details: e }
| KclError::Io(e) | KclError::Io { details: e }
| KclError::Unexpected(e) | KclError::Unexpected { details: e }
| KclError::ValueAlreadyDefined(e) | KclError::ValueAlreadyDefined { details: e }
| KclError::UndefinedValue(e) | KclError::UndefinedValue { details: e }
| KclError::InvalidExpression(e) | KclError::InvalidExpression { details: e }
| KclError::Engine(e) | KclError::Engine { details: e }
| KclError::Internal(e) => { | KclError::Internal { details: e } => {
if let Some(item) = e.backtrace.last_mut() { if let Some(item) = e.backtrace.last_mut() {
item.fn_name = last_fn_name; 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 { pub(crate) fn add_unwind_location(&self, last_fn_name: Option<String>, source_range: SourceRange) -> Self {
let mut new = self.clone(); let mut new = self.clone();
match &mut new { match &mut new {
KclError::Lexical(e) KclError::Lexical { details: e }
| KclError::Syntax(e) | KclError::Syntax { details: e }
| KclError::Semantic(e) | KclError::Semantic { details: e }
| KclError::ImportCycle(e) | KclError::ImportCycle { details: e }
| KclError::Type(e) | KclError::Type { details: e }
| KclError::Io(e) | KclError::Io { details: e }
| KclError::Unexpected(e) | KclError::Unexpected { details: e }
| KclError::ValueAlreadyDefined(e) | KclError::ValueAlreadyDefined { details: e }
| KclError::UndefinedValue(e) | KclError::UndefinedValue { details: e }
| KclError::InvalidExpression(e) | KclError::InvalidExpression { details: e }
| KclError::Engine(e) | KclError::Engine { details: e }
| KclError::Internal(e) => { | KclError::Internal { details: e } => {
if let Some(item) = e.backtrace.last_mut() { if let Some(item) = e.backtrace.last_mut() {
item.fn_name = last_fn_name; item.fn_name = last_fn_name;
} }
@ -645,7 +687,7 @@ impl From<String> for KclError {
#[cfg(feature = "pyo3")] #[cfg(feature = "pyo3")]
impl From<pyo3::PyErr> for KclError { impl From<pyo3::PyErr> for KclError {
fn from(error: pyo3::PyErr) -> Self { fn from(error: pyo3::PyErr) -> Self {
KclError::Internal(KclErrorDetails { KclError::new_internal(KclErrorDetails {
source_ranges: vec![], source_ranges: vec![],
backtrace: Default::default(), backtrace: Default::default(),
message: error.to_string(), message: error.to_string(),

View File

@ -70,7 +70,7 @@ pub(super) fn expect_properties<'a>(
) -> Result<&'a [Node<ObjectProperty>], KclError> { ) -> Result<&'a [Node<ObjectProperty>], KclError> {
assert_eq!(annotation.name().unwrap(), for_key); assert_eq!(annotation.name().unwrap(), for_key);
Ok(&**annotation.properties.as_ref().ok_or_else(|| { Ok(&**annotation.properties.as_ref().ok_or_else(|| {
KclError::Semantic(KclErrorDetails::new( KclError::new_semantic(KclErrorDetails::new(
format!("Empty `{for_key}` annotation"), format!("Empty `{for_key}` annotation"),
vec![annotation.as_source_range()], 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(), "Unexpected settings value, expected a simple name, e.g., `mm`".to_owned(),
vec![expr.into()], 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(), "Unexpected settings value, expected a number, e.g., `1.0`".to_owned(),
vec![expr.into()], vec![expr.into()],
))) )))
@ -113,7 +113,7 @@ pub(super) fn get_impl(annotations: &[Node<Annotation>], source_range: SourceRan
if &*p.key.name == IMPL { if &*p.key.name == IMPL {
if let Some(s) = p.value.ident_name() { if let Some(s) = p.value.ident_name() {
return Impl::from_str(s).map(Some).map_err(|_| { return Impl::from_str(s).map(Some).map_err(|_| {
KclError::Semantic(KclErrorDetails::new( KclError::new_semantic(KclErrorDetails::new(
format!( format!(
"Invalid value for {} attribute, expected one of: {}", "Invalid value for {} attribute, expected one of: {}",
IMPL, IMPL,
@ -139,7 +139,7 @@ impl UnitLen {
"inch" | "in" => Ok(UnitLen::Inches), "inch" | "in" => Ok(UnitLen::Inches),
"ft" => Ok(UnitLen::Feet), "ft" => Ok(UnitLen::Feet),
"yd" => Ok(UnitLen::Yards), "yd" => Ok(UnitLen::Yards),
value => Err(KclError::Semantic(KclErrorDetails::new( value => Err(KclError::new_semantic(KclErrorDetails::new(
format!( format!(
"Unexpected value for length units: `{value}`; expected one of `mm`, `cm`, `m`, `in`, `ft`, `yd`" "Unexpected value for length units: `{value}`; expected one of `mm`, `cm`, `m`, `in`, `ft`, `yd`"
), ),
@ -154,7 +154,7 @@ impl UnitAngle {
match s { match s {
"deg" => Ok(UnitAngle::Degrees), "deg" => Ok(UnitAngle::Degrees),
"rad" => Ok(UnitAngle::Radians), "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`"), format!("Unexpected value for angle units: `{value}`; expected one of `deg`, `rad`"),
vec![source_range], vec![source_range],
))), ))),

View File

@ -24,7 +24,7 @@ macro_rules! internal_error {
($range:expr, $($rest:tt)*) => {{ ($range:expr, $($rest:tt)*) => {{
let message = format!($($rest)*); let message = format!($($rest)*);
debug_assert!(false, "{}", &message); 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(_) => { ModelingCmd::StartPath(_) => {
let mut return_arr = Vec::new(); let mut return_arr = Vec::new();
let current_plane_id = path_to_plane_id_map.get(&artifact_command.cmd_id).ok_or_else(|| { 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:?}"), format!("Expected a current plane ID when processing StartPath command, but we have none: {id:?}"),
vec![range], vec![range],
)) ))
@ -1137,7 +1137,7 @@ fn artifacts_to_update(
// TODO: Using the first one. Make sure to revisit this // TODO: Using the first one. Make sure to revisit this
// choice, don't think it matters for now. // choice, don't think it matters for now.
path_id: ArtifactId::new(*loft_cmd.section_ids.first().ok_or_else(|| { 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:?}"), format!("Expected at least one section ID in Loft command: {id:?}; cmd={cmd:?}"),
vec![range], vec![range],
)) ))
@ -1180,7 +1180,7 @@ fn artifacts_to_update(
}; };
last_path = Some(path); last_path = Some(path);
let path_sweep_id = path.sweep_id.ok_or_else(|| { let path_sweep_id = path.sweep_id.ok_or_else(|| {
KclError::Internal(KclErrorDetails::new( KclError::new_internal(KclErrorDetails::new(
format!( format!(
"Expected a sweep ID on the path when processing Solid3dGetExtrusionFaceInfo command, but we have none: {id:?}, {path:?}" "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; continue;
}; };
let path_sweep_id = path.sweep_id.ok_or_else(|| { let path_sweep_id = path.sweep_id.ok_or_else(|| {
KclError::Internal(KclErrorDetails::new( KclError::new_internal(KclErrorDetails::new(
format!( format!(
"Expected a sweep ID on the path when processing last path's Solid3dGetExtrusionFaceInfo command, but we have none: {id:?}, {path:?}" "Expected a sweep ID on the path when processing last path's Solid3dGetExtrusionFaceInfo command, but we have none: {id:?}, {path:?}"
), ),

View File

@ -131,7 +131,7 @@ impl ExecutorContext {
match statement { match statement {
BodyItem::ImportStatement(import_stmt) => { BodyItem::ImportStatement(import_stmt) => {
if !matches!(body_type, BodyType::Root) { 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(), "Imports are only supported at the top-level of a file.".to_owned(),
vec![import_stmt.into()], 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(); 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() { 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), format!("{} is not defined in module", import_item.name.name),
vec![SourceRange::from(&import_item.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). // 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) { 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!( format!(
"Cannot import \"{}\" from module because it is not exported. Add \"export\" before the definition to export it.", "Cannot import \"{}\" from module because it is not exported. Add \"export\" before the definition to export it.",
import_item.name.name import_item.name.name
@ -182,7 +182,7 @@ impl ExecutorContext {
} }
if ty.is_ok() && !module_exports.contains(&ty_name) { 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.", "Cannot import \"{}\" from module because it is not exported. Add \"export\" before the definition to export it.",
import_item.name.name import_item.name.name
), ),
@ -190,7 +190,7 @@ impl ExecutorContext {
} }
if mod_value.is_ok() && !module_exports.contains(&mod_name) { 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.", "Cannot import \"{}\" from module because it is not exported. Add \"export\" before the definition to export it.",
import_item.name.name import_item.name.name
), ),
@ -253,7 +253,7 @@ impl ExecutorContext {
.memory .memory
.get_from(name, env_ref, source_range, 0) .get_from(name, env_ref, source_range, 0)
.map_err(|_err| { .map_err(|_err| {
KclError::Internal(KclErrorDetails::new( KclError::new_internal(KclErrorDetails::new(
format!("{} is not defined in module (but was exported?)", name), format!("{} is not defined in module (but was exported?)", name),
vec![source_range], vec![source_range],
)) ))
@ -336,7 +336,7 @@ impl ExecutorContext {
let std_path = match &exec_state.mod_local.path { let std_path = match &exec_state.mod_local.path {
ModulePath::Std { value } => value, ModulePath::Std { value } => value,
ModulePath::Local { .. } | ModulePath::Main => { 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(), "User-defined types are not yet supported.".to_owned(),
vec![metadata.source_range], vec![metadata.source_range],
))); )));
@ -352,7 +352,7 @@ impl ExecutorContext {
.mut_stack() .mut_stack()
.add(name_in_mem.clone(), value, metadata.source_range) .add(name_in_mem.clone(), value, metadata.source_range)
.map_err(|_| { .map_err(|_| {
KclError::Semantic(KclErrorDetails::new( KclError::new_semantic(KclErrorDetails::new(
format!("Redefinition of type {}.", ty.name.name), format!("Redefinition of type {}.", ty.name.name),
vec![metadata.source_range], vec![metadata.source_range],
)) ))
@ -373,7 +373,7 @@ impl ExecutorContext {
exec_state, exec_state,
metadata.source_range, metadata.source_range,
) )
.map_err(|e| KclError::Semantic(e.into()))?, .map_err(|e| KclError::new_semantic(e.into()))?,
), ),
meta: vec![metadata], meta: vec![metadata],
}; };
@ -382,7 +382,7 @@ impl ExecutorContext {
.mut_stack() .mut_stack()
.add(name_in_mem.clone(), value, metadata.source_range) .add(name_in_mem.clone(), value, metadata.source_range)
.map_err(|_| { .map_err(|_| {
KclError::Semantic(KclErrorDetails::new( KclError::new_semantic(KclErrorDetails::new(
format!("Redefinition of type {}.", ty.name.name), format!("Redefinition of type {}.", ty.name.name),
vec![metadata.source_range], vec![metadata.source_range],
)) ))
@ -393,7 +393,7 @@ impl ExecutorContext {
} }
} }
None => { None => {
return Err(KclError::Semantic(KclErrorDetails::new( return Err(KclError::new_semantic(KclErrorDetails::new(
"User-defined types are not yet supported.".to_owned(), "User-defined types are not yet supported.".to_owned(),
vec![metadata.source_range], vec![metadata.source_range],
))) )))
@ -407,7 +407,7 @@ impl ExecutorContext {
let metadata = Metadata::from(return_statement); let metadata = Metadata::from(return_statement);
if matches!(body_type, BodyType::Root) { 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(), "Cannot return from outside a function.".to_owned(),
vec![metadata.source_range], vec![metadata.source_range],
))); )));
@ -426,7 +426,7 @@ impl ExecutorContext {
.mut_stack() .mut_stack()
.add(memory::RETURN_NAME.to_owned(), value, metadata.source_range) .add(memory::RETURN_NAME.to_owned(), value, metadata.source_range)
.map_err(|_| { .map_err(|_| {
KclError::Semantic(KclErrorDetails::new( KclError::new_semantic(KclErrorDetails::new(
"Multiple returns from a single function.".to_owned(), "Multiple returns from a single function.".to_owned(),
vec![metadata.source_range], vec![metadata.source_range],
)) ))
@ -531,7 +531,7 @@ impl ExecutorContext {
*cache = Some((val, er, items.clone())); *cache = Some((val, er, items.clone()));
(er, items) (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(), "Cannot import items from foreign modules".to_owned(),
vec![geom.source_range], vec![geom.source_range],
))), ))),
@ -605,12 +605,12 @@ impl ExecutorContext {
exec_state.global.mod_loader.leave_module(path); exec_state.global.mod_loader.leave_module(path);
result.map_err(|err| { result.map_err(|err| {
if let KclError::ImportCycle(_) = err { if let KclError::ImportCycle { .. } = err {
// It was an import cycle. Keep the original message. // It was an import cycle. Keep the original message.
err.override_source_ranges(vec![source_range]) err.override_source_ranges(vec![source_range])
} else { } else {
// TODO would be great to have line/column for the underlying error here // TODO would be great to have line/column for the underlying error here
KclError::Semantic(KclErrorDetails::new( KclError::new_semantic(KclErrorDetails::new(
format!( format!(
"Error loading imported file ({path}). Open it to view more details.\n {}", "Error loading imported file ({path}). Open it to view more details.\n {}",
err.message() err.message()
@ -677,7 +677,7 @@ impl ExecutorContext {
meta: vec![metadata.to_owned()], meta: vec![metadata.to_owned()],
} }
} else { } 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(), "Rust implementation of functions is restricted to the standard library".to_owned(),
vec![metadata.source_range], vec![metadata.source_range],
))); )));
@ -704,7 +704,7 @@ impl ExecutorContext {
"you cannot declare variable {name} as %, because % can only be used in function calls" "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, message,
vec![pipe_substitution.into()], vec![pipe_substitution.into()],
))); )));
@ -712,7 +712,7 @@ impl ExecutorContext {
StatementKind::Expression => match exec_state.mod_local.pipe_value.clone() { StatementKind::Expression => match exec_state.mod_local.pipe_value.clone() {
Some(x) => x, Some(x) => x,
None => { None => {
return Err(KclError::Semantic(KclErrorDetails::new( return Err(KclError::new_semantic(KclErrorDetails::new(
"cannot use % outside a pipe expression".to_owned(), "cannot use % outside a pipe expression".to_owned(),
vec![pipe_substitution.into()], vec![pipe_substitution.into()],
))); )));
@ -761,7 +761,7 @@ fn apply_ascription(
source_range: SourceRange, source_range: SourceRange,
) -> Result<KclValue, KclError> { ) -> Result<KclValue, KclError> {
let ty = RuntimeType::from_parsed(ty.inner.clone(), exec_state, value.into()) 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(|_| { value.coerce(&ty, false, exec_state).map_err(|_| {
let suggestion = if ty == RuntimeType::length() { let suggestion = if ty == RuntimeType::length() {
@ -771,7 +771,7 @@ fn apply_ascription(
} else { } else {
"" ""
}; };
KclError::Semantic(KclErrorDetails::new( KclError::new_semantic(KclErrorDetails::new(
format!( format!(
"could not coerce value of type {} to type {ty}{suggestion}", "could not coerce value of type {} to type {ty}{suggestion}",
value.human_friendly_type() value.human_friendly_type()
@ -804,7 +804,7 @@ impl Node<Name> {
ctx: &ExecutorContext, ctx: &ExecutorContext,
) -> Result<&'a KclValue, KclError> { ) -> Result<&'a KclValue, KclError> {
if self.abs_path { 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(), "Absolute paths (names beginning with `::` are not yet supported)".to_owned(),
self.as_source_ranges(), self.as_source_ranges(),
))); )));
@ -825,7 +825,7 @@ impl Node<Name> {
let value = match mem_spec { let value = match mem_spec {
Some((env, exports)) => { Some((env, exports)) => {
if !exports.contains(&p.name) { 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), format!("Item {} not found in module's exported items", p.name),
p.as_source_ranges(), p.as_source_ranges(),
))); )));
@ -842,7 +842,7 @@ impl Node<Name> {
}; };
let KclValue::Module { value: module_id, .. } = value else { let KclValue::Module { value: module_id, .. } = value else {
return Err(KclError::Semantic(KclErrorDetails::new( return Err(KclError::new_semantic(KclErrorDetails::new(
format!( format!(
"Identifier in path must refer to a module, found {}", "Identifier in path must refer to a module, found {}",
value.human_friendly_type() value.human_friendly_type()
@ -888,7 +888,7 @@ impl Node<Name> {
// Either item or module is defined, but not exported. // Either item or module is defined, but not exported.
debug_assert!((item_value.is_ok() && !item_exported) || (mod_value.is_ok() && !mod_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), format!("Item {} not found in module's exported items", self.name.name),
self.name.as_source_ranges(), self.name.as_source_ranges(),
))) )))
@ -913,14 +913,14 @@ impl Node<MemberExpression> {
if let Some(value) = map.get(&property) { if let Some(value) = map.get(&property) {
Ok(value.to_owned()) Ok(value.to_owned())
} else { } else {
Err(KclError::UndefinedValue(KclErrorDetails::new( Err(KclError::new_undefined_value(KclErrorDetails::new(
format!("Property '{property}' not found in object"), format!("Property '{property}' not found in object"),
vec![self.clone().into()], vec![self.clone().into()],
))) )))
} }
} }
(KclValue::Object { .. }, Property::String(property), true) => { (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}`"), format!("Cannot index object with string; use dot notation instead, e.g. `obj.{property}`"),
vec![self.clone().into()], vec![self.clone().into()],
))) )))
@ -928,7 +928,7 @@ impl Node<MemberExpression> {
(KclValue::Object { .. }, p, _) => { (KclValue::Object { .. }, p, _) => {
let t = p.type_name(); let t = p.type_name();
let article = article_for(t); 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}",), format!("Only strings can be used as the property of an object, but you're using {article} {t}",),
vec![self.clone().into()], vec![self.clone().into()],
))) )))
@ -938,7 +938,7 @@ impl Node<MemberExpression> {
if let Some(value) = value_of_arr { if let Some(value) = value_of_arr {
Ok(value.to_owned()) Ok(value.to_owned())
} else { } else {
Err(KclError::UndefinedValue(KclErrorDetails::new( Err(KclError::new_undefined_value(KclErrorDetails::new(
format!("The array doesn't have any item at index {index}"), format!("The array doesn't have any item at index {index}"),
vec![self.clone().into()], vec![self.clone().into()],
))) )))
@ -950,7 +950,7 @@ impl Node<MemberExpression> {
(KclValue::HomArray { .. }, p, _) => { (KclValue::HomArray { .. }, p, _) => {
let t = p.type_name(); let t = p.type_name();
let article = article_for(t); 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}",), format!("Only integers >= 0 can be used as the index of an array, but you're using {article} {t}",),
vec![self.clone().into()], vec![self.clone().into()],
))) )))
@ -971,7 +971,7 @@ impl Node<MemberExpression> {
(being_indexed, _, _) => { (being_indexed, _, _) => {
let t = being_indexed.human_friendly_type(); let t = being_indexed.human_friendly_type();
let article = article_for(&t); 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}"), format!("Only arrays can be indexed, but you're trying to index {article} {t}"),
vec![self.clone().into()], vec![self.clone().into()],
))) )))
@ -1049,7 +1049,7 @@ impl Node<BinaryExpression> {
meta: _, meta: _,
} = left_value } = left_value
else { else {
return Err(KclError::Semantic(KclErrorDetails::new( return Err(KclError::new_semantic(KclErrorDetails::new(
format!( format!(
"Cannot apply logical operator to non-boolean value: {}", "Cannot apply logical operator to non-boolean value: {}",
left_value.human_friendly_type() left_value.human_friendly_type()
@ -1062,7 +1062,7 @@ impl Node<BinaryExpression> {
meta: _, meta: _,
} = right_value } = right_value
else { else {
return Err(KclError::Semantic(KclErrorDetails::new( return Err(KclError::new_semantic(KclErrorDetails::new(
format!( format!(
"Cannot apply logical operator to non-boolean value: {}", "Cannot apply logical operator to non-boolean value: {}",
right_value.human_friendly_type() right_value.human_friendly_type()
@ -1168,7 +1168,7 @@ impl Node<UnaryExpression> {
meta: _, meta: _,
} = value } = value
else { else {
return Err(KclError::Semantic(KclErrorDetails::new( return Err(KclError::new_semantic(KclErrorDetails::new(
format!( format!(
"Cannot apply unary operator ! to non-boolean value: {}", "Cannot apply unary operator ! to non-boolean value: {}",
value.human_friendly_type() value.human_friendly_type()
@ -1189,7 +1189,7 @@ impl Node<UnaryExpression> {
let value = &self.argument.get_result(exec_state, ctx).await?; let value = &self.argument.get_result(exec_state, ctx).await?;
let err = || { let err = || {
KclError::Semantic(KclErrorDetails::new( KclError::new_semantic(KclErrorDetails::new(
format!( format!(
"You can only negate numbers, planes, or lines, but this is a {}", "You can only negate numbers, planes, or lines, but this is a {}",
value.human_friendly_type() value.human_friendly_type()
@ -1292,7 +1292,7 @@ pub(crate) async fn execute_pipe_body(
ctx: &ExecutorContext, ctx: &ExecutorContext,
) -> Result<KclValue, KclError> { ) -> Result<KclValue, KclError> {
let Some((first, body)) = body.split_first() else { 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(), "Pipe expressions cannot be empty".to_owned(),
vec![source_range], vec![source_range],
))); )));
@ -1330,7 +1330,7 @@ async fn inner_execute_pipe_body(
) -> Result<KclValue, KclError> { ) -> Result<KclValue, KclError> {
for expression in body { for expression in body {
if let Expr::TagDeclarator(_) = expression { 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), format!("This cannot be in a PipeExpression: {:?}", expression),
vec![expression.into()], vec![expression.into()],
))); )));
@ -1404,7 +1404,7 @@ impl Node<ArrayRangeExpression> {
.await?; .await?;
let (start, start_ty) = start_val let (start, start_ty) = start_val
.as_int_with_ty() .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()), format!("Expected int but found {}", start_val.human_friendly_type()),
vec![self.into()], vec![self.into()],
)))?; )))?;
@ -1412,24 +1412,26 @@ impl Node<ArrayRangeExpression> {
let end_val = ctx let end_val = ctx
.execute_expr(&self.end_element, exec_state, &metadata, &[], StatementKind::Expression) .execute_expr(&self.end_element, exec_state, &metadata, &[], StatementKind::Expression)
.await?; .await?;
let (end, end_ty) = end_val.as_int_with_ty().ok_or(KclError::Semantic(KclErrorDetails::new( let (end, end_ty) = end_val
format!("Expected int but found {}", end_val.human_friendly_type()), .as_int_with_ty()
vec![self.into()], .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 { if start_ty != end_ty {
let start = start_val.as_ty_f64().unwrap_or(TyF64 { n: 0.0, ty: start_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 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 = end_val.as_ty_f64().unwrap_or(TyF64 { n: 0.0, ty: end_ty });
let end = fmt::human_display_number(end.n, 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}"), format!("Range start and end must be of the same type, but found {start} and {end}"),
vec![self.into()], vec![self.into()],
))); )));
} }
if end < start { 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}"), format!("Range start is greater than range end: {start} .. {end}"),
vec![self.into()], 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> { fn number_as_f64(v: &KclValue, source_range: SourceRange) -> Result<TyF64, KclError> {
v.as_ty_f64().ok_or_else(|| { v.as_ty_f64().ok_or_else(|| {
let actual_type = v.human_friendly_type(); let actual_type = v.human_friendly_type();
KclError::Semantic(KclErrorDetails::new( KclError::new_semantic(KclErrorDetails::new(
format!("Expected a number, but found {actual_type}",), format!("Expected a number, but found {actual_type}",),
vec![source_range], vec![source_range],
)) ))
@ -1585,13 +1587,13 @@ impl Property {
if let Some(x) = crate::try_f64_to_usize(value) { if let Some(x) = crate::try_f64_to_usize(value) {
Ok(Property::UInt(x)) Ok(Property::UInt(x))
} else { } 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"), format!("{value} is not a valid index, indices must be whole numbers >= 0"),
property_sr, property_sr,
))) )))
} }
} }
_ => Err(KclError::Semantic(KclErrorDetails::new( _ => Err(KclError::new_semantic(KclErrorDetails::new(
"Only numbers (>= 0) can be indexes".to_owned(), "Only numbers (>= 0) can be indexes".to_owned(),
vec![sr], vec![sr],
))), ))),
@ -1602,7 +1604,8 @@ impl Property {
} }
fn jvalue_to_prop(value: &KclValue, property_sr: Vec<SourceRange>, name: &str) -> Result<Property, KclError> { 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 { match value {
KclValue::Number{value: num, .. } => { KclValue::Number{value: num, .. } => {
let num = *num; let num = *num;
@ -1846,7 +1849,7 @@ d = b + c
crate::engine::conn_mock::EngineConnection::new() crate::engine::conn_mock::EngineConnection::new()
.await .await
.map_err(|err| { .map_err(|err| {
KclError::Internal(KclErrorDetails::new( KclError::new_internal(KclErrorDetails::new(
format!("Failed to create mock engine connection: {}", err), format!("Failed to create mock engine connection: {}", err),
vec![SourceRange::default()], vec![SourceRange::default()],
)) ))

View File

@ -295,7 +295,7 @@ impl Node<CallExpressionKw> {
let func = fn_name.get_result(exec_state, ctx).await?.clone(); let func = fn_name.get_result(exec_state, ctx).await?.clone();
let Some(fn_src) = func.as_function() else { 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(), "cannot call this because it isn't a function".to_string(),
vec![callsite], vec![callsite],
))); )));
@ -318,7 +318,7 @@ impl Node<CallExpressionKw> {
if let KclValue::Function { meta, .. } = func { if let KclValue::Function { meta, .. } = func {
source_ranges = meta.iter().map(|m| m.source_range).collect(); 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), format!("Result of user-defined function {} is undefined", fn_name),
source_ranges, 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 tag_id = if let Some(t) = value.sketch.tags.get(&tag.name) {
let mut t = t.clone(); let mut t = t.clone();
let Some(info) = t.get_cur_info() else { 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), format!("Tag {} does not have path info", tag.name),
vec![tag.into()], vec![tag.into()],
))); )));
@ -605,7 +605,7 @@ fn type_check_params_kw(
arg.value = arg arg.value = arg
.value .value
.coerce( .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, true,
exec_state, 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. // 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})`"); 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, message,
vec![arg.source_range], vec![arg.source_range],
)) ))
@ -670,7 +670,7 @@ fn type_check_params_kw(
let first = errors.next().unwrap(); let first = errors.next().unwrap();
errors.for_each(|e| exec_state.err(e)); 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 { if let Some(arg) = &mut args.unlabeled {
@ -680,12 +680,12 @@ fn type_check_params_kw(
.value .value
.coerce( .coerce(
&RuntimeType::from_parsed(ty.clone(), exec_state, arg.1.source_range) &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, true,
exec_state, exec_state,
) )
.map_err(|_| { .map_err(|_| {
KclError::Semantic(KclErrorDetails::new( KclError::new_semantic(KclErrorDetails::new(
format!( format!(
"The input argument of {} requires a value with type `{}`, but found {}", "The input argument of {} requires a value with type `{}`, but found {}",
fn_name fn_name
@ -742,7 +742,7 @@ fn assign_args_to_params_kw(
.add(name.clone(), value, default_val.source_range())?; .add(name.clone(), value, default_val.source_range())?;
} }
None => { None => {
return Err(KclError::Semantic(KclErrorDetails::new( return Err(KclError::new_semantic(KclErrorDetails::new(
format!( format!(
"This function requires a parameter {}, but you haven't passed it one.", "This function requires a parameter {}, but you haven't passed it one.",
name name
@ -759,12 +759,12 @@ fn assign_args_to_params_kw(
let Some(unlabeled) = unlabelled else { let Some(unlabeled) = unlabelled else {
return Err(if args.kw_args.labeled.contains_key(param_name) { 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}:`"), 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, source_ranges,
)) ))
} else { } 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(), "This function expects an unlabeled first parameter, but you haven't passed it one.".to_owned(),
source_ranges, source_ranges,
)) ))
@ -788,9 +788,9 @@ fn coerce_result_type(
if let Ok(Some(val)) = result { if let Ok(Some(val)) = result {
if let Some(ret_ty) = &fn_def.return_type { 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()) 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(|_| { let val = val.coerce(&ty, true, exec_state).map_err(|_| {
KclError::Semantic(KclErrorDetails::new( KclError::new_semantic(KclErrorDetails::new(
format!( format!(
"This function requires its result to be of type `{}`, but found {}", "This function requires its result to be of type `{}`, but found {}",
ty.human_friendly_type(), ty.human_friendly_type(),
@ -874,7 +874,7 @@ mod test {
"all params required, none given, should error", "all params required, none given, should error",
vec![req_param("x")], vec![req_param("x")],
vec![], 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(), "This function requires a parameter x, but you haven't passed it one.".to_owned(),
vec![SourceRange::default()], vec![SourceRange::default()],
))), ))),
@ -889,7 +889,7 @@ mod test {
"mixed params, too few given", "mixed params, too few given",
vec![req_param("x"), opt_param("y")], vec![req_param("x"), opt_param("y")],
vec![], 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(), "This function requires a parameter x, but you haven't passed it one.".to_owned(),
vec![SourceRange::default()], vec![SourceRange::default()],
))), ))),

View File

@ -469,7 +469,7 @@ impl TryFrom<PlaneData> for PlaneInfo {
PlaneData::NegYZ => PlaneName::NegYz, PlaneData::NegYZ => PlaneName::NegYz,
PlaneData::Plane(_) => { PlaneData::Plane(_) => {
// We will never get here since we already checked for 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), format!("PlaneData {:?} not found", value),
Default::default(), Default::default(),
))); )));
@ -477,7 +477,7 @@ impl TryFrom<PlaneData> for PlaneInfo {
}; };
let info = DEFAULT_PLANE_INFO.get(&name).ok_or_else(|| { let info = DEFAULT_PLANE_INFO.get(&name).ok_or_else(|| {
KclError::Internal(KclErrorDetails::new( KclError::new_internal(KclErrorDetails::new(
format!("Plane {} not found", name), format!("Plane {} not found", name),
Default::default(), Default::default(),
)) ))

View File

@ -37,25 +37,25 @@ pub async fn import_foreign(
) -> Result<PreImportedGeometry, KclError> { ) -> Result<PreImportedGeometry, KclError> {
// Make sure the file exists. // Make sure the file exists.
if !ctxt.fs.exists(file_path, source_range).await? { 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()), format!("File `{}` does not exist.", file_path.display()),
vec![source_range], vec![source_range],
))); )));
} }
let ext_format = get_import_format_from_extension(file_path.extension().ok_or_else(|| { 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()), format!("No file extension found for `{}`", file_path.display()),
vec![source_range], 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. // Get the format type from the extension of the file.
let format = if let Some(format) = format { let format = if let Some(format) = format {
// Validate the given format with the extension format. // Validate the given format with the extension format.
validate_extension_format(ext_format, format.clone()) 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 format
} else { } else {
ext_format ext_format
@ -66,11 +66,11 @@ pub async fn import_foreign(
.fs .fs
.read(file_path, source_range) .read(file_path, source_range)
.await .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. // 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(|| { 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()), format!("Could not get the file name from the path `{}`", file_path.display()),
vec![source_range], vec![source_range],
)) ))
@ -87,7 +87,7 @@ pub async fn import_foreign(
// file. // file.
if !file_contents.starts_with(b"glTF") { if !file_contents.starts_with(b"glTF") {
let json = gltf_json::Root::from_slice(&file_contents) 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. // Read the gltf file and check if there is a bin file.
for buffer in json.buffers.iter() { for buffer in json.buffers.iter() {
@ -95,16 +95,15 @@ pub async fn import_foreign(
if !uri.starts_with("data:") { if !uri.starts_with("data:") {
// We want this path relative to the file_path given. // We want this path relative to the file_path given.
let bin_path = file_path.parent().map(|p| p.join(uri)).ok_or_else(|| { 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()), format!("Could not get the parent path of the file `{}`", file_path.display()),
vec![source_range], vec![source_range],
)) ))
})?; })?;
let bin_contents = let bin_contents = ctxt.fs.read(&bin_path, source_range).await.map_err(|e| {
ctxt.fs.read(&bin_path, source_range).await.map_err(|e| { KclError::new_semantic(KclErrorDetails::new(e.to_string(), vec![source_range]))
KclError::Semantic(KclErrorDetails::new(e.to_string(), vec![source_range])) })?;
})?;
import_files.push(ImportFile { import_files.push(ImportFile {
path: uri.to_string(), path: uri.to_string(),
@ -141,7 +140,7 @@ pub(super) fn format_from_annotations(
if p.key.name == annotations::IMPORT_FORMAT { if p.key.name == annotations::IMPORT_FORMAT {
result = Some( result = Some(
get_import_format_from_extension(annotations::expect_ident(&p.value)?).map_err(|_| { get_import_format_from_extension(annotations::expect_ident(&p.value)?).map_err(|_| {
KclError::Semantic(KclErrorDetails::new( KclError::new_semantic(KclErrorDetails::new(
format!( format!(
"Unknown format for import, expected one of: {}", "Unknown format for import, expected one of: {}",
crate::IMPORT_FILE_EXTENSIONS.join(", ") crate::IMPORT_FILE_EXTENSIONS.join(", ")
@ -159,7 +158,7 @@ pub(super) fn format_from_annotations(
path.extension() path.extension()
.and_then(|ext| get_import_format_from_extension(ext).ok()) .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(), "Unknown or missing extension, and no specified format for imported file".to_owned(),
vec![import_source_range], vec![import_source_range],
)))?; )))?;
@ -174,7 +173,7 @@ pub(super) fn format_from_annotations(
} }
annotations::IMPORT_FORMAT => {} annotations::IMPORT_FORMAT => {}
_ => { _ => {
return Err(KclError::Semantic(KclErrorDetails::new( return Err(KclError::new_semantic(KclErrorDetails::new(
format!( format!(
"Unexpected annotation for import, expected one of: {}, {}, {}", "Unexpected annotation for import, expected one of: {}, {}, {}",
annotations::IMPORT_FORMAT, annotations::IMPORT_FORMAT,
@ -199,7 +198,7 @@ fn set_coords(fmt: &mut InputFormat3d, coords_str: &str, source_range: SourceRan
} }
let Some(coords) = coords else { let Some(coords) = coords else {
return Err(KclError::Semantic(KclErrorDetails::new( return Err(KclError::new_semantic(KclErrorDetails::new(
format!( format!(
"Unknown coordinate system: {coords_str}, expected one of: {}", "Unknown coordinate system: {coords_str}, expected one of: {}",
annotations::IMPORT_COORDS_VALUES 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::Ply(opts) => opts.coords = coords,
InputFormat3d::Stl(opts) => opts.coords = coords, InputFormat3d::Stl(opts) => opts.coords = coords,
_ => { _ => {
return Err(KclError::Semantic(KclErrorDetails::new( return Err(KclError::new_semantic(KclErrorDetails::new(
format!( format!(
"`{}` option cannot be applied to the specified format", "`{}` option cannot be applied to the specified format",
annotations::IMPORT_COORDS 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::Ply(opts) => opts.units = units.into(),
InputFormat3d::Stl(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!( format!(
"`{}` option cannot be applied to the specified format", "`{}` option cannot be applied to the specified format",
annotations::IMPORT_LENGTH_UNIT annotations::IMPORT_LENGTH_UNIT

View File

@ -574,7 +574,7 @@ impl KclValue {
pub fn get_tag_identifier(&self) -> Result<TagIdentifier, KclError> { pub fn get_tag_identifier(&self) -> Result<TagIdentifier, KclError> {
match self { match self {
KclValue::TagIdentifier(t) => Ok(*t.clone()), KclValue::TagIdentifier(t) => Ok(*t.clone()),
_ => Err(KclError::Semantic(KclErrorDetails::new( _ => Err(KclError::new_semantic(KclErrorDetails::new(
format!("Not a tag identifier: {:?}", self), format!("Not a tag identifier: {:?}", self),
self.clone().into(), self.clone().into(),
))), ))),
@ -585,7 +585,7 @@ impl KclValue {
pub fn get_tag_declarator(&self) -> Result<TagNode, KclError> { pub fn get_tag_declarator(&self) -> Result<TagNode, KclError> {
match self { match self {
KclValue::TagDeclarator(t) => Ok((**t).clone()), KclValue::TagDeclarator(t) => Ok((**t).clone()),
_ => Err(KclError::Semantic(KclErrorDetails::new( _ => Err(KclError::new_semantic(KclErrorDetails::new(
format!("Not a tag declarator: {:?}", self), format!("Not a tag declarator: {:?}", self),
self.clone().into(), self.clone().into(),
))), ))),
@ -595,7 +595,7 @@ impl KclValue {
/// If this KCL value is a bool, retrieve it. /// If this KCL value is a bool, retrieve it.
pub fn get_bool(&self) -> Result<bool, KclError> { pub fn get_bool(&self) -> Result<bool, KclError> {
self.as_bool().ok_or_else(|| { self.as_bool().ok_or_else(|| {
KclError::Type(KclErrorDetails::new( KclError::new_type(KclErrorDetails::new(
format!("Expected bool, found {}", self.human_friendly_type()), format!("Expected bool, found {}", self.human_friendly_type()),
self.into(), self.into(),
)) ))

View File

@ -367,7 +367,7 @@ impl ProgramMemory {
let name = var.trim_start_matches(TYPE_PREFIX).trim_start_matches(MODULE_PREFIX); 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"), format!("`{name}` is not defined"),
vec![source_range], 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), format!("`{}` is not defined", var),
vec![], vec![],
))) )))
@ -646,7 +646,7 @@ impl Stack {
pub fn add(&mut self, key: String, value: KclValue, source_range: SourceRange) -> Result<(), KclError> { pub fn add(&mut self, key: String, value: KclValue, source_range: SourceRange) -> Result<(), KclError> {
let env = self.memory.get_env(self.current_env.index()); let env = self.memory.get_env(self.current_env.index());
if env.contains_key(&key) { if env.contains_key(&key) {
return Err(KclError::ValueAlreadyDefined(KclErrorDetails::new( return Err(KclError::new_value_already_defined(KclErrorDetails::new(
format!("Cannot redefine `{}`", key), format!("Cannot redefine `{}`", key),
vec![source_range], vec![source_range],
))); )));

View File

@ -858,7 +858,7 @@ impl ExecutorContext {
for module in modules { for module in modules {
let Some((import_stmt, module_id, module_path, repr)) = universe.get(&module) else { 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()), 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)) 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"), format!("Module {module_path} not found in universe"),
vec![source_range], vec![source_range],
))), ))),
@ -1283,7 +1283,7 @@ impl ExecutorContext {
.await?; .await?;
let kittycad_modeling_cmds::websocket::OkWebSocketResponseData::Export { files } = resp else { 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:?}",), format!("Expected Export response, got {resp:?}",),
vec![SourceRange::default()], vec![SourceRange::default()],
))); )));
@ -1303,7 +1303,7 @@ impl ExecutorContext {
coords: *kittycad_modeling_cmds::coord::KITTYCAD, coords: *kittycad_modeling_cmds::coord::KITTYCAD,
created: if deterministic_time { created: if deterministic_time {
Some("2021-01-01T00:00:00Z".parse().map_err(|e| { 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), format!("Failed to parse date: {}", e),
vec![SourceRange::default()], vec![SourceRange::default()],
)) ))
@ -1383,7 +1383,7 @@ pub(crate) async fn parse_execute_with_project_dir(
let exec_ctxt = ExecutorContext { let exec_ctxt = ExecutorContext {
engine: Arc::new(Box::new( engine: Arc::new(Box::new(
crate::engine::conn_mock::EngineConnection::new().await.map_err(|err| { 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), format!("Failed to create mock engine connection: {}", err),
vec![SourceRange::default()], vec![SourceRange::default()],
)) ))
@ -1799,7 +1799,7 @@ foo
let err = result.unwrap_err(); let err = result.unwrap_err();
assert_eq!( assert_eq!(
err, err,
KclError::Syntax(KclErrorDetails::new( KclError::new_syntax(KclErrorDetails::new(
"Unexpected token: #".to_owned(), "Unexpected token: #".to_owned(),
vec![SourceRange::new(14, 15, ModuleId::default())], 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 // TODO: We don't currently parse this, but we should. It should be
// a runtime error instead. // a runtime error instead.
parse_execute(code10).await.unwrap_err(), parse_execute(code10).await.unwrap_err(),
KclError::Syntax(KclErrorDetails::new( KclError::new_syntax(KclErrorDetails::new(
"Unexpected token: !".to_owned(), "Unexpected token: !".to_owned(),
vec![SourceRange::new(10, 11, ModuleId::default())], 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 // TODO: We don't currently parse this, but we should. It should be
// a runtime error instead. // a runtime error instead.
parse_execute(code11).await.unwrap_err(), parse_execute(code11).await.unwrap_err(),
KclError::Syntax(KclErrorDetails::new( KclError::new_syntax(KclErrorDetails::new(
"There was an unexpected !. Try removing it.".to_owned(), "There was an unexpected !. Try removing it.".to_owned(),
vec![SourceRange::new(56, 57, ModuleId::default())], vec![SourceRange::new(56, 57, ModuleId::default())],
)) ))

View File

@ -276,7 +276,7 @@ impl ExecState {
} }
pub(super) fn circular_import_error(&self, path: &ModulePath, source_range: SourceRange) -> KclError { pub(super) fn circular_import_error(&self, path: &ModulePath, source_range: SourceRange) -> KclError {
KclError::ImportCycle(KclErrorDetails::new( KclError::new_import_cycle(KclErrorDetails::new(
format!( format!(
"circular import of modules is not allowed: {} -> {}", "circular import of modules is not allowed: {} -> {}",
self.global self.global
@ -389,7 +389,7 @@ impl MetaSettings {
self.kcl_version = value; self.kcl_version = value;
} }
name => { name => {
return Err(KclError::Semantic(KclErrorDetails::new( return Err(KclError::new_semantic(KclErrorDetails::new(
format!( format!(
"Unexpected settings key: `{name}`; expected one of `{}`, `{}`", "Unexpected settings key: `{name}`; expected one of `{}`, `{}`",
annotations::SETTINGS_UNIT_LENGTH, annotations::SETTINGS_UNIT_LENGTH,

View File

@ -28,7 +28,7 @@ impl Default for FileManager {
impl FileSystem for FileManager { impl FileSystem for FileManager {
async fn read(&self, path: &TypedPath, source_range: SourceRange) -> Result<Vec<u8>, KclError> { async fn read(&self, path: &TypedPath, source_range: SourceRange) -> Result<Vec<u8>, KclError> {
tokio::fs::read(&path.0).await.map_err(|e| { 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), format!("Failed to read file `{}`: {}", path.display(), e),
vec![source_range], 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> { 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| { 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), format!("Failed to read file `{}`: {}", path.display(), e),
vec![source_range], vec![source_range],
)) ))
@ -49,7 +49,7 @@ impl FileSystem for FileManager {
if e.kind() == std::io::ErrorKind::NotFound { if e.kind() == std::io::ErrorKind::NotFound {
Ok(false) Ok(false)
} else { } else {
Err(KclError::Io(KclErrorDetails::new( Err(KclError::new_io(KclErrorDetails::new(
format!("Failed to check if file `{}` exists: {}", path.display(), e), format!("Failed to check if file `{}` exists: {}", path.display(), e),
vec![source_range], vec![source_range],
))) )))
@ -71,7 +71,7 @@ impl FileSystem for FileManager {
} }
let mut read_dir = tokio::fs::read_dir(&path).await.map_err(|e| { 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), format!("Failed to read directory `{}`: {}", path.display(), e),
vec![source_range], vec![source_range],
)) ))

View File

@ -49,10 +49,10 @@ impl FileSystem for FileManager {
let promise = self let promise = self
.manager .manager
.read_file(path.to_string_lossy()) .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| { 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), format!("Failed to wait for promise from engine: {:?}", e),
vec![source_range], 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> { async fn read_to_string(&self, path: &TypedPath, source_range: SourceRange) -> Result<String, KclError> {
let bytes = self.read(path, source_range).await?; let bytes = self.read(path, source_range).await?;
let string = String::from_utf8(bytes).map_err(|e| { 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), format!("Failed to convert bytes to string: {:?}", e),
vec![source_range], vec![source_range],
)) ))
@ -80,17 +80,17 @@ impl FileSystem for FileManager {
let promise = self let promise = self
.manager .manager
.exists(path.to_string_lossy()) .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| { 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), format!("Failed to wait for promise from engine: {:?}", e),
vec![source_range], vec![source_range],
)) ))
})?; })?;
let it_exists = value.as_bool().ok_or_else(|| { 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(), "Failed to convert value to bool".to_string(),
vec![source_range], vec![source_range],
)) ))
@ -107,24 +107,24 @@ impl FileSystem for FileManager {
let promise = self let promise = self
.manager .manager
.get_all_files(path.to_string_lossy()) .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| { 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), format!("Failed to wait for promise from javascript: {:?}", e),
vec![source_range], vec![source_range],
)) ))
})?; })?;
let s = value.as_string().ok_or_else(|| { 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), format!("Failed to get string from response from javascript: `{:?}`", value),
vec![source_range], vec![source_range],
)) ))
})?; })?;
let files: Vec<String> = serde_json::from_str(&s).map_err(|e| { 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), format!("Failed to parse json from javascript: `{}` `{:?}`", s, e),
vec![source_range], vec![source_range],
)) ))

View File

@ -58,7 +58,7 @@ impl ModuleLoader {
} }
pub(crate) fn import_cycle_error(&self, path: &ModulePath, source_range: SourceRange) -> KclError { pub(crate) fn import_cycle_error(&self, path: &ModulePath, source_range: SourceRange) -> KclError {
KclError::ImportCycle(KclErrorDetails::new( KclError::new_import_cycle(KclErrorDetails::new(
format!( format!(
"circular import of modules is not allowed: {} -> {}", "circular import of modules is not allowed: {} -> {}",
self.import_stack self.import_stack
@ -163,7 +163,7 @@ impl ModulePath {
ModulePath::Std { value: name } => Ok(ModuleSource { ModulePath::Std { value: name } => Ok(ModuleSource {
source: read_std(name) source: read_std(name)
.ok_or_else(|| { .ok_or_else(|| {
KclError::Semantic(KclErrorDetails::new( KclError::new_semantic(KclErrorDetails::new(
format!("Cannot find standard library module to import: std::{name}."), format!("Cannot find standard library module to import: std::{name}."),
vec![source_range], vec![source_range],
)) ))
@ -202,7 +202,7 @@ impl ModulePath {
ModulePath::Std { .. } => { ModulePath::Std { .. } => {
let message = format!("Cannot import a non-std KCL file from std: {path}."); let message = format!("Cannot import a non-std KCL file from std: {path}.");
debug_assert!(false, "{}", &message); 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" { if path.len() != 2 || path[0] != "std" {
let message = format!("Invalid std import path: {path:?}."); let message = format!("Invalid std import path: {path:?}.");
debug_assert!(false, "{}", &message); 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() }) Ok(ModulePath::Std { value: path[1].clone() })

View File

@ -51,7 +51,7 @@ pub fn parse_tokens(mut tokens: TokenStream) -> ParseResult {
} else { } else {
format!("found unknown tokens [{}]", token_list.join(", ")) 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. // Important, to not call this before the unknown tokens check.
@ -110,7 +110,7 @@ impl ParseResult {
let (p, errs) = self.0?; let (p, errs) = self.0?;
if let Some(err) = errs.iter().find(|e| e.severity.is_err()) { 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 { match p {
Some(p) => Ok(p), Some(p) => Ok(p),

View File

@ -4412,7 +4412,7 @@ secondExtrude = startSketchOn(XY)
#[test] #[test]
fn test_parse_parens_unicode() { fn test_parse_parens_unicode() {
let result = crate::parsing::top_level_parse(""); 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!(); panic!();
}; };
// TODO: Better errors when program cannot tokenize. // TODO: Better errors when program cannot tokenize.

View File

@ -597,7 +597,7 @@ impl From<ParseError<Input<'_>, winnow::error::ContextError>> for KclError {
// This is an offset, not an index, and may point to // This is an offset, not an index, and may point to
// the end of input (input.len()) on eof errors. // 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(), "unexpected EOF while parsing".to_owned(),
vec![SourceRange::new(offset, offset, module_id)], 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]; let bad_token = &input[offset];
// TODO: Add the Winnow parser context to the error. // TODO: Add the Winnow parser context to the error.
// See https://github.com/KittyCAD/modeling-app/issues/784 // 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), format!("found unknown token '{}'", bad_token),
vec![SourceRange::new(offset, offset + 1, module_id)], vec![SourceRange::new(offset, offset + 1, module_id)],
)) ))

View File

@ -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. // Make sure the color if set is valid.
if let Some(component) = rgb.iter().find(|component| component.n < 0.0 || component.n > 255.0) { 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), format!("Colors are given between 0 and 255, so {} is invalid", component.n),
vec![args.source_range], 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. // Make sure the color if set is valid.
if !HEX_REGEX.is_match(&color) { 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), format!("Invalid hex color (`{}`), try something like `#fff000`", color),
vec![args.source_range], vec![args.source_range],
))); )));
@ -93,7 +93,7 @@ async fn inner_appearance(
for solid_id in solids.ids(&args.ctx).await? { for solid_id in solids.ids(&args.ctx).await? {
// Set the material properties. // Set the material properties.
let rgb = rgba_simple::RGB::<f32>::from_hex(&color).map_err(|err| { 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}"), format!("Invalid hex color (`{color}`): {err}"),
vec![args.source_range], vec![args.source_range],
)) ))

View File

@ -123,7 +123,7 @@ impl Args {
} }
T::from_kcl_val(&arg.value).map(Some).ok_or_else(|| { T::from_kcl_val(&arg.value).map(Some).ok_or_else(|| {
KclError::Type(KclErrorDetails::new( KclError::new_type(KclErrorDetails::new(
format!( format!(
"The arg {label} was given, but it was the wrong type. It should be type {} but it was {}", "The arg {label} was given, but it was the wrong type. It should be type {} but it was {}",
tynm::type_name::<T>(), tynm::type_name::<T>(),
@ -156,7 +156,7 @@ impl Args {
T: FromKclValue<'a>, T: FromKclValue<'a>,
{ {
self.get_kw_arg_opt(label)?.ok_or_else(|| { 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}'"), format!("This function requires a keyword argument '{label}'"),
vec![self.source_range], vec![self.source_range],
)) ))
@ -173,7 +173,7 @@ impl Args {
T: for<'a> FromKclValue<'a>, T: for<'a> FromKclValue<'a>,
{ {
let Some(arg) = self.kw_args.labeled.get(label) else { 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}'"), format!("This function requires a keyword argument '{label}'"),
vec![self.source_range], 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") { 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}"); 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 // TODO unnecessary cloning
@ -221,7 +221,7 @@ impl Args {
label: &str, label: &str,
) -> Result<Vec<(EdgeReference, SourceRange)>, KclError> { ) -> Result<Vec<(EdgeReference, SourceRange)>, KclError> {
let Some(arg) = self.kw_args.labeled.get(label) else { 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}'"), format!("This function requires a keyword argument '{label}'"),
vec![self.source_range], vec![self.source_range],
)); ));
@ -234,7 +234,7 @@ impl Args {
.map(|item| { .map(|item| {
let source = SourceRange::from(item); let source = SourceRange::from(item);
let val = FromKclValue::from_kcl_val(item).ok_or_else(|| { 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()), format!("Expected an Edge but found {}", arg.value.human_friendly_type()),
arg.source_ranges(), arg.source_ranges(),
)) ))
@ -270,7 +270,7 @@ impl Args {
{ {
let arg = self let arg = self
.unlabeled_kw_arg_unconverted() .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}'"), format!("This function requires a value for the special unlabeled first parameter, '{label}'"),
vec![self.source_range], 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") { 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}"); 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(|| { 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:?}"), 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], vec![self.source_range],
)) ))
@ -354,14 +354,14 @@ impl Args {
exec_state.stack().get_from_call_stack(&tag.value, self.source_range)? exec_state.stack().get_from_call_stack(&tag.value, self.source_range)?
{ {
let info = t.get_info(epoch).ok_or_else(|| { 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), format!("Tag `{}` does not have engine info", tag.value),
vec![self.source_range], vec![self.source_range],
)) ))
})?; })?;
Ok(info) Ok(info)
} else { } else {
Err(KclError::Type(KclErrorDetails::new( Err(KclError::new_type(KclErrorDetails::new(
format!("Tag `{}` does not exist", tag.value), format!("Tag `{}` does not exist", tag.value),
vec![self.source_range], vec![self.source_range],
))) )))
@ -493,7 +493,7 @@ impl Args {
must_be_planar: bool, must_be_planar: bool,
) -> Result<uuid::Uuid, KclError> { ) -> Result<uuid::Uuid, KclError> {
if tag.value.is_empty() { 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(), "Expected a non-empty tag for the face".to_string(),
vec![self.source_range], vec![self.source_range],
))); )));
@ -502,7 +502,7 @@ impl Args {
let engine_info = self.get_tag_engine_info_check_surface(exec_state, tag)?; let engine_info = self.get_tag_engine_info_check_surface(exec_state, tag)?;
let surface = engine_info.surface.as_ref().ok_or_else(|| { 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), format!("Tag `{}` does not have a surface", tag.value),
vec![self.source_range], vec![self.source_range],
)) ))
@ -521,7 +521,7 @@ impl Args {
} }
} }
// The must be planar check must be called before the arc check. // 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), format!("Tag `{}` is a non-planar surface", tag.value),
vec![self.source_range], vec![self.source_range],
)))), )))),
@ -548,7 +548,7 @@ impl Args {
} }
} }
// The must be planar check must be called before the fillet check. // 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), format!("Tag `{}` is a non-planar surface", tag.value),
vec![self.source_range], vec![self.source_range],
)))), )))),
@ -568,7 +568,7 @@ impl Args {
} }
// If we still haven't found the face, return an error. // 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), format!("Expected a face with the tag `{}`", tag.value),
vec![self.source_range], vec![self.source_range],
))) )))
@ -593,13 +593,13 @@ where
{ {
fn from_args(args: &'a Args, i: usize) -> Result<Self, KclError> { fn from_args(args: &'a Args, i: usize) -> Result<Self, KclError> {
let Some(arg) = args.args.get(i) else { 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}"), format!("Expected an argument at index {i}"),
vec![args.source_range], vec![args.source_range],
))); )));
}; };
let Some(val) = T::from_kcl_val(&arg.value) else { let Some(val) = T::from_kcl_val(&arg.value) else {
return Err(KclError::Semantic(KclErrorDetails::new( return Err(KclError::new_semantic(KclErrorDetails::new(
format!( format!(
"Argument at index {i} was supposed to be type {} but found {}", "Argument at index {i} was supposed to be type {} but found {}",
tynm::type_name::<T>(), tynm::type_name::<T>(),
@ -622,7 +622,7 @@ where
return Ok(None); return Ok(None);
} }
let Some(val) = T::from_kcl_val(&arg.value) else { let Some(val) = T::from_kcl_val(&arg.value) else {
return Err(KclError::Semantic(KclErrorDetails::new( return Err(KclError::new_semantic(KclErrorDetails::new(
format!( format!(
"Argument at index {i} was supposed to be type Option<{}> but found {}", "Argument at index {i} was supposed to be type Option<{}> but found {}",
tynm::type_name::<T>(), tynm::type_name::<T>(),

View File

@ -58,7 +58,7 @@ async fn call_map_closure(
let output = map_fn.call_kw(None, exec_state, ctxt, args, source_range).await?; let output = map_fn.call_kw(None, exec_state, ctxt, args, source_range).await?;
let source_ranges = vec![source_range]; let source_ranges = vec![source_range];
let output = output.ok_or_else(|| { let output = output.ok_or_else(|| {
KclError::Semantic(KclErrorDetails::new( KclError::new_semantic(KclErrorDetails::new(
"Map function must return a value".to_owned(), "Map function must return a value".to_owned(),
source_ranges, source_ranges,
)) ))
@ -118,7 +118,7 @@ async fn call_reduce_closure(
// Unpack the returned transform object. // Unpack the returned transform object.
let source_ranges = vec![source_range]; let source_ranges = vec![source_range];
let out = transform_fn_return.ok_or_else(|| { 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(), "Reducer function must return a value".to_string(),
source_ranges.clone(), 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> { 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)?; let (mut array, ty) = args.get_unlabeled_kw_arg_array_and_type("array", exec_state)?;
if array.is_empty() { 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(), "Cannot pop from an empty array".to_string(),
vec![args.source_range], vec![args.source_range],
))); )));

View File

@ -11,7 +11,7 @@ use crate::{
async fn _assert(value: bool, message: &str, args: &Args) -> Result<(), KclError> { async fn _assert(value: bool, message: &str, args: &Args) -> Result<(), KclError> {
if !value { if !value {
return Err(KclError::Type(KclErrorDetails::new( return Err(KclError::new_type(KclErrorDetails::new(
format!("assert failed: {}", message), format!("assert failed: {}", message),
vec![args.source_range], vec![args.source_range],
))); )));
@ -72,14 +72,14 @@ async fn inner_assert(
.iter() .iter()
.all(|cond| cond.is_none()); .all(|cond| cond.is_none());
if no_condition_given { 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(), "You must provide at least one condition in this assert (for example, isEqualTo)".to_owned(),
vec![args.source_range], vec![args.source_range],
))); )));
} }
if tolerance.is_some() && is_equal_to.is_none() { 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." "The `tolerance` arg is only used with `isEqualTo`. Either remove `tolerance` or add an `isEqualTo` arg."
.to_owned(), .to_owned(),
vec![args.source_range], vec![args.source_range],

View File

@ -41,7 +41,7 @@ async fn inner_chamfer(
// If you try and tag multiple edges with a tagged chamfer, we want to return an // 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. // error to the user that they can only tag one edge at a time.
if tag.is_some() && tags.len() > 1 { 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(), "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], vec![args.source_range],
))); )));

View File

@ -84,7 +84,7 @@ async fn inner_clone(
fix_tags_and_references(&mut new_geometry, old_id, exec_state, &args) fix_tags_and_references(&mut new_geometry, old_id, exec_state, &args)
.await .await
.map_err(|e| { .map_err(|e| {
KclError::Internal(KclErrorDetails::new( KclError::new_internal(KclErrorDetails::new(
format!("failed to fix tags and references: {:?}", e), format!("failed to fix tags and references: {:?}", e),
vec![args.source_range], vec![args.source_range],
)) ))

View File

@ -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)?; let tolerance: Option<TyF64> = args.get_kw_arg_opt_typed("tolerance", &RuntimeType::length(), exec_state)?;
if solids.len() < 2 { 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(), "At least two solids are required for a union operation.".to_string(),
vec![args.source_range], vec![args.source_range],
))); )));
@ -66,7 +66,7 @@ pub(crate) async fn inner_union(
modeling_response: OkModelingCmdResponse::BooleanUnion(BooleanUnion { extra_solid_ids }), modeling_response: OkModelingCmdResponse::BooleanUnion(BooleanUnion { extra_solid_ids }),
} = result } = result
else { 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(), "Failed to get the result of the union operation.".to_string(),
vec![args.source_range], 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)?; let tolerance: Option<TyF64> = args.get_kw_arg_opt_typed("tolerance", &RuntimeType::length(), exec_state)?;
if solids.len() < 2 { 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(), "At least two solids are required for an intersect operation.".to_string(),
vec![args.source_range], vec![args.source_range],
))); )));
@ -131,7 +131,7 @@ pub(crate) async fn inner_intersect(
modeling_response: OkModelingCmdResponse::BooleanIntersection(BooleanIntersection { extra_solid_ids }), modeling_response: OkModelingCmdResponse::BooleanIntersection(BooleanIntersection { extra_solid_ids }),
} = result } = result
else { 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(), "Failed to get the result of the intersection operation.".to_string(),
vec![args.source_range], vec![args.source_range],
))); )));
@ -193,7 +193,7 @@ pub(crate) async fn inner_subtract(
modeling_response: OkModelingCmdResponse::BooleanSubtract(BooleanSubtract { extra_solid_ids }), modeling_response: OkModelingCmdResponse::BooleanSubtract(BooleanSubtract { extra_solid_ids }),
} = result } = result
else { 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(), "Failed to get the result of the subtract operation.".to_string(),
vec![args.source_range], vec![args.source_range],
))); )));

View File

@ -52,7 +52,7 @@ async fn inner_get_opposite_edge(
modeling_response: OkModelingCmdResponse::Solid3dGetOppositeEdge(opposite_edge), modeling_response: OkModelingCmdResponse::Solid3dGetOppositeEdge(opposite_edge),
} = &resp } = &resp
else { else {
return Err(KclError::Engine(KclErrorDetails::new( return Err(KclError::new_engine(KclErrorDetails::new(
format!("mcmd::Solid3dGetOppositeEdge response was not as expected: {:?}", resp), format!("mcmd::Solid3dGetOppositeEdge response was not as expected: {:?}", resp),
vec![args.source_range], vec![args.source_range],
))); )));
@ -100,7 +100,7 @@ async fn inner_get_next_adjacent_edge(
modeling_response: OkModelingCmdResponse::Solid3dGetNextAdjacentEdge(adjacent_edge), modeling_response: OkModelingCmdResponse::Solid3dGetNextAdjacentEdge(adjacent_edge),
} = &resp } = &resp
else { else {
return Err(KclError::Engine(KclErrorDetails::new( return Err(KclError::new_engine(KclErrorDetails::new(
format!( format!(
"mcmd::Solid3dGetNextAdjacentEdge response was not as expected: {:?}", "mcmd::Solid3dGetNextAdjacentEdge response was not as expected: {:?}",
resp resp
@ -110,7 +110,7 @@ async fn inner_get_next_adjacent_edge(
}; };
adjacent_edge.edge.ok_or_else(|| { 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), format!("No edge found next adjacent to tag: `{}`", edge.value),
vec![args.source_range], vec![args.source_range],
)) ))
@ -155,7 +155,7 @@ async fn inner_get_previous_adjacent_edge(
modeling_response: OkModelingCmdResponse::Solid3dGetPrevAdjacentEdge(adjacent_edge), modeling_response: OkModelingCmdResponse::Solid3dGetPrevAdjacentEdge(adjacent_edge),
} = &resp } = &resp
else { else {
return Err(KclError::Engine(KclErrorDetails::new( return Err(KclError::new_engine(KclErrorDetails::new(
format!( format!(
"mcmd::Solid3dGetPrevAdjacentEdge response was not as expected: {:?}", "mcmd::Solid3dGetPrevAdjacentEdge response was not as expected: {:?}",
resp resp
@ -165,7 +165,7 @@ async fn inner_get_previous_adjacent_edge(
}; };
adjacent_edge.edge.ok_or_else(|| { 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), format!("No edge found previous adjacent to tag: `{}`", edge.value),
vec![args.source_range], vec![args.source_range],
)) ))
@ -198,7 +198,7 @@ async fn inner_get_common_edge(
} }
if faces.len() != 2 { 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(), "getCommonEdge requires exactly two tags for faces".to_string(),
vec![args.source_range], 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])?; let second_tagged_path = args.get_tag_engine_info(exec_state, &faces[1])?;
if first_tagged_path.sketch != second_tagged_path.sketch { 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(), "getCommonEdge requires the faces to be in the same original sketch".to_string(),
vec![args.source_range], vec![args.source_range],
))); )));
@ -239,14 +239,14 @@ async fn inner_get_common_edge(
modeling_response: OkModelingCmdResponse::Solid3dGetCommonEdge(common_edge), modeling_response: OkModelingCmdResponse::Solid3dGetCommonEdge(common_edge),
} = &resp } = &resp
else { else {
return Err(KclError::Engine(KclErrorDetails::new( return Err(KclError::new_engine(KclErrorDetails::new(
format!("mcmd::Solid3dGetCommonEdge response was not as expected: {:?}", resp), format!("mcmd::Solid3dGetCommonEdge response was not as expected: {:?}", resp),
vec![args.source_range], vec![args.source_range],
))); )));
}; };
common_edge.edge.ok_or_else(|| { common_edge.edge.ok_or_else(|| {
KclError::Type(KclErrorDetails::new( KclError::new_type(KclErrorDetails::new(
format!( format!(
"No common edge was found between `{}` and `{}`", "No common edge was found between `{}` and `{}`",
faces[0].value, faces[1].value faces[0].value, faces[1].value

View File

@ -66,7 +66,7 @@ async fn inner_extrude(
let mut solids = Vec::new(); let mut solids = Vec::new();
if symmetric.unwrap_or(false) && bidirectional_length.is_some() { 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" "You cannot give both `symmetric` and `bidirectional` params, you have to choose one or the other"
.to_owned(), .to_owned(),
vec![args.source_range], 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. // The "get extrusion face info" API call requires *any* edge on the sketch being extruded.
// So, let's just use the first one. // 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 { 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(), "Expected a non-empty sketch".to_owned(),
vec![args.source_range], 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. // Add the tags for the start or end caps.
if let Some(tag_start) = named_cap_tags.start { if let Some(tag_start) = named_cap_tags.start {
let Some(start_cap_id) = start_cap_id else { let Some(start_cap_id) = start_cap_id else {
return Err(KclError::Type(KclErrorDetails::new( return Err(KclError::new_type(KclErrorDetails::new(
format!( format!(
"Expected a start cap ID for tag `{}` for extrusion of sketch {:?}", "Expected a start cap ID for tag `{}` for extrusion of sketch {:?}",
tag_start.name, sketch.id 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 { if let Some(tag_end) = named_cap_tags.end {
let Some(end_cap_id) = end_cap_id else { let Some(end_cap_id) = end_cap_id else {
return Err(KclError::Type(KclErrorDetails::new( return Err(KclError::new_type(KclErrorDetails::new(
format!( format!(
"Expected an end cap ID for tag `{}` for extrusion of sketch {:?}", "Expected an end cap ID for tag `{}` for extrusion of sketch {:?}",
tag_end.name, sketch.id tag_end.name, sketch.id

View File

@ -49,7 +49,7 @@ pub(super) fn validate_unique<T: Eq + std::hash::Hash>(tags: &[(T, SourceRange)]
} }
} }
if !duplicate_tags_source.is_empty() { 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" "The same edge ID is being referenced multiple times, which is not allowed. Please select a different edge"
.to_string(), .to_string(),
duplicate_tags_source, 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 // 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. // error to the user that they can only tag one edge at a time.
if tag.is_some() && tags.len() > 1 { 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(), 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], source_ranges: vec![args.source_range],
backtrace: Default::default(), backtrace: Default::default(),
})); }));
} }
if tags.is_empty() { if tags.is_empty() {
return Err(KclError::Semantic(KclErrorDetails { return Err(KclError::new_semantic(KclErrorDetails {
source_ranges: vec![args.source_range], source_ranges: vec![args.source_range],
message: "You must fillet at least one tag".to_owned(), message: "You must fillet at least one tag".to_owned(),
backtrace: Default::default(), backtrace: Default::default(),

View File

@ -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. // Make sure we have a radius if we don't have a cylinder.
if radius.is_none() && cylinder.is_none() { 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(), "Radius is required when creating a helix without a cylinder.".to_string(),
vec![args.source_range], 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. // Make sure we don't have a radius if we have a cylinder.
if radius.is_some() && cylinder.is_some() { 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(), "Radius is not allowed when creating a helix with a cylinder.".to_string(),
vec![args.source_range], 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. // Make sure we have an axis if we don't have a cylinder.
if axis.is_none() && cylinder.is_none() { 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(), "Axis is required when creating a helix without a cylinder.".to_string(),
vec![args.source_range], 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. // Make sure we don't have an axis if we have a cylinder.
if axis.is_some() && cylinder.is_some() { 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(), "Axis is not allowed when creating a helix with a cylinder.".to_string(),
vec![args.source_range], 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. // Make sure we have a radius if we have an axis.
if radius.is_none() && axis.is_some() { 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(), "Radius is required when creating a helix around an axis.".to_string(),
vec![args.source_range], 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. // Make sure we have an axis if we have a radius.
if axis.is_none() && radius.is_some() { 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(), "Axis is required when creating a helix around an axis.".to_string(),
vec![args.source_range], vec![args.source_range],
))); )));
@ -140,7 +140,7 @@ async fn inner_helix(
Axis3dOrEdgeReference::Axis { direction, origin } => { Axis3dOrEdgeReference::Axis { direction, origin } => {
// Make sure they gave us a length. // Make sure they gave us a length.
let Some(length) = length else { 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(), "Length is required when creating a helix around an axis.".to_owned(),
vec![args.source_range], vec![args.source_range],
))); )));

View File

@ -68,7 +68,7 @@ async fn inner_loft(
) -> Result<Box<Solid>, KclError> { ) -> Result<Box<Solid>, KclError> {
// Make sure we have at least two sketches. // Make sure we have at least two sketches.
if sketches.len() < 2 { if sketches.len() < 2 {
return Err(KclError::Semantic(KclErrorDetails::new( return Err(KclError::new_semantic(KclErrorDetails::new(
format!( format!(
"Loft requires at least two sketches, but only {} were provided.", "Loft requires at least two sketches, but only {} were provided.",
sketches.len() sketches.len()

View File

@ -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)?; let input: TyF64 = args.get_unlabeled_kw_arg_typed("input", &RuntimeType::num_any(), exec_state)?;
if input.n < 0.0 { if input.n < 0.0 {
return Err(KclError::Semantic(KclErrorDetails::new( return Err(KclError::new_semantic(KclErrorDetails::new(
format!( format!(
"Attempt to take square root (`sqrt`) of a number less than zero ({})", "Attempt to take square root (`sqrt`) of a number less than zero ({})",
input.n input.n

View File

@ -101,7 +101,7 @@ async fn inner_mirror_2d(
OkModelingCmdResponse::EntityGetAllChildUuids(EntityGetAllChildUuids { entity_ids: child_ids }), OkModelingCmdResponse::EntityGetAllChildUuids(EntityGetAllChildUuids { entity_ids: child_ids }),
} = response } = response
else { else {
return Err(KclError::Internal(KclErrorDetails::new( return Err(KclError::new_internal(KclErrorDetails::new(
"Expected a successful response from EntityGetAllChildUuids".to_string(), "Expected a successful response from EntityGetAllChildUuids".to_string(),
vec![args.source_range], vec![args.source_range],
))); )));
@ -112,7 +112,7 @@ async fn inner_mirror_2d(
let child_id = child_ids[1]; let child_id = child_ids[1];
sketch.mirror = Some(child_id); sketch.mirror = Some(child_id);
} else { } else {
return Err(KclError::Type(KclErrorDetails::new( return Err(KclError::new_type(KclErrorDetails::new(
"Expected child uuids to be >= 2".to_string(), "Expected child uuids to be >= 2".to_string(),
vec![args.source_range], vec![args.source_range],
))); )));

View File

@ -66,7 +66,7 @@ async fn inner_pattern_transform<'a>(
// Build the vec of transforms, one for each repetition. // Build the vec of transforms, one for each repetition.
let mut transform_vec = Vec::with_capacity(usize::try_from(instances).unwrap()); let mut transform_vec = Vec::with_capacity(usize::try_from(instances).unwrap());
if instances < 1 { if instances < 1 {
return Err(KclError::Semantic(KclErrorDetails::new( return Err(KclError::new_semantic(KclErrorDetails::new(
MUST_HAVE_ONE_INSTANCE.to_owned(), MUST_HAVE_ONE_INSTANCE.to_owned(),
vec![args.source_range], vec![args.source_range],
))); )));
@ -96,7 +96,7 @@ async fn inner_pattern_transform_2d<'a>(
// Build the vec of transforms, one for each repetition. // Build the vec of transforms, one for each repetition.
let mut transform_vec = Vec::with_capacity(usize::try_from(instances).unwrap()); let mut transform_vec = Vec::with_capacity(usize::try_from(instances).unwrap());
if instances < 1 { if instances < 1 {
return Err(KclError::Semantic(KclErrorDetails::new( return Err(KclError::new_semantic(KclErrorDetails::new(
MUST_HAVE_ONE_INSTANCE.to_owned(), MUST_HAVE_ONE_INSTANCE.to_owned(),
vec![args.source_range], vec![args.source_range],
))); )));
@ -176,7 +176,7 @@ async fn send_pattern_transform<T: GeometryTrait>(
} }
&mock_ids &mock_ids
} else { } else {
return Err(KclError::Engine(KclErrorDetails::new( return Err(KclError::new_engine(KclErrorDetails::new(
format!("EntityLinearPattern response was not as expected: {:?}", resp), format!("EntityLinearPattern response was not as expected: {:?}", resp),
vec![args.source_range], vec![args.source_range],
))); )));
@ -222,7 +222,7 @@ async fn make_transform<T: GeometryTrait>(
// Unpack the returned transform object. // Unpack the returned transform object.
let source_ranges = vec![source_range]; let source_ranges = vec![source_range];
let transform_fn_return = transform_fn_return.ok_or_else(|| { 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(), "Transform function must return a value".to_string(),
source_ranges.clone(), source_ranges.clone(),
)) ))
@ -233,7 +233,7 @@ async fn make_transform<T: GeometryTrait>(
let transforms: Vec<_> = value let transforms: Vec<_> = value
.into_iter() .into_iter()
.map(|val| { .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(), "Transform function must return a transform object".to_string(),
source_ranges.clone(), source_ranges.clone(),
))) )))
@ -242,7 +242,7 @@ async fn make_transform<T: GeometryTrait>(
transforms transforms
} }
_ => { _ => {
return Err(KclError::Semantic(KclErrorDetails::new( return Err(KclError::new_semantic(KclErrorDetails::new(
"Transform function must return a transform object".to_string(), "Transform function must return a transform object".to_string(),
source_ranges.clone(), source_ranges.clone(),
))) )))
@ -265,7 +265,7 @@ fn transform_from_obj_fields<T: GeometryTrait>(
Some(KclValue::Bool { value: true, .. }) => true, Some(KclValue::Bool { value: true, .. }) => true,
Some(KclValue::Bool { value: false, .. }) => false, Some(KclValue::Bool { value: false, .. }) => false,
Some(_) => { Some(_) => {
return Err(KclError::Semantic(KclErrorDetails::new( return Err(KclError::new_semantic(KclErrorDetails::new(
"The 'replicate' key must be a bool".to_string(), "The 'replicate' key must be a bool".to_string(),
source_ranges.clone(), source_ranges.clone(),
))); )));
@ -297,7 +297,7 @@ fn transform_from_obj_fields<T: GeometryTrait>(
let mut rotation = Rotation::default(); let mut rotation = Rotation::default();
if let Some(rot) = transform.get("rotation") { if let Some(rot) = transform.get("rotation") {
let KclValue::Object { value: rot, meta: _ } = rot else { 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(), "The 'rotation' key must be an object (with optional fields 'angle', 'axis' and 'origin')".to_owned(),
source_ranges.clone(), source_ranges.clone(),
))); )));
@ -311,7 +311,7 @@ fn transform_from_obj_fields<T: GeometryTrait>(
rotation.angle = Angle::from_degrees(*number); 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(), "The 'rotation.angle' key must be a number (of degrees)".to_owned(),
source_ranges.clone(), source_ranges.clone(),
))); )));
@ -345,7 +345,7 @@ fn array_to_point3d(
) -> Result<[TyF64; 3], KclError> { ) -> Result<[TyF64; 3], KclError> {
val.coerce(&RuntimeType::point3d(), true, exec_state) val.coerce(&RuntimeType::point3d(), true, exec_state)
.map_err(|e| { .map_err(|e| {
KclError::Semantic(KclErrorDetails::new( KclError::new_semantic(KclErrorDetails::new(
format!( format!(
"Expected an array of 3 numbers (i.e., a 3D point), found {}", "Expected an array of 3 numbers (i.e., a 3D point), found {}",
e.found e.found
@ -365,7 +365,7 @@ fn array_to_point2d(
) -> Result<[TyF64; 2], KclError> { ) -> Result<[TyF64; 2], KclError> {
val.coerce(&RuntimeType::point2d(), true, exec_state) val.coerce(&RuntimeType::point2d(), true, exec_state)
.map_err(|e| { .map_err(|e| {
KclError::Semantic(KclErrorDetails::new( KclError::new_semantic(KclErrorDetails::new(
format!( format!(
"Expected an array of 2 numbers (i.e., a 2D point), found {}", "Expected an array of 2 numbers (i.e., a 2D point), found {}",
e.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(); let axis = axis.to_point2d();
if axis[0].n == 0.0 && axis[1].n == 0.0 { 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." "The axis of the linear pattern cannot be the zero vector. Otherwise they will just duplicate in place."
.to_owned(), .to_owned(),
vec![args.source_range], 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(); let axis = axis.to_point3d();
if axis[0].n == 0.0 && axis[1].n == 0.0 && axis[2].n == 0.0 { 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." "The axis of the linear pattern cannot be the zero vector. Otherwise they will just duplicate in place."
.to_owned(), .to_owned(),
vec![args.source_range], vec![args.source_range],
@ -803,7 +803,7 @@ async fn inner_pattern_circular_2d(
.await?; .await?;
let Geometries::Sketches(new_sketches) = geometries else { 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(), "Expected a vec of sketches".to_string(),
vec![args.source_range], vec![args.source_range],
))); )));
@ -901,7 +901,7 @@ async fn inner_pattern_circular_3d(
.await?; .await?;
let Geometries::Solids(new_solids) = geometries else { 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(), "Expected a vec of solids".to_string(),
vec![args.source_range], vec![args.source_range],
))); )));
@ -926,7 +926,7 @@ async fn pattern_circular(
return Ok(Geometries::from(geometry)); return Ok(Geometries::from(geometry));
} }
RepetitionsNeeded::Invalid => { RepetitionsNeeded::Invalid => {
return Err(KclError::Semantic(KclErrorDetails::new( return Err(KclError::new_semantic(KclErrorDetails::new(
MUST_HAVE_ONE_INSTANCE.to_owned(), MUST_HAVE_ONE_INSTANCE.to_owned(),
vec![args.source_range], vec![args.source_range],
))); )));
@ -971,7 +971,7 @@ async fn pattern_circular(
} }
&mock_ids &mock_ids
} else { } else {
return Err(KclError::Engine(KclErrorDetails::new( return Err(KclError::new_engine(KclErrorDetails::new(
format!("EntityCircularPattern response was not as expected: {:?}", resp), format!("EntityCircularPattern response was not as expected: {:?}", resp),
vec![args.source_range], vec![args.source_range],
))); )));

View File

@ -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 // 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. // 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 { 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), format!("Expected angle to be between -360 and 360 and not 0, found `{}`", angle),
vec![args.source_range], 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 // 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. // 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 { 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!( format!(
"Expected bidirectional angle to be between -360 and 360 and not 0, found `{}`", "Expected bidirectional angle to be between -360 and 360 and not 0, found `{}`",
bidirectional_angle bidirectional_angle
@ -99,7 +99,7 @@ async fn inner_revolve(
if let Some(angle) = angle { if let Some(angle) = angle {
let ang = angle.signum() * bidirectional_angle + angle; let ang = angle.signum() * bidirectional_angle + angle;
if !(-360.0..=360.0).contains(&ang) { if !(-360.0..=360.0).contains(&ang) {
return Err(KclError::Semantic(KclErrorDetails::new( return Err(KclError::new_semantic(KclErrorDetails::new(
format!( format!(
"Combined angle and bidirectional must be between -360 and 360, found '{}'", "Combined angle and bidirectional must be between -360 and 360, found '{}'",
ang ang
@ -111,7 +111,7 @@ async fn inner_revolve(
} }
if symmetric.unwrap_or(false) && bidirectional_angle.is_some() { 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" "You cannot give both `symmetric` and `bidirectional` params, you have to choose one or the other"
.to_owned(), .to_owned(),
vec![args.source_range], vec![args.source_range],

View File

@ -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> { 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 line = args.get_tag_engine_info(exec_state, tag)?;
let path = line.path.clone().ok_or_else(|| { 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), format!("Expected a line segment with a path, found `{:?}`", line),
vec![args.source_range], 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> { 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 line = args.get_tag_engine_info(exec_state, tag)?;
let path = line.path.clone().ok_or_else(|| { 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), format!("Expected a line segment with a path, found `{:?}`", line),
vec![args.source_range], 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> { 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 line = args.get_tag_engine_info(exec_state, tag)?;
let path = line.path.clone().ok_or_else(|| { 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), format!("Expected a line segment with a path, found `{:?}`", line),
vec![args.source_range], 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> { 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 line = args.get_tag_engine_info(exec_state, tag)?;
let path = line.path.clone().ok_or_else(|| { 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), format!("Expected a line segment with a path, found `{:?}`", line),
vec![args.source_range], 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> { 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 line = args.get_tag_engine_info(exec_state, tag)?;
let path = line.path.clone().ok_or_else(|| { 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), format!("Expected a line segment with a path, found `{:?}`", line),
vec![args.source_range], 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> { 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 line = args.get_tag_engine_info(exec_state, tag)?;
let path = line.path.clone().ok_or_else(|| { 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), format!("Expected a line segment with a path, found `{:?}`", line),
vec![args.source_range], vec![args.source_range],
)) ))
@ -327,7 +327,7 @@ fn inner_last_segment_x(sketch: Sketch, args: Args) -> Result<TyF64, KclError> {
.paths .paths
.last() .last()
.ok_or_else(|| { .ok_or_else(|| {
KclError::Type(KclErrorDetails::new( KclError::new_type(KclErrorDetails::new(
format!("Expected a Sketch with at least one segment, found `{:?}`", sketch), format!("Expected a Sketch with at least one segment, found `{:?}`", sketch),
vec![args.source_range], vec![args.source_range],
)) ))
@ -373,7 +373,7 @@ fn inner_last_segment_y(sketch: Sketch, args: Args) -> Result<TyF64, KclError> {
.paths .paths
.last() .last()
.ok_or_else(|| { .ok_or_else(|| {
KclError::Type(KclErrorDetails::new( KclError::new_type(KclErrorDetails::new(
format!("Expected a Sketch with at least one segment, found `{:?}`", sketch), format!("Expected a Sketch with at least one segment, found `{:?}`", sketch),
vec![args.source_range], 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> { 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 line = args.get_tag_engine_info(exec_state, tag)?;
let path = line.path.clone().ok_or_else(|| { 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), format!("Expected a line segment with a path, found `{:?}`", line),
vec![args.source_range], 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> { 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 line = args.get_tag_engine_info(exec_state, tag)?;
let path = line.path.clone().ok_or_else(|| { 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), format!("Expected a line segment with a path, found `{:?}`", line),
vec![args.source_range], 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> { 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 line = args.get_tag_engine_info(exec_state, tag)?;
let path = line.path.clone().ok_or_else(|| { 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), format!("Expected a line segment with a path, found `{:?}`", line),
vec![args.source_range], vec![args.source_range],
)) ))

View File

@ -271,14 +271,14 @@ async fn inner_polygon(
args: Args, args: Args,
) -> Result<Sketch, KclError> { ) -> Result<Sketch, KclError> {
if num_sides < 3 { 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(), "Polygon must have at least 3 sides".to_string(),
vec![args.source_range], vec![args.source_range],
))); )));
} }
if radius.n <= 0.0 { 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(), "Radius must be greater than 0".to_string(),
vec![args.source_range], vec![args.source_range],
))); )));
@ -407,11 +407,11 @@ pub(crate) fn get_radius(
match (radius, diameter) { match (radius, diameter) {
(Some(radius), None) => Ok(radius), (Some(radius), None) => Ok(radius),
(None, Some(diameter)) => Ok(TyF64::new(diameter.n / 2.0, diameter.ty)), (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(), "This function needs either `diameter` or `radius`".to_string(),
vec![source_range], 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(), "You cannot specify both `diameter` and `radius`, please remove one".to_string(),
vec![source_range], vec![source_range],
))), ))),

View File

@ -36,14 +36,14 @@ async fn inner_shell(
args: Args, args: Args,
) -> Result<Vec<Solid>, KclError> { ) -> Result<Vec<Solid>, KclError> {
if faces.is_empty() { 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(), "You must shell at least one face".to_owned(),
vec![args.source_range], vec![args.source_range],
))); )));
} }
if solids.is_empty() { 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(), "You must shell at least one solid".to_owned(),
vec![args.source_range], vec![args.source_range],
))); )));
@ -63,7 +63,7 @@ async fn inner_shell(
} }
if face_ids.is_empty() { 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(), "Expected at least one valid face".to_owned(),
vec![args.source_range], 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 // Make sure all the solids have the same id, as we are going to shell them all at
// once. // once.
if !solids.iter().all(|eg| eg.id == solids[0].id) { 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(), "All solids stem from the same root object, like multiple sketch on face extrusions, etc.".to_owned(),
vec![args.source_range], vec![args.source_range],
))); )));

View File

@ -65,13 +65,13 @@ impl FaceTag {
match self { match self {
FaceTag::Tag(ref t) => args.get_adjacent_face_to_tag(exec_state, t, must_be_planar).await, 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(|| { 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(), "Expected a start face".to_string(),
vec![args.source_range], vec![args.source_range],
)) ))
}), }),
FaceTag::StartOrEnd(StartOrEnd::End) => solid.end_cap_id.ok_or_else(|| { 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(), "Expected an end face".to_string(),
vec![args.source_range], vec![args.source_range],
)) ))
@ -328,7 +328,7 @@ async fn straight_line(
let from = sketch.current_pen_position()?; let from = sketch.current_pen_position()?;
let (point, is_absolute) = match (end_absolute, end) { let (point, is_absolute) = match (end_absolute, end) {
(Some(_), Some(_)) => { (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(), "You cannot give both `end` and `endAbsolute` params, you have to choose one or the other".to_owned(),
vec![args.source_range], vec![args.source_range],
))); )));
@ -336,7 +336,7 @@ async fn straight_line(
(Some(end_absolute), None) => (end_absolute, true), (Some(end_absolute), None) => (end_absolute, true),
(None, Some(end)) => (end, false), (None, Some(end)) => (end, false),
(None, None) => { (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"), format!("You must supply either `{relative_name}` or `endAbsolute` arguments"),
vec![args.source_range], vec![args.source_range],
))); )));
@ -603,7 +603,7 @@ async fn inner_angled_line(
.filter(|x| x.is_some()) .filter(|x| x.is_some())
.count(); .count();
if options_given > 1 { 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(), " one of `length`, `lengthX`, `lengthY`, `endAbsoluteX`, `endAbsoluteY` can be given".to_string(),
vec![args.source_range], vec![args.source_range],
))); )));
@ -631,11 +631,11 @@ async fn inner_angled_line(
(None, None, None, None, Some(end_absolute_y)) => { (None, None, None, None, Some(end_absolute_y)) => {
inner_angled_line_to_y(angle_degrees, end_absolute_y, sketch, tag, exec_state, args).await 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(), "One of `length`, `lengthX`, `lengthY`, `endAbsoluteX`, `endAbsoluteY` must be given".to_string(),
vec![args.source_range], 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(), "Only One of `length`, `lengthX`, `lengthY`, `endAbsoluteX`, `endAbsoluteY` can be given".to_owned(),
vec![args.source_range], vec![args.source_range],
))), ))),
@ -709,14 +709,14 @@ async fn inner_angled_line_of_x_length(
args: Args, args: Args,
) -> Result<Sketch, KclError> { ) -> Result<Sketch, KclError> {
if angle_degrees.abs() == 270.0 { 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(), "Cannot have an x constrained angle of 270 degrees".to_string(),
vec![args.source_range], vec![args.source_range],
))); )));
} }
if angle_degrees.abs() == 90.0 { 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(), "Cannot have an x constrained angle of 90 degrees".to_string(),
vec![args.source_range], vec![args.source_range],
))); )));
@ -741,14 +741,14 @@ async fn inner_angled_line_to_x(
let from = sketch.current_pen_position()?; let from = sketch.current_pen_position()?;
if angle_degrees.abs() == 270.0 { 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(), "Cannot have an x constrained angle of 270 degrees".to_string(),
vec![args.source_range], vec![args.source_range],
))); )));
} }
if angle_degrees.abs() == 90.0 { 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(), "Cannot have an x constrained angle of 90 degrees".to_string(),
vec![args.source_range], vec![args.source_range],
))); )));
@ -776,14 +776,14 @@ async fn inner_angled_line_of_y_length(
args: Args, args: Args,
) -> Result<Sketch, KclError> { ) -> Result<Sketch, KclError> {
if angle_degrees.abs() == 0.0 { 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(), "Cannot have a y constrained angle of 0 degrees".to_string(),
vec![args.source_range], vec![args.source_range],
))); )));
} }
if angle_degrees.abs() == 180.0 { 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(), "Cannot have a y constrained angle of 180 degrees".to_string(),
vec![args.source_range], vec![args.source_range],
))); )));
@ -808,14 +808,14 @@ async fn inner_angled_line_to_y(
let from = sketch.current_pen_position()?; let from = sketch.current_pen_position()?;
if angle_degrees.abs() == 0.0 { 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(), "Cannot have a y constrained angle of 0 degrees".to_string(),
vec![args.source_range], vec![args.source_range],
))); )));
} }
if angle_degrees.abs() == 180.0 { 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(), "Cannot have a y constrained angle of 180 degrees".to_string(),
vec![args.source_range], vec![args.source_range],
))); )));
@ -892,7 +892,7 @@ pub async fn inner_angled_line_that_intersects(
) -> Result<Sketch, KclError> { ) -> Result<Sketch, KclError> {
let intersect_path = args.get_tag_engine_info(exec_state, &intersect_tag)?; let intersect_path = args.get_tag_engine_info(exec_state, &intersect_tag)?;
let path = intersect_path.path.clone().ok_or_else(|| { 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), format!("Expected an intersect path with a path, found `{:?}`", intersect_path),
vec![args.source_range], vec![args.source_range],
)) ))
@ -1169,7 +1169,7 @@ async fn inner_start_sketch_on(
SketchData::Plane(plane) => { SketchData::Plane(plane) => {
if plane.value == crate::exec::PlaneType::Uninit { if plane.value == crate::exec::PlaneType::Uninit {
if plane.info.origin.units == UnitLen::Unknown { 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(), "Origin of plane has unknown units".to_string(),
vec![args.source_range], vec![args.source_range],
))); )));
@ -1193,7 +1193,7 @@ async fn inner_start_sketch_on(
} }
SketchData::Solid(solid) => { SketchData::Solid(solid) => {
let Some(tag) = face else { 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(), "Expected a tag for the face to sketch on".to_string(),
vec![args.source_range], 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 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(), "Invalid combination of arguments. Either provide (angleStart, angleEnd, radius) or (endAbsolute, interiorAbsolute)".to_owned(),
vec![args.source_range], vec![args.source_range],
))) )))
@ -1804,7 +1804,7 @@ pub async fn relative_arc(
let radius = radius.to_length_units(from.units); let radius = radius.to_length_units(from.units);
let (center, end) = arc_center_and_end(from.ignore_units(), a_start, a_end, radius); let (center, end) = arc_center_and_end(from.ignore_units(), a_start, a_end, radius);
if a_start == a_end { 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(), "Arc start and end angles must be different".to_string(),
vec![args.source_range], vec![args.source_range],
))); )));
@ -1972,11 +1972,11 @@ async fn inner_tangential_arc(
let data = TangentialArcData::RadiusAndOffset { radius, offset: angle }; let data = TangentialArcData::RadiusAndOffset { radius, offset: angle };
inner_tangential_arc_radius_angle(data, sketch, tag, exec_state, args).await 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(), "You cannot give both `end` and `endAbsolute` params, you have to choose one or the other".to_owned(),
vec![args.source_range], 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(), "You must supply `end`, `endAbsolute`, or both `angle` and `radius`/`diameter` arguments".to_owned(),
vec![args.source_range], vec![args.source_range],
))), ))),
@ -2130,13 +2130,13 @@ async fn inner_tangential_arc_to_point(
}); });
if result.center[0].is_infinite() { 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" "could not sketch tangential arc, because its center would be infinitely far away in the X direction"
.to_owned(), .to_owned(),
vec![args.source_range], vec![args.source_range],
))); )));
} else if result.center[1].is_infinite() { } 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" "could not sketch tangential arc, because its center would be infinitely far away in the Y direction"
.to_owned(), .to_owned(),
vec![args.source_range], vec![args.source_range],
@ -2314,7 +2314,7 @@ async fn inner_bezier_curve(
to 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(), "You must either give `control1`, `control2` and `end`, or `control1Absolute`, `control2Absolute` and `endAbsolute`.".to_owned(),
vec![args.source_range], vec![args.source_range],
))); )));

View File

@ -75,7 +75,7 @@ async fn inner_sweep(
Some("sketchPlane") => RelativeTo::SketchPlane, Some("sketchPlane") => RelativeTo::SketchPlane,
Some("trajectoryCurve") | None => RelativeTo::TrajectoryCurve, Some("trajectoryCurve") | None => RelativeTo::TrajectoryCurve,
Some(_) => { 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(), "If you provide relativeTo, it must either be 'sketchPlane' or 'trajectoryCurve'".to_owned(),
vec![args.source_range], vec![args.source_range],
))) )))

View File

@ -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. // Ensure at least one scale value is provided.
if scale_x.is_none() && scale_y.is_none() && scale_z.is_none() { 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(), "Expected `x`, `y`, or `z` to be provided.".to_string(),
vec![args.source_range], 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. // Ensure at least one translation value is provided.
if translate_x.is_none() && translate_y.is_none() && translate_z.is_none() { 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(), "Expected `x`, `y`, or `z` to be provided.".to_string(),
vec![args.source_range], 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. // Check if no rotation values are provided.
if roll.is_none() && pitch.is_none() && yaw.is_none() && axis.is_none() && angle.is_none() { 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(), "Expected `roll`, `pitch`, and `yaw` or `axis` and `angle` to be provided.".to_string(),
vec![args.source_range], 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() { if roll.is_some() || pitch.is_some() || yaw.is_some() {
// Ensure they didn't also provide an axis or angle. // Ensure they didn't also provide an axis or angle.
if axis.is_some() || angle.is_some() { 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." "Expected `axis` and `angle` to not be provided when `roll`, `pitch`, and `yaw` are provided."
.to_owned(), .to_owned(),
vec![args.source_range], 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 they give us an axis or angle, they must give us both.
if axis.is_some() || angle.is_some() { if axis.is_some() || angle.is_some() {
if axis.is_none() { 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(), "Expected `axis` to be provided when `angle` is provided.".to_string(),
vec![args.source_range], vec![args.source_range],
))); )));
} }
if angle.is_none() { 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(), "Expected `angle` to be provided when `axis` is provided.".to_string(),
vec![args.source_range], 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. // Ensure they didn't also provide a roll, pitch, or yaw.
if roll.is_some() || pitch.is_some() || yaw.is_some() { 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." "Expected `roll`, `pitch`, and `yaw` to not be provided when `axis` and `angle` are provided."
.to_owned(), .to_owned(),
vec![args.source_range], 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. // Validate the roll, pitch, and yaw values.
if let Some(roll) = &roll { if let Some(roll) = &roll {
if !(-360.0..=360.0).contains(&roll.n) { 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), format!("Expected roll to be between -360 and 360, found `{}`", roll.n),
vec![args.source_range], 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 let Some(pitch) = &pitch {
if !(-360.0..=360.0).contains(&pitch.n) { 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), format!("Expected pitch to be between -360 and 360, found `{}`", pitch.n),
vec![args.source_range], 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 let Some(yaw) = &yaw {
if !(-360.0..=360.0).contains(&yaw.n) { 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), format!("Expected yaw to be between -360 and 360, found `{}`", yaw.n),
vec![args.source_range], 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. // Validate the axis and angle values.
if let Some(angle) = &angle { if let Some(angle) = &angle {
if !(-360.0..=360.0).contains(&angle.n) { 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), format!("Expected angle to be between -360 and 360, found `{}`", angle.n),
vec![args.source_range], vec![args.source_range],
))); )));

View File

@ -93,7 +93,7 @@ async fn do_execute_and_snapshot(
for e in exec_state.errors() { for e in exec_state.errors() {
if e.severity.is_err() { if e.severity.is_err() {
return Err(ExecErrorWithState::new( 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(), exec_state.clone(),
)); ));
} }
@ -164,7 +164,7 @@ pub async fn execute_and_export_step(
for e in exec_state.errors() { for e in exec_state.errors() {
if e.severity.is_err() { if e.severity.is_err() {
return Err(ExecErrorWithState::new( 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(), exec_state.clone(),
)); ));
} }

View File

@ -883,7 +883,7 @@ pub async fn walk_dir(dir: &std::path::PathBuf) -> Result<Vec<std::path::PathBuf
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
pub async fn recast_dir(dir: &std::path::Path, options: &crate::FormatOptions) -> Result<(), anyhow::Error> { 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| { 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), format!("Failed to walk directory `{}`: {:?}", dir.display(), err),
vec![crate::SourceRange::default()], 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 { if ce.severity != crate::errors::Severity::Warning {
let report = crate::Report { let report = crate::Report {
kcl_source: contents.to_string(), 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(), filename: file.to_string_lossy().to_string(),
}; };
let report = miette::Report::new(report); let report = miette::Report::new(report);

View File

@ -96,7 +96,7 @@ fn topsort(all_modules: &[&str], graph: Graph) -> Result<Vec<Vec<String>>, KclEr
if stage_modules.is_empty() { if stage_modules.is_empty() {
waiting_modules.sort(); 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(", ")), 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 // TODO: we can get the right import lines from the AST, but we don't
vec![SourceRange::default()], vec![SourceRange::default()],
@ -146,7 +146,7 @@ pub(crate) fn import_dependencies(
// This is a bit of a hack, but it works for now. // This is a bit of a hack, but it works for now.
ret.lock() ret.lock()
.map_err(|err| { .map_err(|err| {
KclError::Internal(KclErrorDetails::new( KclError::new_internal(KclErrorDetails::new(
format!("Failed to lock mutex: {}", err), format!("Failed to lock mutex: {}", err),
Default::default(), Default::default(),
)) ))
@ -156,7 +156,7 @@ pub(crate) fn import_dependencies(
ImportPath::Foreign { path } => { ImportPath::Foreign { path } => {
ret.lock() ret.lock()
.map_err(|err| { .map_err(|err| {
KclError::Internal(KclErrorDetails::new( KclError::new_internal(KclErrorDetails::new(
format!("Failed to lock mutex: {}", err), format!("Failed to lock mutex: {}", err),
Default::default(), Default::default(),
)) ))
@ -178,7 +178,7 @@ pub(crate) fn import_dependencies(
walk(ret.clone(), prog.into(), path, ctx)?; walk(ret.clone(), prog.into(), path, ctx)?;
let ret = ret.lock().map_err(|err| { let ret = ret.lock().map_err(|err| {
KclError::Internal(KclErrorDetails::new( KclError::new_internal(KclErrorDetails::new(
format!("Failed to lock mutex: {}", err), format!("Failed to lock mutex: {}", err),
Default::default(), Default::default(),
)) ))
@ -223,7 +223,7 @@ pub(crate) async fn import_universe(
let repr = { let repr = {
let Some(module_info) = exec_state.get_module(module_id) else { 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), format!("Module {} not found", module_id),
vec![import_stmt.into()], vec![import_stmt.into()],
))); )));

View File

@ -159,20 +159,20 @@ export function defaultSourceRange(): SourceRange {
} }
function bestSourceRange(error: RustKclError): SourceRange { function bestSourceRange(error: RustKclError): SourceRange {
if (error.sourceRanges.length === 0) { if (error.details.sourceRanges.length === 0) {
return defaultSourceRange() return defaultSourceRange()
} }
// When there's an error, the call stack is unwound, and the locations are // 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. // 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. // Skip ranges pointing into files that aren't the top-level module.
if (isTopLevelModule(range)) { if (isTopLevelModule(range)) {
return sourceRangeFromRust(range) return sourceRangeFromRust(range)
} }
} }
// We didn't find a top-level module range, so just use the first one. // 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 = ( const splitErrors = (
@ -241,7 +241,7 @@ export const parse = (code: string | Error): ParseResult | Error => {
const parsed: RustKclError = JSON.parse(e.toString()) const parsed: RustKclError = JSON.parse(e.toString())
return new KCLError( return new KCLError(
parsed.kind, parsed.kind,
parsed.msg, parsed.details.msg,
bestSourceRange(parsed), bestSourceRange(parsed),
[], [],
[], [],
@ -392,9 +392,9 @@ export const errFromErrWithOutputs = (e: any): KCLError => {
const parsed: KclErrorWithOutputs = JSON.parse(e.toString()) const parsed: KclErrorWithOutputs = JSON.parse(e.toString())
return new KCLError( return new KCLError(
parsed.error.kind, parsed.error.kind,
parsed.error.msg, parsed.error.details.msg,
bestSourceRange(parsed.error), bestSourceRange(parsed.error),
parsed.error.backtrace, parsed.error.details.backtrace,
parsed.nonFatal, parsed.nonFatal,
parsed.operations, parsed.operations,
parsed.artifactCommands, parsed.artifactCommands,

View File

@ -141,7 +141,7 @@ export default class RustContext {
) )
} catch (e: any) { } catch (e: any) {
const parsed: RustKclError = JSON.parse(e.toString()) const parsed: RustKclError = JSON.parse(e.toString())
toast.error(parsed.msg, { id: toastId }) toast.error(parsed.details.msg, { id: toastId })
return return
} }
} }