Skip to main content

synth_frontend/
parser.rs

1//! WebAssembly Component Parser
2
3use synth_core::{Component, CoreModule, Error, Export, ExportKind, Memory, Result};
4use wasmparser::{Parser, Payload};
5
6/// Component parser
7pub struct ComponentParser;
8
9impl ComponentParser {
10    /// Create a new parser
11    pub fn new() -> Self {
12        Self
13    }
14
15    /// Parse a WebAssembly component from bytes
16    pub fn parse(&self, bytes: &[u8]) -> Result<Component> {
17        let parser = Parser::new(0);
18
19        // For PoC, we'll treat all WebAssembly modules as components
20        // In production, we'd properly handle the Component Model format
21        let mut component = Component::new("main".to_string());
22
23        for payload in parser.parse_all(bytes) {
24            let payload =
25                payload.map_err(|e| Error::parse(format!("WebAssembly parse error: {}", e)))?;
26
27            match payload {
28                Payload::Version { .. } => {
29                    // Validate version
30                }
31                Payload::ModuleSection { .. } => {
32                    // This is a component with embedded modules
33                    // For PoC, we'll handle this later
34                }
35                Payload::TypeSection(reader) => {
36                    // Parse type section (function signatures)
37                    for ty in reader {
38                        let _ty =
39                            ty.map_err(|e| Error::parse(format!("Failed to parse type: {}", e)))?;
40                        // Store types for later use
41                    }
42                }
43                Payload::FunctionSection(reader) => {
44                    // Parse function declarations
45                    for func in reader {
46                        let _func_type_idx = func.map_err(|e| {
47                            Error::parse(format!("Failed to parse function: {}", e))
48                        })?;
49                        // We'll fully implement this in the next iteration
50                    }
51                }
52                Payload::MemorySection(reader) => {
53                    // Parse linear memories
54                    let mut memories = Vec::new();
55                    for (index, memory) in reader.into_iter().enumerate() {
56                        let mem = memory
57                            .map_err(|e| Error::parse(format!("Failed to parse memory: {}", e)))?;
58
59                        memories.push(Memory {
60                            index: index as u32,
61                            initial: mem.initial as u32,
62                            maximum: mem.maximum.map(|m| m as u32),
63                            shared: mem.shared,
64                            memory64: mem.memory64,
65                        });
66                    }
67
68                    // Create a core module if we don't have one yet
69                    if component.modules.is_empty() {
70                        let module = CoreModule {
71                            id: "module0".to_string(),
72                            binary: bytes.to_vec(),
73                            functions: Vec::new(),
74                            memories,
75                            tables: Vec::new(),
76                            globals: Vec::new(),
77                        };
78                        component.modules.push(module);
79                    } else {
80                        component.modules[0].memories.extend(memories);
81                    }
82                }
83                Payload::ExportSection(reader) => {
84                    // Parse exports
85                    for export in reader {
86                        let export = export
87                            .map_err(|e| Error::parse(format!("Failed to parse export: {}", e)))?;
88
89                        let kind = match export.kind {
90                            wasmparser::ExternalKind::Func => ExportKind::Function(export.index),
91                            wasmparser::ExternalKind::Memory => ExportKind::Memory(export.index),
92                            wasmparser::ExternalKind::Table => ExportKind::Table(export.index),
93                            wasmparser::ExternalKind::Global => ExportKind::Global(export.index),
94                            _ => continue,
95                        };
96
97                        component.exports.push(Export {
98                            name: export.name.to_string(),
99                            kind,
100                        });
101                    }
102                }
103                Payload::CodeSectionEntry(body) => {
104                    // Parse function bodies
105                    // For PoC, we'll skip detailed parsing
106                    let _locals = body
107                        .get_locals_reader()
108                        .map_err(|e| Error::parse(format!("Failed to parse locals: {}", e)))?;
109                }
110                _ => {
111                    // Handle other sections as needed
112                }
113            }
114        }
115
116        // If we parsed a regular module, ensure it's in a component wrapper
117        if component.modules.is_empty() {
118            let module = CoreModule {
119                id: "module0".to_string(),
120                binary: bytes.to_vec(),
121                functions: Vec::new(),
122                memories: Vec::new(),
123                tables: Vec::new(),
124                globals: Vec::new(),
125            };
126            component.modules.push(module);
127        }
128
129        Ok(component)
130    }
131}
132
133impl Default for ComponentParser {
134    fn default() -> Self {
135        Self::new()
136    }
137}
138
139#[cfg(test)]
140mod tests {
141    use super::*;
142
143    #[test]
144    fn test_parse_empty_module() {
145        // Minimal valid WebAssembly module
146        let wasm = vec![
147            0x00, 0x61, 0x73, 0x6D, // Magic number
148            0x01, 0x00, 0x00, 0x00, // Version
149        ];
150
151        let parser = ComponentParser::new();
152        let result = parser.parse(&wasm);
153        assert!(result.is_ok());
154    }
155}