@@ -51,6 +51,8 @@ use crate::internal::{
5151    lexer:: Token , 
5252} ; 
5353
54+ use  owo_colors:: OwoColorize ; 
55+ 
5456/// Parser for statistical formulas 
5557/// 
5658/// The parser converts formula strings into Abstract Syntax Trees (ASTs). 
@@ -113,22 +115,63 @@ impl<'a> Parser<'a> {
113115        crate :: internal:: new:: new ( input) 
114116    } 
115117
118+     /// Pretty-print a parse error with context (tokens, last-consumed lexeme, expected/found) 
119+      /// 
120+      /// This produces a colored, human-friendly message useful for CLI output. 
121+      pub  fn  pretty_error ( & self ,  err :  & ParseError )  -> String  { 
122+         match  err { 
123+             ParseError :: Lex ( s)  => { 
124+                 format ! ( "{}\n \n {}\n " ,  "Lexing error" . red( ) . bold( ) ,  s) 
125+             } 
126+             ParseError :: Eoi  => { 
127+                 format ! ( "{}\n \n {}\n " ,  "Unexpected end of input" . red( ) . bold( ) ,  "the formula ended earlier than expected" ) 
128+             } 
129+             ParseError :: Unexpected  {  expected,  found :  _ }  => { 
130+                 let  mut  out = String :: new ( ) ; 
131+                 
132+                 // Header 
133+                 out. push_str ( & format ! ( "{}\n " ,  "Syntax error- Unexpected Token" . red( ) . bold( ) ) ) ; 
134+                 
135+                 // Formula: just print the original formula uncolored 
136+                 out. push_str ( & format ! ( "Formula: {}\n " ,  self . input) ) ; 
137+                 
138+                 // Show: previous successful lexemes in green then failed lexeme in red 
139+                 out. push_str ( "Show: " ) ; 
140+                 for  i in  0 ..self . pos  { 
141+                     if  let  Some ( ( _,  lex) )  = self . tokens . get ( i)  { 
142+                         out. push_str ( & format ! ( "{} " ,  lex. green( ) ) ) ; 
143+                     } 
144+                 } 
145+                 let  failed = self . tokens . get ( self . pos ) . map ( |( _,  l) | * l) . unwrap_or ( "<eoi>" ) ; 
146+                 out. push_str ( & format ! ( "{}\n " ,  failed. red( ) ) ) ; 
147+                 
148+                 // Expected Token: list expected tokens 
149+                 out. push_str ( & format ! ( "Expected Token: {}\n " ,  expected. to_string( ) ) ) ; 
150+                 
151+                 out
152+             } 
153+             ParseError :: Syntax ( s)  => { 
154+                 format ! ( "{}\n \n {}\n " ,  "Syntax error" . red( ) . bold( ) ,  s) 
155+             } 
156+         } 
157+     } 
158+ 
116159    /// Parses the formula and returns the complete AST information 
117160     /// 
118161     /// This method performs the syntactic analysis of the tokenized formula 
119-      /// and returns the parsed components . 
162+      /// and returns the structured representation needed for statistical modeling . 
120163     /// 
121164     /// # Returns 
122-      /// 
165+      ///   
123166     /// A tuple containing: 
124-      /// * `String` - The response variable name  
167+      /// * `String` - The response variable (left side of ~)  
125168     /// * `Vec<Term>` - All terms in the formula (fixed effects, random effects, etc.) 
126169     /// * `bool` - Whether the model includes an intercept 
127170     /// * `Option<Family>` - The distribution family (if specified) 
128171     /// 
129172     /// # Examples 
130- /// 
131- /// ```rust 
173+      /// 
174+      /// ```rust 
132175/// use fiasto::internal::parser::Parser; 
133176/// 
134177/// let formula = "y ~ x + (1 | group), family = gaussian"; 
@@ -142,6 +185,12 @@ impl<'a> Parser<'a> {
142185     pub  fn  parse_formula ( 
143186        & mut  self , 
144187    )  -> Result < ( String ,  Vec < Term > ,  bool ,  Option < Family > ) ,  ParseError >  { 
145-         crate :: internal:: parse_formula:: parse_formula ( & self . tokens ,  & mut  self . pos ) 
188+         match  crate :: internal:: parse_formula:: parse_formula ( & self . tokens ,  & mut  self . pos )  { 
189+             Ok ( v)  => Ok ( v) , 
190+             Err ( e)  => { 
191+                 // Return the original error unchanged so pretty_error can handle it properly 
192+                 Err ( e) 
193+             } 
194+         } 
146195    } 
147196} 
0 commit comments