@@ -18,7 +18,7 @@ pub fn dump(module: &Module) -> String {
1818 let ctx = DumpContext :: new ( module) ;
1919
2020 dump_header ( & mut out, module) ;
21- dump_strings ( & mut out, module) ;
21+ dump_strings ( & mut out, module, & ctx ) ;
2222 dump_types_defs ( & mut out, module, & ctx) ;
2323 dump_types_members ( & mut out, module, & ctx) ;
2424 dump_types_names ( & mut out, module, & ctx) ;
@@ -35,6 +35,15 @@ fn dump_header(out: &mut String, module: &Module) {
3535 out. push ( '\n' ) ;
3636}
3737
38+ /// Calculate the minimum width needed to display numbers up to `count - 1`.
39+ fn width_for_count ( count : usize ) -> usize {
40+ if count <= 1 {
41+ 1
42+ } else {
43+ ( ( count - 1 ) as f64 ) . log10 ( ) . floor ( ) as usize + 1
44+ }
45+ }
46+
3847/// Context for dump formatting, precomputes lookups for O(1) access.
3948struct DumpContext {
4049 /// Whether the bytecode is linked (contains grammar IDs vs StringIds).
@@ -47,6 +56,16 @@ struct DumpContext {
4756 node_field_names : BTreeMap < u16 , String > ,
4857 /// All strings (for unlinked mode lookups).
4958 all_strings : Vec < String > ,
59+ /// Width for string indices (S#).
60+ str_width : usize ,
61+ /// Width for type indices (T#).
62+ type_width : usize ,
63+ /// Width for member indices (M#).
64+ member_width : usize ,
65+ /// Width for name indices (N#).
66+ name_width : usize ,
67+ /// Width for step indices.
68+ step_width : usize ,
5069}
5170
5271impl DumpContext {
@@ -83,12 +102,26 @@ impl DumpContext {
83102 . map ( |i| strings. get ( StringId ( i as u16 ) ) . to_string ( ) )
84103 . collect ( ) ;
85104
105+ // Compute widths for index formatting
106+ let types = module. types ( ) ;
107+ let type_count = 3 + types. defs_count ( ) ; // 3 builtins + custom types
108+ let str_width = width_for_count ( str_count) ;
109+ let type_width = width_for_count ( type_count) ;
110+ let member_width = width_for_count ( types. members_count ( ) ) ;
111+ let name_width = width_for_count ( types. names_count ( ) ) ;
112+ let step_width = width_for_count ( header. transitions_count as usize ) ;
113+
86114 Self {
87115 is_linked,
88116 step_labels,
89117 node_type_names,
90118 node_field_names,
91119 all_strings,
120+ str_width,
121+ type_width,
122+ member_width,
123+ name_width,
124+ step_width,
92125 }
93126 }
94127
@@ -123,46 +156,50 @@ impl DumpContext {
123156 }
124157}
125158
126- fn dump_strings ( out : & mut String , module : & Module ) {
159+ fn dump_strings ( out : & mut String , module : & Module , ctx : & DumpContext ) {
127160 let strings = module. strings ( ) ;
128161 let count = module. header ( ) . str_table_count as usize ;
162+ let w = ctx. str_width ;
129163
130164 out. push_str ( "[strings]\n " ) ;
131165 for i in 0 ..count {
132166 let s = strings. get ( StringId ( i as u16 ) ) ;
133- writeln ! ( out, "S{i:02 } {s:?}" ) . unwrap ( ) ;
167+ writeln ! ( out, "S{i:0w$ } {s:?}" ) . unwrap ( ) ;
134168 }
135169 out. push ( '\n' ) ;
136170}
137171
138172fn dump_types_defs ( out : & mut String , module : & Module , ctx : & DumpContext ) {
139173 let types = module. types ( ) ;
140174 let strings = module. strings ( ) ;
175+ let tw = ctx. type_width ;
176+ let mw = ctx. member_width ;
141177
142178 out. push_str ( "[type_defs]\n " ) ;
143179
144- // Builtins (T00-T02)
145- out. push_str ( "T00 = void\n " ) ;
146- out. push_str ( "T01 = Node\n " ) ;
147- out. push_str ( "T02 = str\n " ) ;
148-
149- // Custom types (T03+)
180+ // All types are now in type_defs, including builtins
150181 for i in 0 ..types. defs_count ( ) {
151182 let def = types. get_def ( i) ;
152- let type_id = i + 3 ; // Custom types start at index 3
153-
154183 let kind = def. type_kind ( ) . expect ( "valid type kind" ) ;
184+
155185 let formatted = match kind {
156- TypeKind :: Struct => format ! ( "Struct M{}[{}]" , def. data, def. count) ,
157- TypeKind :: Enum => format ! ( "Enum M{}[{}]" , def. data, def. count) ,
158- TypeKind :: Optional => format ! ( "Optional(T{:02})" , def. data) ,
159- TypeKind :: ArrayZeroOrMore => format ! ( "ArrayStar(T{:02})" , def. data) ,
160- TypeKind :: ArrayOneOrMore => format ! ( "ArrayPlus(T{:02})" , def. data) ,
161- TypeKind :: Alias => format ! ( "Alias(T{:02})" , def. data) ,
186+ // Primitive types
187+ TypeKind :: Void => "<Void>" . to_string ( ) ,
188+ TypeKind :: Node => "<Node>" . to_string ( ) ,
189+ TypeKind :: String => "<String>" . to_string ( ) ,
190+ // Composite types
191+ TypeKind :: Struct => format ! ( "Struct M{:0mw$}:{}" , def. data, def. count) ,
192+ TypeKind :: Enum => format ! ( "Enum M{:0mw$}:{}" , def. data, def. count) ,
193+ // Wrapper types
194+ TypeKind :: Optional => format ! ( "Optional(T{:0tw$})" , def. data) ,
195+ TypeKind :: ArrayZeroOrMore => format ! ( "ArrayStar(T{:0tw$})" , def. data) ,
196+ TypeKind :: ArrayOneOrMore => format ! ( "ArrayPlus(T{:0tw$})" , def. data) ,
197+ TypeKind :: Alias => format ! ( "Alias(T{:0tw$})" , def. data) ,
162198 } ;
163199
164- // Generate comment for composites
200+ // Generate comment for non-primitives
165201 let comment = match kind {
202+ TypeKind :: Void | TypeKind :: Node | TypeKind :: String => String :: new ( ) ,
166203 TypeKind :: Struct => {
167204 let fields: Vec < _ > = types
168205 . members_of ( & def)
@@ -192,14 +229,17 @@ fn dump_types_defs(out: &mut String, module: &Module, ctx: &DumpContext) {
192229 TypeKind :: Alias => String :: new ( ) ,
193230 } ;
194231
195- writeln ! ( out, "T{type_id:02 } = {formatted}{comment}" ) . unwrap ( ) ;
232+ writeln ! ( out, "T{i:0tw$ } = {formatted}{comment}" ) . unwrap ( ) ;
196233 }
197234 out. push ( '\n' ) ;
198235}
199236
200237fn dump_types_members ( out : & mut String , module : & Module , ctx : & DumpContext ) {
201238 let types = module. types ( ) ;
202239 let strings = module. strings ( ) ;
240+ let mw = ctx. member_width ;
241+ let sw = ctx. str_width ;
242+ let tw = ctx. type_width ;
203243
204244 out. push_str ( "[type_members]\n " ) ;
205245 for i in 0 ..types. members_count ( ) {
@@ -208,25 +248,28 @@ fn dump_types_members(out: &mut String, module: &Module, ctx: &DumpContext) {
208248 let type_name = format_type_name ( member. type_id , module, ctx) ;
209249 writeln ! (
210250 out,
211- "M{i}: S{:02 } → T{:02 } ; {name}: {type_name}" ,
251+ "M{i:0mw$ }: S{:0sw$ } → T{:0tw$ } ; {name}: {type_name}" ,
212252 member. name. 0 , member. type_id. 0
213253 )
214254 . unwrap ( ) ;
215255 }
216256 out. push ( '\n' ) ;
217257}
218258
219- fn dump_types_names ( out : & mut String , module : & Module , _ctx : & DumpContext ) {
259+ fn dump_types_names ( out : & mut String , module : & Module , ctx : & DumpContext ) {
220260 let types = module. types ( ) ;
221261 let strings = module. strings ( ) ;
262+ let nw = ctx. name_width ;
263+ let sw = ctx. str_width ;
264+ let tw = ctx. type_width ;
222265
223266 out. push_str ( "[type_names]\n " ) ;
224267 for i in 0 ..types. names_count ( ) {
225268 let entry = types. get_name ( i) ;
226269 let name = strings. get ( entry. name ) ;
227270 writeln ! (
228271 out,
229- "N{i}: S{:02 } → T{:02 } ; {name}" ,
272+ "N{i:0nw$ }: S{:0sw$ } → T{:0tw$ } ; {name}" ,
230273 entry. name. 0 , entry. type_id. 0
231274 )
232275 . unwrap ( ) ;
@@ -235,34 +278,37 @@ fn dump_types_names(out: &mut String, module: &Module, _ctx: &DumpContext) {
235278}
236279
237280/// Format a type ID as a human-readable name.
238- fn format_type_name ( type_id : QTypeId , module : & Module , _ctx : & DumpContext ) -> String {
239- if type_id. is_builtin ( ) {
240- return match type_id. 0 {
241- 0 => "void" . to_string ( ) ,
242- 1 => "Node" . to_string ( ) ,
243- 2 => "str" . to_string ( ) ,
244- _ => unreachable ! ( ) ,
245- } ;
246- }
247-
248- // Try to find a name in types.names
281+ fn format_type_name ( type_id : QTypeId , module : & Module , ctx : & DumpContext ) -> String {
249282 let types = module. types ( ) ;
250283 let strings = module. strings ( ) ;
251284
285+ // Check if it's a primitive type
286+ if let Some ( def) = types. get ( type_id) {
287+ if let Some ( kind) = def. type_kind ( ) {
288+ if let Some ( name) = kind. primitive_name ( ) {
289+ return format ! ( "<{}>" , name) ;
290+ }
291+ }
292+ }
293+
294+ // Try to find a name in types.names
252295 for i in 0 ..types. names_count ( ) {
253296 let entry = types. get_name ( i) ;
254297 if entry. type_id == type_id {
255298 return strings. get ( entry. name ) . to_string ( ) ;
256299 }
257300 }
258301
259- // Fall back to T## format
260- format ! ( "T{:02}" , type_id. 0 )
302+ // Fall back to T# format
303+ let tw = ctx. type_width ;
304+ format ! ( "T{:0tw$}" , type_id. 0 )
261305}
262306
263- fn dump_entrypoints ( out : & mut String , module : & Module , _ctx : & DumpContext ) {
307+ fn dump_entrypoints ( out : & mut String , module : & Module , ctx : & DumpContext ) {
264308 let strings = module. strings ( ) ;
265309 let entrypoints = module. entrypoints ( ) ;
310+ let stw = ctx. step_width ;
311+ let tw = ctx. type_width ;
266312
267313 out. push_str ( "[entrypoints]\n " ) ;
268314
@@ -282,7 +328,7 @@ fn dump_entrypoints(out: &mut String, module: &Module, _ctx: &DumpContext) {
282328 for ( name, target, type_id) in entries {
283329 writeln ! (
284330 out,
285- "{name:width$} = {:02 } :: T{type_id:02 }" ,
331+ "{name:width$} = {:0stw$ } :: T{type_id:0tw$ }" ,
286332 target,
287333 width = max_len
288334 )
@@ -294,13 +340,7 @@ fn dump_entrypoints(out: &mut String, module: &Module, _ctx: &DumpContext) {
294340fn dump_code ( out : & mut String , module : & Module , ctx : & DumpContext ) {
295341 let header = module. header ( ) ;
296342 let transitions_count = header. transitions_count as usize ;
297-
298- // Calculate step number width based on total steps
299- let step_width = if transitions_count == 0 {
300- 2
301- } else {
302- ( ( transitions_count as f64 ) . log10 ( ) . floor ( ) as usize + 1 ) . max ( 2 )
303- } ;
343+ let step_width = ctx. step_width ;
304344
305345 out. push_str ( "[transitions]\n " ) ;
306346
0 commit comments