@@ -185,6 +185,111 @@ fn eval_const_expr(const_expr: wasmparser::ConstExpr) -> Result<InitValue> {
185185 }
186186}
187187
188+ /// Parse an active element segment, or return None for passive/declared segments.
189+ fn parse_element_segment ( element : wasmparser:: Element ) -> Result < Option < ElementSegment > > {
190+ match element. kind {
191+ wasmparser:: ElementKind :: Active {
192+ table_index,
193+ offset_expr,
194+ } => {
195+ // table_index is Option<u32>; None means table 0 (MVP default)
196+ let tidx = table_index. unwrap_or ( 0 ) ;
197+ if tidx != 0 {
198+ anyhow:: bail!(
199+ "Multi-table element segments not supported (table_index={})" ,
200+ tidx
201+ ) ;
202+ }
203+
204+ let offset = match eval_const_expr ( offset_expr) ? {
205+ InitValue :: I32 ( v) => v as u32 ,
206+ _ => anyhow:: bail!( "Element segment offset must be i32" ) ,
207+ } ;
208+
209+ // Collect function indices from element items
210+ let mut func_indices = Vec :: new ( ) ;
211+ match element. items {
212+ wasmparser:: ElementItems :: Functions ( funcs) => {
213+ for func_idx in funcs {
214+ let idx = func_idx. context ( "reading element func index" ) ?;
215+ func_indices. push ( idx) ;
216+ }
217+ }
218+ wasmparser:: ElementItems :: Expressions ( ..) => {
219+ anyhow:: bail!( "Expression-based element segments not supported" ) ;
220+ }
221+ }
222+
223+ Ok ( Some ( ElementSegment {
224+ offset,
225+ func_indices,
226+ } ) )
227+ }
228+ wasmparser:: ElementKind :: Passive | wasmparser:: ElementKind :: Declared => {
229+ // Skip passive/declared element segments
230+ Ok ( None )
231+ }
232+ }
233+ }
234+
235+ /// Parse an active data segment, or return None for passive segments.
236+ fn parse_data_segment ( data : wasmparser:: Data ) -> Result < Option < DataSegment > > {
237+ match data. kind {
238+ wasmparser:: DataKind :: Active {
239+ memory_index : 0 ,
240+ offset_expr,
241+ } => {
242+ let offset = match eval_const_expr ( offset_expr) ? {
243+ InitValue :: I32 ( v) => v as u32 ,
244+ _ => anyhow:: bail!( "Data segment offset must be i32" ) ,
245+ } ;
246+ Ok ( Some ( DataSegment {
247+ offset,
248+ data : data. data . to_vec ( ) ,
249+ } ) )
250+ }
251+ wasmparser:: DataKind :: Passive => {
252+ // Skip passive data segments (used with memory.init)
253+ Ok ( None )
254+ }
255+ wasmparser:: DataKind :: Active { memory_index, .. } => {
256+ anyhow:: bail!(
257+ "Multi-memory data segments not supported (memory_index={})" ,
258+ memory_index
259+ ) ;
260+ }
261+ }
262+ }
263+
264+ /// Parse a function code section entry, extracting locals and bytecode.
265+ fn parse_code_entry ( body : wasmparser:: FunctionBody , type_idx : u32 ) -> Result < ParsedFunction > {
266+ // Extract locals
267+ let mut locals = Vec :: new ( ) ;
268+ let locals_reader = body. get_locals_reader ( ) . context ( "getting locals reader" ) ?;
269+ for local in locals_reader {
270+ let ( count, val_type) = local. context ( "reading local" ) ?;
271+ for _ in 0 ..count {
272+ locals. push ( val_type) ;
273+ }
274+ }
275+
276+ // Extract operators as raw bytes (parsed later in the IR builder)
277+ let operators_reader = body
278+ . get_operators_reader ( )
279+ . context ( "getting operators reader" ) ?;
280+ let mut binary_reader = operators_reader. get_binary_reader ( ) ;
281+ let remaining = binary_reader. bytes_remaining ( ) ;
282+ let body_bytes = binary_reader
283+ . read_bytes ( remaining)
284+ . context ( "reading body bytes" ) ?;
285+
286+ Ok ( ParsedFunction {
287+ type_idx,
288+ locals,
289+ body : body_bytes. to_vec ( ) ,
290+ } )
291+ }
292+
188293/// Parse a WebAssembly binary into a structured module.
189294pub fn parse_wasm ( wasm_bytes : & [ u8 ] ) -> Result < ParsedModule > {
190295 let parser = Parser :: new ( 0 ) ;
@@ -268,32 +373,9 @@ pub fn parse_wasm(wasm_bytes: &[u8]) -> Result<ParsedModule> {
268373 }
269374
270375 Payload :: CodeSectionEntry ( body) => {
271- // Extract locals
272- let mut locals = Vec :: new ( ) ;
273- let locals_reader = body. get_locals_reader ( ) . context ( "getting locals reader" ) ?;
274- for local in locals_reader {
275- let ( count, val_type) = local. context ( "reading local" ) ?;
276- for _ in 0 ..count {
277- locals. push ( val_type) ;
278- }
279- }
280-
281- // Extract operators as raw bytes
282- // (We'll parse them later in the IR builder)
283- let operators_reader = body
284- . get_operators_reader ( )
285- . context ( "getting operators reader" ) ?;
286- let mut binary_reader = operators_reader. get_binary_reader ( ) ;
287- let remaining = binary_reader. bytes_remaining ( ) ;
288- let body_bytes = binary_reader
289- . read_bytes ( remaining)
290- . context ( "reading body bytes" ) ?;
291-
292- functions. push ( ParsedFunction {
293- type_idx : function_types[ functions. len ( ) ] , // Match with function section
294- locals,
295- body : body_bytes. to_vec ( ) ,
296- } ) ;
376+ let type_idx = function_types[ functions. len ( ) ] ; // Match with function section
377+ let parsed_func = parse_code_entry ( body, type_idx) ?;
378+ functions. push ( parsed_func) ;
297379 }
298380
299381 Payload :: MemorySection ( reader) => {
@@ -321,46 +403,8 @@ pub fn parse_wasm(wasm_bytes: &[u8]) -> Result<ParsedModule> {
321403 Payload :: ElementSection ( reader) => {
322404 for element in reader {
323405 let element = element. context ( "reading element segment" ) ?;
324- match element. kind {
325- wasmparser:: ElementKind :: Active {
326- table_index,
327- offset_expr,
328- } => {
329- // table_index is Option<u32>; None means table 0 (MVP default)
330- let tidx = table_index. unwrap_or ( 0 ) ;
331- if tidx != 0 {
332- anyhow:: bail!(
333- "Multi-table element segments not supported (table_index={})" ,
334- tidx
335- ) ;
336- }
337- let offset = match eval_const_expr ( offset_expr) ? {
338- InitValue :: I32 ( v) => v as u32 ,
339- _ => anyhow:: bail!( "Element segment offset must be i32" ) ,
340- } ;
341- // Collect function indices from element items
342- let mut func_indices = Vec :: new ( ) ;
343- match element. items {
344- wasmparser:: ElementItems :: Functions ( funcs) => {
345- for func_idx in funcs {
346- let idx = func_idx. context ( "reading element func index" ) ?;
347- func_indices. push ( idx) ;
348- }
349- }
350- wasmparser:: ElementItems :: Expressions ( ..) => {
351- anyhow:: bail!(
352- "Expression-based element segments not supported"
353- ) ;
354- }
355- }
356- element_segments. push ( ElementSegment {
357- offset,
358- func_indices,
359- } ) ;
360- }
361- wasmparser:: ElementKind :: Passive | wasmparser:: ElementKind :: Declared => {
362- // Skip passive/declared element segments
363- }
406+ if let Some ( segment) = parse_element_segment ( element) ? {
407+ element_segments. push ( segment) ;
364408 }
365409 }
366410 }
@@ -398,29 +442,8 @@ pub fn parse_wasm(wasm_bytes: &[u8]) -> Result<ParsedModule> {
398442 Payload :: DataSection ( reader) => {
399443 for data in reader {
400444 let data = data. context ( "reading data segment" ) ?;
401- match data. kind {
402- wasmparser:: DataKind :: Active {
403- memory_index : 0 ,
404- offset_expr,
405- } => {
406- let offset = match eval_const_expr ( offset_expr) ? {
407- InitValue :: I32 ( v) => v as u32 ,
408- _ => anyhow:: bail!( "Data segment offset must be i32" ) ,
409- } ;
410- data_segments. push ( DataSegment {
411- offset,
412- data : data. data . to_vec ( ) ,
413- } ) ;
414- }
415- wasmparser:: DataKind :: Passive => {
416- // Skip passive data segments (used with memory.init)
417- }
418- wasmparser:: DataKind :: Active { memory_index, .. } => {
419- anyhow:: bail!(
420- "Multi-memory data segments not supported (memory_index={})" ,
421- memory_index
422- ) ;
423- }
445+ if let Some ( segment) = parse_data_segment ( data) ? {
446+ data_segments. push ( segment) ;
424447 }
425448 }
426449 }
0 commit comments