@@ -115,4 +115,314 @@ impl Decl {
115115 Decl :: Interface ( Interface { name, .. } ) => * name,
116116 }
117117 }
118+
119+ /// Pretty-print a declaration in lyte syntax.
120+ ///
121+ /// This method formats a declaration as it would appear in lyte source code,
122+ /// suitable for displaying to users or generating code.
123+ ///
124+ /// # Examples
125+ ///
126+ /// ```ignore
127+ /// // Given a function declaration:
128+ /// let decl = Decl::Func(func);
129+ /// let output = decl.pretty_print(&decls);
130+ /// // Output: "add(a: i32, b: i32) → i32"
131+ /// ```
132+ pub fn pretty_print ( & self , decls : & DeclTable ) -> String {
133+ match self {
134+ Decl :: Func ( func) => format_func_decl ( func, decls, false ) ,
135+ Decl :: Macro ( func) => format_func_decl ( func, decls, true ) ,
136+ Decl :: Struct ( st) => format_struct_decl ( st, decls) ,
137+ Decl :: Enum { name, cases } => format_enum_decl ( * name, cases) ,
138+ Decl :: Global { name, ty } => format ! ( "var {}: {}" , name, format_type( * ty, decls) ) ,
139+ Decl :: Interface ( iface) => format_interface ( iface, decls) ,
140+ }
141+ }
142+ }
143+
144+ fn format_typevars ( typevars : & [ Name ] ) -> String {
145+ if typevars. is_empty ( ) {
146+ String :: new ( )
147+ } else {
148+ format ! ( "<{}>" , typevars. iter( ) . map( |tv| tv. to_string( ) ) . collect:: <Vec <_>>( ) . join( ", " ) )
149+ }
150+ }
151+
152+ fn format_params ( params : & [ Param ] , decls : & DeclTable ) -> String {
153+ params
154+ . iter ( )
155+ . map ( |p| {
156+ if let Some ( ty) = p. ty {
157+ format ! ( "{}: {}" , p. name, format_type( ty, decls) )
158+ } else {
159+ p. name . to_string ( )
160+ }
161+ } )
162+ . collect :: < Vec < _ > > ( )
163+ . join ( ", " )
164+ }
165+
166+ fn format_type ( ty : TypeID , decls : & DeclTable ) -> String {
167+ match & * ty {
168+ Type :: Void => "void" . to_string ( ) ,
169+ Type :: Bool => "bool" . to_string ( ) ,
170+ Type :: Int8 => "i8" . to_string ( ) ,
171+ Type :: UInt8 => "u8" . to_string ( ) ,
172+ Type :: Int32 => "i32" . to_string ( ) ,
173+ Type :: UInt32 => "u32" . to_string ( ) ,
174+ Type :: Float32 => "f32" . to_string ( ) ,
175+ Type :: Float64 => "f64" . to_string ( ) ,
176+ Type :: Tuple ( types) => {
177+ format ! ( "({})" , types. iter( ) . map( |t| format_type( * t, decls) ) . collect:: <Vec <_>>( ) . join( ", " ) )
178+ }
179+ Type :: Var ( name) => name. to_string ( ) ,
180+ Type :: Anon ( id) => format ! ( "?{}" , id) ,
181+ Type :: Func ( dom, rng) => format ! ( "{} → {}" , format_type( * dom, decls) , format_type( * rng, decls) ) ,
182+ Type :: Array ( elem, size) => format ! ( "[{}; {}]" , format_type( * elem, decls) , size) ,
183+ Type :: Name ( name, params) => {
184+ if params. is_empty ( ) {
185+ name. to_string ( )
186+ } else {
187+ format ! ( "{}<{}>" , name, params. iter( ) . map( |t| format_type( * t, decls) ) . collect:: <Vec <_>>( ) . join( ", " ) )
188+ }
189+ }
190+ }
191+ }
192+
193+ fn format_constraints ( constraints : & [ InterfaceConstraint ] ) -> String {
194+ if constraints. is_empty ( ) {
195+ String :: new ( )
196+ } else {
197+ let formatted = constraints
198+ . iter ( )
199+ . map ( |c| {
200+ if c. typevars . is_empty ( ) {
201+ c. interface_name . to_string ( )
202+ } else {
203+ format ! ( "{}<{}>" , c. interface_name, c. typevars. iter( ) . map( |tv| tv. to_string( ) ) . collect:: <Vec <_>>( ) . join( ", " ) )
204+ }
205+ } )
206+ . collect :: < Vec < _ > > ( )
207+ . join ( ", " ) ;
208+ format ! ( " where {}" , formatted)
209+ }
210+ }
211+
212+ fn format_func_decl ( func : & FuncDecl , decls : & DeclTable , is_macro : bool ) -> String {
213+ let keyword = if is_macro { "macro" } else { "" } ;
214+ let typevars = format_typevars ( & func. typevars ) ;
215+ let params = format_params ( & func. params , decls) ;
216+ let ret_type = if matches ! ( & * func. ret, Type :: Void ) {
217+ String :: new ( )
218+ } else {
219+ format ! ( " → {}" , format_type( func. ret, decls) )
220+ } ;
221+ let constraints = format_constraints ( & func. constraints ) ;
222+
223+ let signature = if is_macro {
224+ format ! ( "macro {}{}" , func. name, typevars)
225+ } else if keyword. is_empty ( ) {
226+ format ! ( "{}{}" , func. name, typevars)
227+ } else {
228+ format ! ( "{} {}{}" , keyword, func. name, typevars)
229+ } ;
230+
231+ if func. body . is_some ( ) {
232+ format ! ( "{}({}){}{} {{ ... }}" , signature, params, ret_type, constraints)
233+ } else {
234+ format ! ( "{}({}){}{}" , signature, params, ret_type, constraints)
235+ }
236+ }
237+
238+ fn format_struct_decl ( st : & StructDecl , decls : & DeclTable ) -> String {
239+ let typevars = format_typevars ( & st. typevars ) ;
240+ let fields = st
241+ . fields
242+ . iter ( )
243+ . map ( |f| format ! ( " {}: {}" , f. name, format_type( f. ty, decls) ) )
244+ . collect :: < Vec < _ > > ( )
245+ . join ( "\n " ) ;
246+
247+ if fields. is_empty ( ) {
248+ format ! ( "struct {}{} {{}}" , st. name, typevars)
249+ } else {
250+ format ! ( "struct {}{} {{\n {}\n }}" , st. name, typevars, fields)
251+ }
252+ }
253+
254+ fn format_enum_decl ( name : Name , cases : & [ Name ] ) -> String {
255+ let cases_str = cases
256+ . iter ( )
257+ . map ( |c| format ! ( " {}" , c) )
258+ . collect :: < Vec < _ > > ( )
259+ . join ( "\n " ) ;
260+
261+ if cases. is_empty ( ) {
262+ format ! ( "enum {} {{}}" , name)
263+ } else {
264+ format ! ( "enum {} {{\n {}\n }}" , name, cases_str)
265+ }
266+ }
267+
268+ fn format_interface ( iface : & Interface , decls : & DeclTable ) -> String {
269+ let typevars = format_typevars ( & iface. typevars ) ;
270+ let funcs = iface
271+ . funcs
272+ . iter ( )
273+ . map ( |f| format ! ( " {}" , format_func_decl( f, decls, false ) ) )
274+ . collect :: < Vec < _ > > ( )
275+ . join ( "\n " ) ;
276+
277+ if funcs. is_empty ( ) {
278+ format ! ( "interface {}{} {{}}" , iface. name, typevars)
279+ } else {
280+ format ! ( "interface {}{} {{\n {}\n }}" , iface. name, typevars, funcs)
281+ }
282+ }
283+
284+ #[ cfg( test) ]
285+ mod tests {
286+ use super :: * ;
287+
288+ #[ test]
289+ fn test_pretty_print_func ( ) {
290+ let decls = DeclTable :: new ( vec ! [ ] ) ;
291+
292+ let func = FuncDecl {
293+ name : Name :: str ( "add" ) ,
294+ typevars : vec ! [ ] ,
295+ params : vec ! [
296+ Param {
297+ name: Name :: str ( "a" ) ,
298+ ty: Some ( mk_type( Type :: Int32 ) ) ,
299+ } ,
300+ Param {
301+ name: Name :: str ( "b" ) ,
302+ ty: Some ( mk_type( Type :: Int32 ) ) ,
303+ } ,
304+ ] ,
305+ body : None ,
306+ ret : mk_type ( Type :: Int32 ) ,
307+ constraints : vec ! [ ] ,
308+ loc : test_loc ( ) ,
309+ arena : ExprArena :: new ( ) ,
310+ types : vec ! [ ] ,
311+ } ;
312+
313+ let decl = Decl :: Func ( func) ;
314+ let output = decl. pretty_print ( & decls) ;
315+ assert_eq ! ( output, "add(a: i32, b: i32) → i32" ) ;
316+ }
317+
318+ #[ test]
319+ fn test_pretty_print_generic_func ( ) {
320+ let decls = DeclTable :: new ( vec ! [ ] ) ;
321+
322+ let func = FuncDecl {
323+ name : Name :: str ( "id" ) ,
324+ typevars : vec ! [ Name :: str ( "T" ) ] ,
325+ params : vec ! [ Param {
326+ name: Name :: str ( "x" ) ,
327+ ty: Some ( mk_type( Type :: Var ( Name :: str ( "T" ) ) ) ) ,
328+ } ] ,
329+ body : Some ( 0 ) ,
330+ ret : mk_type ( Type :: Var ( Name :: str ( "T" ) ) ) ,
331+ constraints : vec ! [ ] ,
332+ loc : test_loc ( ) ,
333+ arena : ExprArena :: new ( ) ,
334+ types : vec ! [ ] ,
335+ } ;
336+
337+ let decl = Decl :: Func ( func) ;
338+ let output = decl. pretty_print ( & decls) ;
339+ assert_eq ! ( output, "id<T>(x: T) → T { ... }" ) ;
340+ }
341+
342+ #[ test]
343+ fn test_pretty_print_struct ( ) {
344+ let decls = DeclTable :: new ( vec ! [ ] ) ;
345+
346+ let st = StructDecl {
347+ name : Name :: str ( "Point" ) ,
348+ typevars : vec ! [ ] ,
349+ fields : vec ! [
350+ Field {
351+ name: Name :: str ( "x" ) ,
352+ ty: mk_type( Type :: Float32 ) ,
353+ loc: test_loc( ) ,
354+ } ,
355+ Field {
356+ name: Name :: str ( "y" ) ,
357+ ty: mk_type( Type :: Float32 ) ,
358+ loc: test_loc( ) ,
359+ } ,
360+ ] ,
361+ } ;
362+
363+ let decl = Decl :: Struct ( st) ;
364+ let output = decl. pretty_print ( & decls) ;
365+ assert_eq ! ( output, "struct Point {\n x: f32\n y: f32\n }" ) ;
366+ }
367+
368+ #[ test]
369+ fn test_pretty_print_interface ( ) {
370+ let decls = DeclTable :: new ( vec ! [ ] ) ;
371+
372+ let iface = Interface {
373+ name : Name :: str ( "Compare" ) ,
374+ typevars : vec ! [ Name :: str ( "A" ) ] ,
375+ funcs : vec ! [ FuncDecl {
376+ name: Name :: str ( "cmp" ) ,
377+ typevars: vec![ ] ,
378+ params: vec![
379+ Param {
380+ name: Name :: str ( "lhs" ) ,
381+ ty: Some ( mk_type( Type :: Var ( Name :: str ( "A" ) ) ) ) ,
382+ } ,
383+ Param {
384+ name: Name :: str ( "rhs" ) ,
385+ ty: Some ( mk_type( Type :: Var ( Name :: str ( "A" ) ) ) ) ,
386+ } ,
387+ ] ,
388+ body: None ,
389+ ret: mk_type( Type :: Int32 ) ,
390+ constraints: vec![ ] ,
391+ loc: test_loc( ) ,
392+ arena: ExprArena :: new( ) ,
393+ types: vec![ ] ,
394+ } ] ,
395+ loc : test_loc ( ) ,
396+ } ;
397+
398+ let decl = Decl :: Interface ( iface) ;
399+ let output = decl. pretty_print ( & decls) ;
400+ assert_eq ! ( output, "interface Compare<A> {\n cmp(lhs: A, rhs: A) → i32\n }" ) ;
401+ }
402+
403+ #[ test]
404+ fn test_pretty_print_global ( ) {
405+ let decls = DeclTable :: new ( vec ! [ ] ) ;
406+
407+ let decl = Decl :: Global {
408+ name : Name :: str ( "counter" ) ,
409+ ty : mk_type ( Type :: Int32 ) ,
410+ } ;
411+
412+ let output = decl. pretty_print ( & decls) ;
413+ assert_eq ! ( output, "var counter: i32" ) ;
414+ }
415+
416+ #[ test]
417+ fn test_pretty_print_enum ( ) {
418+ let decls = DeclTable :: new ( vec ! [ ] ) ;
419+
420+ let decl = Decl :: Enum {
421+ name : Name :: str ( "Status" ) ,
422+ cases : vec ! [ Name :: str ( "Active" ) , Name :: str ( "Inactive" ) ] ,
423+ } ;
424+
425+ let output = decl. pretty_print ( & decls) ;
426+ assert_eq ! ( output, "enum Status {\n Active\n Inactive\n }" ) ;
427+ }
118428}
0 commit comments