1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
// WASM analysis implementations - included from wasm.rs
// NO use imports or #! inner attributes allowed (shares parent module scope)
impl WasmModuleAnalyzer {
/// Creates a new WASM module analyzer
#[must_use]
pub fn new(file_path: &Path) -> Self {
Self {
items: Vec::new(),
_file_path: file_path.to_path_buf(),
module_name: file_path
.file_stem()
.and_then(|s| s.to_str())
.unwrap_or("unknown")
.to_string(),
function_count: 0,
_import_count: 0,
_export_count: 0,
}
}
/// Analyzes WASM binary and extracts AST items (complexity ≤10)
pub fn analyze_wasm_binary(mut self, wasm_bytes: &[u8]) -> Result<Vec<AstItem>, String> {
if wasm_bytes.len() < 8 {
return Err("Invalid WASM binary: too short".to_string());
}
if &wasm_bytes[0..4] != b"\0asm" {
return Err("Invalid WASM magic number".to_string());
}
let parser = Parser::new(0);
for (i, payload) in parser.parse_all(wasm_bytes).enumerate() {
match payload {
Ok(Payload::FunctionSection(_)) => {
self.function_count = i + 1;
self.items.push(AstItem::Function {
name: self.get_qualified_name(&format!("function_{i}")),
visibility: "export".to_string(),
is_async: false,
line: 1,
});
}
_ => continue,
}
}
Ok(self.items)
}
/// Analyzes WASM text format (.wat) (complexity ≤10)
pub fn analyze_wat_text(mut self, wat_source: &str) -> Result<Vec<AstItem>, String> {
let mut function_count = 0;
for line in wat_source.lines() {
let trimmed = line.trim();
// Match function definitions, not function references in exports
// Function definitions start with "(func " but exports have "(func $name)"
if trimmed.starts_with("(func ") {
let func_name = self.extract_wat_function_name(trimmed);
let qualified_name = self.get_qualified_name(&func_name);
self.items.push(AstItem::Function {
name: qualified_name,
visibility: "export".to_string(),
is_async: false,
line: function_count + 1,
});
function_count += 1;
}
}
self.function_count = function_count;
Ok(self.items)
}
/// Extracts function information from WASM (complexity ≤10)
fn _extract_wasm_functions(&mut self, _parser: &Parser) -> Result<(), String> {
// Not yet implemented - WASM function extraction requires wasmparser iteration
Err("WASM function extraction not yet implemented".to_string())
}
/// Extracts import/export information (complexity ≤10)
fn _extract_imports_exports(&mut self, _parser: &Parser) -> Result<(), String> {
// Not yet implemented - WASM import/export extraction requires section parsing
Err("WASM import/export extraction not yet implemented".to_string())
}
/// Calculates WASM-specific complexity metrics (complexity ≤10)
fn _calculate_wasm_complexity(&self, _function_body: &[u8]) -> Result<(u32, u32), String> {
// Not yet implemented - WASM complexity analysis requires instruction counting
Err("WASM complexity calculation not yet implemented".to_string())
}
/// Extracts function name from WAT line (complexity ≤10)
fn extract_wat_function_name(&self, line: &str) -> String {
if let Some(start) = line.find('$') {
if let Some(end) = line[start..].find(' ') {
line[start + 1..start + end].to_string()
} else {
format!("function_{}", self.function_count)
}
} else {
format!("function_{}", self.function_count)
}
}
/// Gets qualified name for WASM symbol (complexity ≤10)
fn get_qualified_name(&self, symbol_name: &str) -> String {
if self.module_name.is_empty() {
symbol_name.to_string()
} else {
format!("{}::{}", self.module_name, symbol_name)
}
}
}
impl WasmStackAnalyzer {
/// Creates a new WASM stack analyzer
#[must_use]
pub fn new() -> Self {
Self {
max_stack_depth: 0,
current_depth: 0,
branch_count: 0,
}
}
/// Analyzes stack depth complexity (complexity ≤10)
pub fn analyze_stack_complexity(&mut self, function_body: &[u8]) -> Result<u32, String> {
self.current_depth = 0;
self.max_stack_depth = 0;
for &byte in function_body {
match byte {
0x20 => self.current_depth += 1, // local.get - pushes value to stack
0x41 => self.current_depth += 1, // i32.const
0x42 => self.current_depth += 1, // i64.const
0x6a => {
// i32.add - pops 2, pushes 1 (net -1)
if self.current_depth >= 2 {
self.current_depth -= 1;
}
}
0x1a => {
// drop
if self.current_depth > 0 {
self.current_depth -= 1;
}
}
_ => {}
}
self.max_stack_depth = self.max_stack_depth.max(self.current_depth);
}
Ok(self.max_stack_depth)
}
/// Analyzes control flow complexity (complexity ≤10)
pub fn analyze_control_flow_complexity(&mut self, function_body: &[u8]) -> Result<u32, String> {
self.branch_count = 1; // Base complexity
for &byte in function_body {
match byte {
0x04 => self.branch_count += 1, // if block
0x05 => self.branch_count += 1, // else
0x03 => self.branch_count += 1, // loop
0x02 => self.branch_count += 1, // block
0x0c => self.branch_count += 1, // br (branch)
0x0d => self.branch_count += 1, // br_if (conditional branch)
_ => {}
}
}
Ok(self.branch_count)
}
}