1+ //! # Error Handling and Type Validation
2+ //!
3+ //! This example demonstrates comprehensive error handling scenarios,
4+ //! type validation, and error recovery patterns in Unilang applications.
5+
6+ use unilang:: data:: { ArgumentAttributes , ArgumentDefinition , CommandDefinition , Kind , OutputData , ValidationRule } ;
7+ use unilang:: registry:: CommandRegistry ;
8+ use unilang:: semantic:: SemanticAnalyzer ;
9+ use unilang:: error:: Error ;
10+ use unilang:: help:: HelpGenerator ;
11+ use unilang_parser:: Parser ;
12+
13+ fn main ( ) -> Result < ( ) , Box < dyn std:: error:: Error > >
14+ {
15+ println ! ( "=== Error Handling and Type Validation Demo ===\n " ) ;
16+
17+ let mut registry = CommandRegistry :: new ( ) ;
18+
19+ // Step 1: Command with strict validation rules
20+ let validate_cmd = CommandDefinition :: former ( )
21+ . name ( "validate" )
22+ . namespace ( ".test" )
23+ . description ( "Tests various validation scenarios and error handling" . to_string ( ) )
24+ . hint ( "Validation testing command" )
25+ . status ( "experimental" )
26+ . version ( "1.0.0" )
27+ . aliases ( vec ! [ ] )
28+ . tags ( vec ! [ "validation" . to_string( ) , "testing" . to_string( ) ] )
29+ . permissions ( vec ! [ ] )
30+ . idempotent ( true )
31+ . deprecation_message ( String :: new ( ) )
32+ . http_method_hint ( "POST" . to_string ( ) )
33+ . examples ( vec !
34+ [
35+ "test.validate age::25 email::[email protected] " . to_string
( ) , 36+ "validate age::30 score::95.5 level::advanced" . to_string( )
37+ ] )
38+ . arguments ( vec !
39+ [
40+ // Integer with range validation
41+ ArgumentDefinition {
42+ name: "age" . to_string( ) ,
43+ description: "Age in years (18-120)" . to_string( ) ,
44+ kind: Kind :: Integer ,
45+ hint: "Must be between 18 and 120" . to_string( ) ,
46+ attributes: ArgumentAttributes { optional: false , ..Default :: default ( ) } ,
47+ validation_rules: vec![ ValidationRule :: Min ( 18.0 ) , ValidationRule :: Max ( 120.0 ) ] ,
48+ aliases: vec![ "a" . to_string( ) ] ,
49+ tags: vec![ "required" . to_string( ) ] ,
50+ } ,
51+
52+ // String with pattern validation
53+ ArgumentDefinition {
54+ name: "email" . to_string( ) ,
55+ description: "Valid email address" . to_string( ) ,
56+ kind: Kind :: String ,
57+ hint: "Standard email format" . to_string( ) ,
58+ attributes: ArgumentAttributes { optional: false , ..Default :: default ( ) } ,
59+ validation_rules: vec![ ValidationRule :: Pattern ( r"^[^\s@]+@[^\s@]+\.[^\s@]+$" . to_string( ) ) ] ,
60+ aliases: vec![ "e" . to_string( ) ] ,
61+ tags: vec![ "required" . to_string( ) ] ,
62+ } ,
63+
64+ // Float with precision validation
65+ ArgumentDefinition {
66+ name: "score" . to_string( ) ,
67+ description: "Score percentage (0.0-100.0)" . to_string( ) ,
68+ kind: Kind :: Float ,
69+ hint: "Decimal percentage value" . to_string( ) ,
70+ attributes: ArgumentAttributes { optional: true , default : Some ( "0.0" . to_string( ) ) , ..Default :: default ( ) } ,
71+ validation_rules: vec![ ValidationRule :: Min ( 0.0 ) , ValidationRule :: Max ( 100.0 ) ] ,
72+ aliases: vec![ "s" . to_string( ) ] ,
73+ tags: vec![ "optional" . to_string( ) ] ,
74+ } ,
75+
76+ // Enum with restricted choices
77+ ArgumentDefinition {
78+ name: "level" . to_string( ) ,
79+ description: "Skill level selection" . to_string( ) ,
80+ kind: Kind :: Enum ( vec![ "beginner" . to_string( ) , "intermediate" . to_string( ) , "advanced" . to_string( ) , "expert" . to_string( ) ] ) ,
81+ hint: "Choose from predefined levels" . to_string( ) ,
82+ attributes: ArgumentAttributes { optional: true , default : Some ( "beginner" . to_string( ) ) , ..Default :: default ( ) } ,
83+ validation_rules: vec![ ] ,
84+ aliases: vec![ "l" . to_string( ) ] ,
85+ tags: vec![ "choice" . to_string( ) ] ,
86+ } ,
87+
88+ // Interactive argument that triggers special error
89+ ArgumentDefinition {
90+ name: "password" . to_string( ) ,
91+ description: "User password (interactive input required)" . to_string( ) ,
92+ kind: Kind :: String ,
93+ hint: "Secure password" . to_string( ) ,
94+ attributes: ArgumentAttributes {
95+ optional: true ,
96+ interactive: true ,
97+ sensitive: true ,
98+ ..Default :: default ( )
99+ } ,
100+ validation_rules: vec![ ValidationRule :: MinLength ( 8 ) ] ,
101+ aliases: vec![ "p" . to_string( ) ] ,
102+ tags: vec![ "security" . to_string( ) ] ,
103+ } ,
104+ ] )
105+ . end ( ) ;
106+
107+ let validate_routine = Box :: new ( | cmd : unilang:: semantic:: VerifiedCommand , _ctx |
108+ {
109+ println ! ( "✓ Validation passed for all arguments!" ) ;
110+ println ! ( "Processed {} arguments successfully" , cmd. arguments. len( ) ) ;
111+
112+ for ( name, value ) in & cmd. arguments
113+ {
114+ println ! ( " ✓ {name}: {value}" ) ;
115+ }
116+
117+ Ok ( OutputData
118+ {
119+ content : "All validations passed successfully" . to_string ( ) ,
120+ format : "text" . to_string ( ) ,
121+ } )
122+ } ) ;
123+
124+ registry. command_add_runtime ( & validate_cmd, validate_routine ) ?;
125+ println ! ( "✓ Registered validation test command" ) ;
126+
127+ println ! ( "\n === Error Scenarios Demonstration ===\n " ) ;
128+
129+ let options = unilang_parser:: UnilangParserOptions :: default ( ) ;
130+ let parser = Parser :: new ( options ) ;
131+ let help_generator = HelpGenerator :: new ( & registry ) ;
132+
133+ // Test cases with different error types
134+ let test_cases = vec ! [
135+ // 1. Type conversion errors
136+ ( "test.validate age::not_a_number email::[email protected] " , "Invalid integer conversion" ) , 137+ ( "test.validate age::25 email::[email protected] score::invalid_float" , "Invalid float conversion" ) , 138+ ( "test.validate age::25 email::[email protected] level::invalid_choice" , "Enum choice validation" ) , 139+
140+ // 2. Range validation errors
141+ ( "test.validate age::15 email::[email protected] " , "Age below minimum (18)" ) , 142+ ( "test.validate age::150 email::[email protected] " , "Age above maximum (120)" ) , 143+ ( "test.validate age::25 email::[email protected] score::-5.0" , "Score below minimum (0.0)" ) , 144+ ( "test.validate age::25 email::[email protected] score::150.0" , "Score above maximum (100.0)" ) , 145+
146+ // 3. Pattern validation errors
147+ ( "test.validate age::25 email::invalid_email" , "Email pattern validation" ) ,
148+ ( "test.validate age::25 email::@invalid.com" , "Email format validation" ) ,
149+
150+ // 4. Missing required arguments
151+ ( "test.validate email::[email protected] " , "Missing required age argument" ) , 152+ ( "test.validate age::25" , "Missing required email argument" ) ,
153+
154+ // 5. Interactive argument signaling
155+ ( "test.validate age::25 email::[email protected] password::secret123" , "Interactive argument error" ) , 156+
157+ // 6. Command not found
158+ ( "nonexistent.command arg::value" , "Command not found" ) ,
159+
160+ // 7. Parsing errors
161+ ( "test.validate age::25 email::[email protected] invalid::syntax::" , "Parsing error" ) , 162+ ] ;
163+
164+ for ( input, expected_error ) in test_cases
165+ {
166+ println ! ( "🧪 Testing: {input}" ) ;
167+ println ! ( " Expected: {expected_error}" ) ;
168+
169+ match parser. parse ( input )
170+ {
171+ Ok ( instructions ) =>
172+ {
173+ let analyzer = SemanticAnalyzer :: new ( & instructions, & registry ) ;
174+ match analyzer. analyze ( )
175+ {
176+ Ok ( _verified_commands ) =>
177+ {
178+ println ! ( " ❌ Unexpectedly succeeded (should have failed)" ) ;
179+ } ,
180+ Err ( error ) =>
181+ {
182+ println ! ( " ✓ Caught error: {}" , format_error( & error ) ) ;
183+ }
184+ }
185+ } ,
186+ Err ( parse_error ) =>
187+ {
188+ println ! ( " ✓ Parse error: {parse_error}" ) ;
189+ }
190+ }
191+ println ! ( ) ;
192+ }
193+
194+ println ! ( "=== Error Type Classification ===" ) ;
195+ println ! ( "• Parse Errors - Syntax issues in command string" ) ;
196+ println ! ( "• Type Errors - Invalid type conversions (UNILANG_TYPE_MISMATCH)" ) ;
197+ println ! ( "• Validation Errors - Failed validation rules" ) ;
198+ println ! ( "• Missing Argument Errors - Required arguments not provided" ) ;
199+ println ! ( "• Interactive Argument Errors - UNILANG_ARGUMENT_INTERACTIVE_REQUIRED" ) ;
200+ println ! ( "• Command Not Found - Unknown command or namespace" ) ;
201+ println ! ( "• Registration Errors - Runtime command registration issues" ) ;
202+
203+ println ! ( "\n === Error Recovery Patterns ===\n " ) ;
204+
205+ // Demonstrate error recovery with fallback commands
206+ println ! ( "🔄 Error Recovery Example:" ) ;
207+ let problematic_input =
"test.validate age::invalid email::[email protected] " ; 208+
209+ match parser. parse ( problematic_input )
210+ {
211+ Ok ( instructions ) =>
212+ {
213+ let analyzer = SemanticAnalyzer :: new ( & instructions, & registry ) ;
214+ match analyzer. analyze ( )
215+ {
216+ Ok ( _verified ) => println ! ( " ✓ Command executed successfully" ) ,
217+ Err ( error ) =>
218+ {
219+ println ! ( " ❌ Command failed: {}" , format_error( & error ) ) ;
220+ println ! ( " 💡 Recovery suggestion:" ) ;
221+
222+ if let Some ( help ) = help_generator. command ( "test.validate" )
223+ {
224+ println ! ( " 📖 Command help:\n {help}" ) ;
225+ }
226+
227+ println ! ( " 🔧 Corrected command:" ) ;
228+ println ! ( " test.validate age::25 email::[email protected] " ) ; 229+ }
230+ }
231+ } ,
232+ Err ( parse_error ) =>
233+ {
234+ println ! ( " ❌ Parse failed: {parse_error}" ) ;
235+ }
236+ }
237+
238+ println ! ( "\n === Best Practices for Error Handling ===\n " ) ;
239+ println ! ( "✨ Error Handling Guidelines:" ) ;
240+ println ! ( " • Always check command syntax before execution" ) ;
241+ println ! ( " • Provide clear, actionable error messages" ) ;
242+ println ! ( " • Use validation rules to prevent invalid input" ) ;
243+ println ! ( " • Handle interactive arguments appropriately" ) ;
244+ println ! ( " • Implement graceful degradation for non-critical failures" ) ;
245+ println ! ( " • Log errors with sufficient context for debugging" ) ;
246+ println ! ( " • Provide help information when commands fail" ) ;
247+
248+ println ! ( "\n === Usage Examples ===" ) ;
249+ println ! ( "# Valid command:" ) ;
250+ println ! ( "cargo run --bin unilang_cli test.validate age::25 email::[email protected] score::95.5 level::advanced" ) ; 251+
252+ println ! ( "\n # Invalid commands (for testing):" ) ;
253+ println ! ( "cargo run --bin unilang_cli test.validate age::15 email::[email protected] # Age too low" ) ; 254+ println ! ( "cargo run --bin unilang_cli test.validate age::25 email::invalid_email # Invalid email" ) ;
255+ println ! ( "cargo run --bin unilang_cli test.validate email::[email protected] # Missing age" ) ; 256+
257+ Ok ( ( ) )
258+ }
259+
260+ /// Format error with appropriate styling and context
261+ fn format_error ( error : & Error ) -> String
262+ {
263+ match error
264+ {
265+ Error :: Execution ( error_data ) =>
266+ {
267+ match error_data. code . as_str ( )
268+ {
269+ "UNILANG_TYPE_MISMATCH" => format ! ( "🔢 Type Error: {}" , error_data. message ) ,
270+ "UNILANG_ARGUMENT_INTERACTIVE_REQUIRED" => format ! ( "🔒 Interactive Input: {}" , error_data. message ) ,
271+ _ => format ! ( "⚠️ Execution Error: {}" , error_data. message ) ,
272+ }
273+ } ,
274+ Error :: Registration ( msg ) => format ! ( "📝 Registration: {msg}" ) ,
275+ Error :: Yaml ( err ) => format ! ( "📄 YAML: {err}" ) ,
276+ Error :: Json ( err ) => format ! ( "📄 JSON: {err}" ) ,
277+ Error :: Parse ( err ) => format ! ( "🔍 Parse: {err}" ) ,
278+ }
279+ }
0 commit comments