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