Skip to content
This repository was archived by the owner on Oct 3, 2025. It is now read-only.

Commit 295a48c

Browse files
feat: improve parser
Signed-off-by: Henry <[email protected]>
1 parent fcb92ca commit 295a48c

File tree

6 files changed

+118
-36
lines changed

6 files changed

+118
-36
lines changed

crates/parser/src/conversion.rs

Lines changed: 46 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,40 @@ use tinywasm_types::{
44
BlockArgs, ConstInstruction, Export, ExternalKind, FuncType, Global, GlobalType, Import, ImportKind, Instruction,
55
MemArg, MemoryArch, MemoryType, TableType, ValType,
66
};
7-
use wasmparser::{FuncValidator, ValidatorResources};
7+
use wasmparser::{FuncValidator, OperatorsReader, ValidatorResources};
88

99
use crate::{module::CodeSection, Result};
1010

11+
pub(crate) fn convert_module_data_sections<'a, T: IntoIterator<Item = wasmparser::Result<wasmparser::Data<'a>>>>(
12+
data_sections: T,
13+
) -> Result<Vec<tinywasm_types::Data>> {
14+
let data_sections = data_sections
15+
.into_iter()
16+
.map(|data| convert_module_data(data?))
17+
.collect::<Result<Vec<_>>>()?;
18+
Ok(data_sections)
19+
}
20+
21+
pub(crate) fn convert_module_data(data: wasmparser::Data<'_>) -> Result<tinywasm_types::Data> {
22+
Ok(tinywasm_types::Data {
23+
data: data.data.to_vec().into_boxed_slice(),
24+
range: data.range,
25+
kind: match data.kind {
26+
wasmparser::DataKind::Active {
27+
memory_index,
28+
offset_expr,
29+
} => {
30+
let offset = process_const_operators(offset_expr.get_operators_reader())?;
31+
tinywasm_types::DataKind::Active {
32+
mem: memory_index,
33+
offset,
34+
}
35+
}
36+
wasmparser::DataKind::Passive => tinywasm_types::DataKind::Passive,
37+
},
38+
})
39+
}
40+
1141
pub(crate) fn convert_module_imports<'a, T: IntoIterator<Item = wasmparser::Result<wasmparser::Import<'a>>>>(
1242
imports: T,
1343
) -> Result<Vec<Import>> {
@@ -20,8 +50,8 @@ pub(crate) fn convert_module_imports<'a, T: IntoIterator<Item = wasmparser::Resu
2050

2151
pub(crate) fn convert_module_import(import: wasmparser::Import<'_>) -> Result<Import> {
2252
Ok(Import {
23-
module: import.module.to_string(),
24-
name: import.name.to_string(),
53+
module: import.module.to_string().into_boxed_str(),
54+
name: import.name.to_string().into_boxed_str(),
2555
kind: match import.ty {
2656
wasmparser::TypeRef::Func(ty) => ImportKind::Func(ty),
2757
wasmparser::TypeRef::Table(ty) => ImportKind::Table(convert_module_table(ty)?),
@@ -90,21 +120,10 @@ pub(crate) fn convert_module_globals<'a, T: IntoIterator<Item = wasmparser::Resu
90120
.map(|global| {
91121
let global = global?;
92122
let ty = convert_valtype(&global.ty.content_type);
93-
94-
let ops = global
95-
.init_expr
96-
.get_operators_reader()
97-
.into_iter()
98-
.collect::<wasmparser::Result<Vec<_>>>()?;
99-
100-
// In practice, the len can never be something other than 2,
101-
// but we'll keep this here since it's part of the spec
102-
// Invalid modules will be rejected by the validator anyway (there are also tests for this in the testsuite)
103-
assert!(ops.len() >= 2);
104-
assert!(matches!(ops[ops.len() - 1], wasmparser::Operator::End));
123+
let ops = global.init_expr.get_operators_reader();
105124

106125
Ok(Global {
107-
init: process_const_operator(ops[ops.len() - 2].clone())?,
126+
init: process_const_operators(ops)?,
108127
ty: GlobalType {
109128
mutable: global.ty.mutable,
110129
ty,
@@ -215,6 +234,17 @@ pub(crate) fn convert_memarg(memarg: wasmparser::MemArg) -> MemArg {
215234
}
216235
}
217236

237+
pub(crate) fn process_const_operators(ops: OperatorsReader) -> Result<ConstInstruction> {
238+
let ops = ops.into_iter().collect::<wasmparser::Result<Vec<_>>>()?;
239+
// In practice, the len can never be something other than 2,
240+
// but we'll keep this here since it's part of the spec
241+
// Invalid modules will be rejected by the validator anyway (there are also tests for this in the testsuite)
242+
assert!(ops.len() >= 2);
243+
assert!(matches!(ops[ops.len() - 1], wasmparser::Operator::End));
244+
245+
Ok(process_const_operator(ops[ops.len() - 2].clone())?)
246+
}
247+
218248
pub fn process_const_operator(op: wasmparser::Operator) -> Result<ConstInstruction> {
219249
match op {
220250
wasmparser::Operator::I32Const { value } => Ok(ConstInstruction::I32Const(value)),

crates/parser/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,8 @@ impl TryFrom<ModuleReader> for TinyWasmModule {
126126
globals: globals.into_boxed_slice(),
127127
table_types: table_types.into_boxed_slice(),
128128
memory_types: reader.memory_types.into_boxed_slice(),
129+
imports: reader.imports.into_boxed_slice(),
130+
data: reader.data.into_boxed_slice(),
129131
})
130132
}
131133
}

crates/parser/src/module.rs

Lines changed: 43 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
use crate::log::debug;
2+
use crate::{conversion, ParseError, Result};
23
use alloc::{boxed::Box, format, vec::Vec};
34
use core::fmt::Debug;
4-
use tinywasm_types::{Export, FuncType, Global, Import, Instruction, MemoryType, TableType, ValType};
5+
use tinywasm_types::{Data, Export, FuncType, Global, Import, Instruction, MemoryType, TableType, ValType};
56
use wasmparser::{Payload, Validator};
67

7-
use crate::{conversion, ParseError, Result};
8-
98
#[derive(Debug, Clone, PartialEq)]
109
pub struct CodeSection {
1110
pub locals: Box<[ValType]>,
@@ -25,9 +24,9 @@ pub struct ModuleReader {
2524
pub table_types: Vec<TableType>,
2625
pub memory_types: Vec<MemoryType>,
2726
pub imports: Vec<Import>,
27+
pub data: Vec<Data>,
2828

2929
// pub element_section: Option<ElementSectionReader<'a>>,
30-
// pub data_section: Option<DataSectionReader<'a>>,
3130
pub end_reached: bool,
3231
}
3332

@@ -67,11 +66,19 @@ impl ModuleReader {
6766
}
6867
}
6968
StartSection { func, range } => {
69+
if self.start_func.is_some() {
70+
return Err(ParseError::DuplicateSection("Start section".into()));
71+
}
72+
7073
debug!("Found start section");
7174
validator.start_section(func, &range)?;
7275
self.start_func = Some(func);
7376
}
7477
TypeSection(reader) => {
78+
if !self.func_types.is_empty() {
79+
return Err(ParseError::DuplicateSection("Type section".into()));
80+
}
81+
7582
debug!("Found type section");
7683
validator.type_section(&reader)?;
7784
self.func_types = reader
@@ -80,21 +87,37 @@ impl ModuleReader {
8087
.collect::<Result<Vec<FuncType>>>()?;
8188
}
8289
FunctionSection(reader) => {
90+
if !self.func_addrs.is_empty() {
91+
return Err(ParseError::DuplicateSection("Function section".into()));
92+
}
93+
8394
debug!("Found function section");
8495
validator.function_section(&reader)?;
8596
self.func_addrs = reader.into_iter().map(|f| Ok(f?)).collect::<Result<Vec<_>>>()?;
8697
}
8798
GlobalSection(reader) => {
99+
if !self.globals.is_empty() {
100+
return Err(ParseError::DuplicateSection("Global section".into()));
101+
}
102+
88103
debug!("Found global section");
89104
validator.global_section(&reader)?;
90105
self.globals = conversion::convert_module_globals(reader)?;
91106
}
92107
TableSection(reader) => {
108+
if !self.table_types.is_empty() {
109+
return Err(ParseError::DuplicateSection("Table section".into()));
110+
}
111+
93112
debug!("Found table section");
94113
validator.table_section(&reader)?;
95114
self.table_types = conversion::convert_module_tables(reader)?;
96115
}
97116
MemorySection(reader) => {
117+
if !self.memory_types.is_empty() {
118+
return Err(ParseError::DuplicateSection("Memory section".into()));
119+
}
120+
98121
debug!("Found memory section");
99122
validator.memory_section(&reader)?;
100123
self.memory_types = conversion::convert_module_memories(reader)?;
@@ -105,11 +128,14 @@ impl ModuleReader {
105128
// validator.element_section(&reader)?;
106129
// self.element_section = Some(reader);
107130
}
108-
DataSection(_reader) => {
109-
return Err(ParseError::UnsupportedSection("Data section".into()));
110-
// debug!("Found data section");
111-
// validator.data_section(&reader)?;
112-
// self.data_section = Some(reader);
131+
DataSection(reader) => {
132+
if !self.data.is_empty() {
133+
return Err(ParseError::DuplicateSection("Data section".into()));
134+
}
135+
136+
debug!("Found data section");
137+
validator.data_section(&reader)?;
138+
self.data = conversion::convert_module_data_sections(reader)?;
113139
}
114140
CodeSectionStart { count, range, .. } => {
115141
debug!("Found code section ({} functions)", count);
@@ -127,11 +153,19 @@ impl ModuleReader {
127153
.push(conversion::convert_module_code(function, func_validator)?);
128154
}
129155
ImportSection(reader) => {
156+
if !self.imports.is_empty() {
157+
return Err(ParseError::DuplicateSection("Import section".into()));
158+
}
159+
130160
debug!("Found import section");
131161
validator.import_section(&reader)?;
132162
self.imports = conversion::convert_module_imports(reader)?;
133163
}
134164
ExportSection(reader) => {
165+
if !self.exports.is_empty() {
166+
return Err(ParseError::DuplicateSection("Export section".into()));
167+
}
168+
135169
debug!("Found export section");
136170
validator.export_section(&reader)?;
137171
self.exports = reader

0 commit comments

Comments
 (0)