Skip to content

Commit b69f8cd

Browse files
committed
wip
1 parent 86b20b9 commit b69f8cd

File tree

15 files changed

+1671
-131
lines changed

15 files changed

+1671
-131
lines changed

module/move/unilang/roadmap.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,19 +30,19 @@ The project has successfully completed its foundational phases (1-3), culminatin
3030
* **Goal:** To implement the mandatory performance NFR for a zero-overhead static command system, enabling utilities with thousands of commands to start instantly.
3131
* **Outcome:** A framework with a hybrid command registry where all compile-time commands are stored in a Perfect Hash Function (PHF), eliminating runtime registration costs and ensuring sub-millisecond command resolution.
3232

33-
* [] **M4.1: registry_design_hybrid_architecture:**
33+
* [] **M4.1: registry_design_hybrid_architecture:**
3434
* **Spec Reference:** FR-PERF-1, NFR-Performance
3535
* **Deliverable:** A detailed task plan for implementing a zero-overhead static command registry.
3636
* **Description:** Design a build-time mechanism (using `build.rs` and the `phf` crate) to generate a Perfect Hash Function (PHF) map from a command manifest. This plan will outline the steps to refactor the `CommandRegistry` into a hybrid model.
37-
* [] **M4.2: phf_implement_build_time_generation:**
37+
* [] **M4.2: phf_implement_build_time_generation:**
3838
* **Prerequisites:** M4.1
3939
* **Deliverable:** A `build.rs` script that generates a `.rs` file containing the static PHF map from `unilang.commands.yaml`.
4040
* **Description:** Implement the build script that parses the YAML manifest and uses `phf_codegen` to construct the perfect hash map.
41-
* [] **M4.3: registry_refactor_to_hybrid_model:**
41+
* [] **M4.3: registry_refactor_to_hybrid_model:**
4242
* **Prerequisites:** M4.2
4343
* **Deliverable:** An updated `CommandRegistry` that uses the generated PHF for static commands and a `HashMap` for dynamic commands.
4444
* **Description:** Refactor all lookup methods to query the static PHF first before falling back to the dynamic `HashMap`.
45-
* [] **M4.4: test_implement_performance_stress_harness:**
45+
* [] **M4.4: test_implement_performance_stress_harness:**
4646
* **Prerequisites:** M4.3
4747
* **Spec Reference:** FR-PERF-1
4848
* **Deliverable:** A new integration test that generates a large YAML manifest (1000+ commands) and a test binary that proves the performance NFRs are met.
@@ -52,15 +52,15 @@ The project has successfully completed its foundational phases (1-3), culminatin
5252
* **Goal:** To implement the remaining mandatory functional requirements from Spec v2.2.0, ensuring the framework fully supports REPL, interactive CLI, and WebAssembly (WASM) modalities.
5353
* **Outcome:** A functionally complete and validated API for building sophisticated, user-friendly command-line applications that can run in native and web environments.
5454

55-
* [] **M5.1: pipeline_refactor_for_reusability:**
55+
* [] **M5.1: pipeline_refactor_for_reusability:**
5656
* **Spec Reference:** FR-REPL-1
5757
* **Deliverable:** An audited and confirmed stateless core pipeline and a new example file (`repl_example.rs`).
5858
* **Description:** Audit the core pipeline components (`Parser`, `SemanticAnalyzer`, `Interpreter`) to ensure they are stateless and can be reused in a REPL loop.
59-
* [] **M5.2: argument_implement_interactive_signaling:**
59+
* [] **M5.2: argument_implement_interactive_signaling:**
6060
* **Spec Reference:** FR-INTERACTIVE-1
6161
* **Deliverable:** The `SemanticAnalyzer` correctly returns the `UNILANG_ARGUMENT_INTERACTIVE_REQUIRED` error for missing interactive arguments.
6262
* **Description:** Modify the `bind_arguments` logic to check for the `interactive: true` attribute on missing mandatory arguments and return the specific error code.
63-
* [] **M5.3: test_create_interactive_prompting_verification:**
63+
* [] **M5.3: test_create_interactive_prompting_verification:**
6464
* **Prerequisites:** M5.2
6565
* **Deliverable:** A new unit test for the `SemanticAnalyzer` and an updated CLI binary demonstrating how to catch the interactive signal.
6666
* [] **M5.4: example_create_wasm_repl:**

module/move/unilang/src/error.rs

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,165 @@ mod private
5555
Error::Execution( error )
5656
}
5757
}
58+
59+
#[cfg(test)]
60+
mod tests
61+
{
62+
use super::*;
63+
use crate::data::ErrorData;
64+
65+
#[test]
66+
fn test_error_execution_display()
67+
{
68+
let error_data = ErrorData::new(
69+
"TEST_ERROR".to_string(),
70+
"This is a test error message".to_string(),
71+
);
72+
let error = Error::Execution(error_data);
73+
74+
let error_string = error.to_string();
75+
assert!(error_string.contains("Execution Error"));
76+
assert!(error_string.contains("This is a test error message"));
77+
}
78+
79+
#[test]
80+
fn test_error_registration_display()
81+
{
82+
let error = Error::Registration("Failed to register command".to_string());
83+
let error_string = error.to_string();
84+
assert!(error_string.contains("Registration Error"));
85+
assert!(error_string.contains("Failed to register command"));
86+
}
87+
88+
#[test]
89+
fn test_error_yaml_display()
90+
{
91+
let yaml_error = serde_yaml::from_str::<serde_yaml::Value>("invalid: yaml: {").unwrap_err();
92+
let error = Error::Yaml(yaml_error);
93+
let error_string = error.to_string();
94+
assert!(error_string.contains("YAML Deserialization Error"));
95+
}
96+
97+
#[test]
98+
fn test_error_json_display()
99+
{
100+
let json_error = serde_json::from_str::<serde_json::Value>("{invalid json").unwrap_err();
101+
let error = Error::Json(json_error);
102+
let error_string = error.to_string();
103+
assert!(error_string.contains("JSON Deserialization Error"));
104+
}
105+
106+
#[test]
107+
fn test_error_parse_display()
108+
{
109+
let parse_error = unilang_parser::error::ParseError::new(
110+
unilang_parser::error::ErrorKind::Syntax("test parse error".to_string()),
111+
unilang_parser::SourceLocation::StrSpan { start: 0, end: 5 }
112+
);
113+
let error = Error::Parse(parse_error);
114+
let error_string = error.to_string();
115+
assert!(error_string.contains("Parse Error"));
116+
assert!(error_string.contains("test parse error"));
117+
}
118+
119+
#[test]
120+
fn test_type_error_conversion()
121+
{
122+
let type_error = crate::types::TypeError {
123+
expected_kind: crate::data::Kind::Integer,
124+
reason: "Invalid integer format".to_string(),
125+
};
126+
127+
let error: Error = type_error.into();
128+
129+
if let Error::Execution(error_data) = error {
130+
assert_eq!(error_data.code, "UNILANG_TYPE_MISMATCH");
131+
assert!(error_data.message.contains("Type Error: Invalid integer format"));
132+
assert!(error_data.message.contains("Please provide a valid value for this type"));
133+
} else {
134+
panic!("Expected Execution error");
135+
}
136+
}
137+
138+
#[test]
139+
fn test_error_data_conversion()
140+
{
141+
let error_data = ErrorData::new(
142+
"CUSTOM_ERROR".to_string(),
143+
"Custom error message".to_string(),
144+
);
145+
146+
let error: Error = error_data.into();
147+
148+
if let Error::Execution(data) = error {
149+
assert_eq!(data.code, "CUSTOM_ERROR");
150+
assert_eq!(data.message, "Custom error message");
151+
} else {
152+
panic!("Expected Execution error");
153+
}
154+
}
155+
156+
#[test]
157+
fn test_yaml_error_from_conversion()
158+
{
159+
let yaml_error = serde_yaml::from_str::<serde_yaml::Value>("invalid: yaml: content: {").unwrap_err();
160+
let error: Error = yaml_error.into();
161+
162+
assert!(matches!(error, Error::Yaml(_)));
163+
}
164+
165+
#[test]
166+
fn test_json_error_from_conversion()
167+
{
168+
let json_error = serde_json::from_str::<serde_json::Value>("{malformed json").unwrap_err();
169+
let error: Error = json_error.into();
170+
171+
assert!(matches!(error, Error::Json(_)));
172+
}
173+
174+
#[test]
175+
fn test_parse_error_from_conversion()
176+
{
177+
let parse_error = unilang_parser::error::ParseError::new(
178+
unilang_parser::error::ErrorKind::Syntax("parsing failed".to_string()),
179+
unilang_parser::SourceLocation::StrSpan { start: 0, end: 3 }
180+
);
181+
let error: Error = parse_error.into();
182+
183+
assert!(matches!(error, Error::Parse(_)));
184+
}
185+
186+
#[test]
187+
fn test_error_debug_format()
188+
{
189+
let error_data = ErrorData::new(
190+
"DEBUG_ERROR".to_string(),
191+
"Debug error message".to_string(),
192+
);
193+
let error = Error::Execution(error_data);
194+
195+
let debug_string = format!("{:?}", error);
196+
assert!(debug_string.contains("Execution"));
197+
assert!(debug_string.contains("DEBUG_ERROR"));
198+
}
199+
200+
#[test]
201+
fn test_multiple_error_types()
202+
{
203+
let execution_error = Error::Execution(ErrorData::new(
204+
"EXEC_ERROR".to_string(),
205+
"Execution failed".to_string(),
206+
));
207+
208+
let registration_error = Error::Registration("Registration failed".to_string());
209+
210+
// Test that different error types display differently
211+
assert!(execution_error.to_string().contains("Execution Error"));
212+
assert!(registration_error.to_string().contains("Registration Error"));
213+
assert!(!execution_error.to_string().contains("Registration"));
214+
assert!(!registration_error.to_string().contains("Execution"));
215+
}
216+
}
58217
}
59218

60219
mod_interface::mod_interface!

0 commit comments

Comments
 (0)