summaryrefslogtreecommitdiff
path: root/crates/parser/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/parser/src')
-rw-r--r--crates/parser/src/conversion.rs227
-rw-r--r--crates/parser/src/error.rs25
-rw-r--r--crates/parser/src/lib.rs73
-rw-r--r--crates/parser/src/module.rs181
4 files changed, 506 insertions, 0 deletions
diff --git a/crates/parser/src/conversion.rs b/crates/parser/src/conversion.rs
new file mode 100644
index 0000000..c75aaf1
--- /dev/null
+++ b/crates/parser/src/conversion.rs
@@ -0,0 +1,227 @@
+use alloc::{format, vec::Vec};
+use tinywasm_types::{BlockArgs, Instruction, MemArg, ValType};
+
+use crate::Result;
+
+fn convert_blocktype(blocktype: wasmparser::BlockType) -> BlockArgs {
+ use wasmparser::BlockType::*;
+ match blocktype {
+ Empty => BlockArgs::Empty,
+ Type(ty) => BlockArgs::Type(convert_valtype(ty)),
+ FuncType(ty) => BlockArgs::FuncType(ty),
+ }
+}
+
+fn convert_valtype(valtype: wasmparser::ValType) -> ValType {
+ use wasmparser::ValType::*;
+ match valtype {
+ I32 => ValType::I32,
+ I64 => ValType::I64,
+ F32 => ValType::F32,
+ F64 => ValType::F64,
+ V128 => ValType::V128,
+ FuncRef => ValType::FuncRef,
+ ExternRef => ValType::ExternRef,
+ }
+}
+
+fn convert_memarg(memarg: wasmparser::MemArg) -> MemArg {
+ MemArg {
+ offset: memarg.offset,
+ align: memarg.align,
+ }
+}
+
+pub fn process_operator(op: wasmparser::Operator<'_>) -> Result<Instruction> {
+ use wasmparser::Operator::*;
+ let v = match op {
+ Unreachable => Instruction::Unreachable,
+ Nop => Instruction::Nop,
+ Block { blockty } => Instruction::Block(convert_blocktype(blockty)),
+ Loop { blockty } => Instruction::Loop(convert_blocktype(blockty)),
+ If { blockty } => Instruction::If(convert_blocktype(blockty)),
+ Else => Instruction::Else,
+ End => Instruction::End,
+ Br { relative_depth } => Instruction::Br(relative_depth),
+ BrIf { relative_depth } => Instruction::BrIf(relative_depth),
+ BrTable { targets } => {
+ let default = targets.default();
+ let targets = targets
+ .targets()
+ .map(|t| Ok(t?))
+ .collect::<Result<Vec<u32>>>()?;
+
+ Instruction::BrTable(targets, default)
+ }
+ Return => Instruction::Return,
+ Call { function_index } => Instruction::Call(function_index),
+ CallIndirect {
+ type_index,
+ table_index,
+ ..
+ } => Instruction::CallIndirect(type_index, table_index),
+ Drop => Instruction::Drop,
+ Select => Instruction::Select,
+ LocalGet { local_index } => Instruction::LocalGet(local_index),
+ LocalSet { local_index } => Instruction::LocalSet(local_index),
+ LocalTee { local_index } => Instruction::LocalTee(local_index),
+ GlobalGet { global_index } => Instruction::GlobalGet(global_index),
+ GlobalSet { global_index } => Instruction::GlobalSet(global_index),
+ MemorySize { .. } => Instruction::MemorySize,
+ MemoryGrow { .. } => Instruction::MemoryGrow,
+ I32Load { memarg } => Instruction::I32Load(convert_memarg(memarg)),
+ I64Load { memarg } => Instruction::I64Load(convert_memarg(memarg)),
+ F32Load { memarg } => Instruction::F32Load(convert_memarg(memarg)),
+ F64Load { memarg } => Instruction::F64Load(convert_memarg(memarg)),
+ I32Load8S { memarg } => Instruction::I32Load8S(convert_memarg(memarg)),
+ I32Load8U { memarg } => Instruction::I32Load8U(convert_memarg(memarg)),
+ I32Load16S { memarg } => Instruction::I32Load16S(convert_memarg(memarg)),
+ I32Load16U { memarg } => Instruction::I32Load16U(convert_memarg(memarg)),
+ I64Load8S { memarg } => Instruction::I64Load8S(convert_memarg(memarg)),
+ I64Load8U { memarg } => Instruction::I64Load8U(convert_memarg(memarg)),
+ I64Load16S { memarg } => Instruction::I64Load16S(convert_memarg(memarg)),
+ I64Load16U { memarg } => Instruction::I64Load16U(convert_memarg(memarg)),
+ I64Load32S { memarg } => Instruction::I64Load32S(convert_memarg(memarg)),
+ I64Load32U { memarg } => Instruction::I64Load32U(convert_memarg(memarg)),
+ I32Store { memarg } => Instruction::I32Store(convert_memarg(memarg)),
+ I64Store { memarg } => Instruction::I64Store(convert_memarg(memarg)),
+ F32Store { memarg } => Instruction::F32Store(convert_memarg(memarg)),
+ F64Store { memarg } => Instruction::F64Store(convert_memarg(memarg)),
+ I32Store8 { memarg } => Instruction::I32Store8(convert_memarg(memarg)),
+ I32Store16 { memarg } => Instruction::I32Store16(convert_memarg(memarg)),
+ I64Store8 { memarg } => Instruction::I64Store8(convert_memarg(memarg)),
+ I64Store16 { memarg } => Instruction::I64Store16(convert_memarg(memarg)),
+ I64Store32 { memarg } => Instruction::I64Store32(convert_memarg(memarg)),
+ I32Eqz => Instruction::I32Eqz,
+ I32Eq => Instruction::I32Eq,
+ I32Ne => Instruction::I32Ne,
+ I32LtS => Instruction::I32LtS,
+ I32LtU => Instruction::I32LtU,
+ I32GtS => Instruction::I32GtS,
+ I32GtU => Instruction::I32GtU,
+ I32LeS => Instruction::I32LeS,
+ I32LeU => Instruction::I32LeU,
+ I32GeS => Instruction::I32GeS,
+ I32GeU => Instruction::I32GeU,
+ I64Eqz => Instruction::I64Eqz,
+ I64Eq => Instruction::I64Eq,
+ I64Ne => Instruction::I64Ne,
+ I64LtS => Instruction::I64LtS,
+ I64LtU => Instruction::I64LtU,
+ I64GtS => Instruction::I64GtS,
+ I64GtU => Instruction::I64GtU,
+ I64LeS => Instruction::I64LeS,
+ I64LeU => Instruction::I64LeU,
+ I64GeS => Instruction::I64GeS,
+ I64GeU => Instruction::I64GeU,
+ F32Eq => Instruction::F32Eq,
+ F32Ne => Instruction::F32Ne,
+ F32Lt => Instruction::F32Lt,
+ F32Gt => Instruction::F32Gt,
+ F32Le => Instruction::F32Le,
+ F32Ge => Instruction::F32Ge,
+ F64Eq => Instruction::F64Eq,
+ F64Ne => Instruction::F64Ne,
+ F64Lt => Instruction::F64Lt,
+ F64Gt => Instruction::F64Gt,
+ F64Le => Instruction::F64Le,
+ F64Ge => Instruction::F64Ge,
+ I32Clz => Instruction::I32Clz,
+ I32Ctz => Instruction::I32Ctz,
+ I32Popcnt => Instruction::I32Popcnt,
+ I32Add => Instruction::I32Add,
+ I32Sub => Instruction::I32Sub,
+ I32Mul => Instruction::I32Mul,
+ I32DivS => Instruction::I32DivS,
+ I32DivU => Instruction::I32DivU,
+ I32RemS => Instruction::I32RemS,
+ I32RemU => Instruction::I32RemU,
+ I32And => Instruction::I32And,
+ I32Or => Instruction::I32Or,
+ I32Xor => Instruction::I32Xor,
+ I32Shl => Instruction::I32Shl,
+ I32ShrS => Instruction::I32ShrS,
+ I32ShrU => Instruction::I32ShrU,
+ I32Rotl => Instruction::I32Rotl,
+ I32Rotr => Instruction::I32Rotr,
+ I64Clz => Instruction::I64Clz,
+ I64Ctz => Instruction::I64Ctz,
+ I64Popcnt => Instruction::I64Popcnt,
+ I64Add => Instruction::I64Add,
+ I64Sub => Instruction::I64Sub,
+ I64Mul => Instruction::I64Mul,
+ I64DivS => Instruction::I64DivS,
+ I64DivU => Instruction::I64DivU,
+ I64RemS => Instruction::I64RemS,
+ I64RemU => Instruction::I64RemU,
+ I64And => Instruction::I64And,
+ I64Or => Instruction::I64Or,
+ I64Xor => Instruction::I64Xor,
+ I64Shl => Instruction::I64Shl,
+ I64ShrS => Instruction::I64ShrS,
+ I64ShrU => Instruction::I64ShrU,
+ I64Rotl => Instruction::I64Rotl,
+ I64Rotr => Instruction::I64Rotr,
+ F32Abs => Instruction::F32Abs,
+ F32Neg => Instruction::F32Neg,
+ F32Ceil => Instruction::F32Ceil,
+ F32Floor => Instruction::F32Floor,
+ F32Trunc => Instruction::F32Trunc,
+ F32Nearest => Instruction::F32Nearest,
+ F32Sqrt => Instruction::F32Sqrt,
+ F32Add => Instruction::F32Add,
+ F32Sub => Instruction::F32Sub,
+ F32Mul => Instruction::F32Mul,
+ F32Div => Instruction::F32Div,
+ F32Min => Instruction::F32Min,
+ F32Max => Instruction::F32Max,
+ F32Copysign => Instruction::F32Copysign,
+ F64Abs => Instruction::F64Abs,
+ F64Neg => Instruction::F64Neg,
+ F64Ceil => Instruction::F64Ceil,
+ F64Floor => Instruction::F64Floor,
+ F64Trunc => Instruction::F64Trunc,
+ F64Nearest => Instruction::F64Nearest,
+ F64Sqrt => Instruction::F64Sqrt,
+ F64Add => Instruction::F64Add,
+ F64Sub => Instruction::F64Sub,
+ F64Mul => Instruction::F64Mul,
+ F64Div => Instruction::F64Div,
+ F64Min => Instruction::F64Min,
+ F64Max => Instruction::F64Max,
+ F64Copysign => Instruction::F64Copysign,
+ I32WrapI64 => Instruction::I32WrapI64,
+ I32TruncF32S => Instruction::I32TruncF32S,
+ I32TruncF32U => Instruction::I32TruncF32U,
+ I32TruncF64S => Instruction::I32TruncF64S,
+ I32TruncF64U => Instruction::I32TruncF64U,
+ I64ExtendI32S => Instruction::I64ExtendI32S,
+ I64ExtendI32U => Instruction::I64ExtendI32U,
+ I64TruncF32S => Instruction::I64TruncF32S,
+ I64TruncF32U => Instruction::I64TruncF32U,
+ I64TruncF64S => Instruction::I64TruncF64S,
+ I64TruncF64U => Instruction::I64TruncF64U,
+ F32ConvertI32S => Instruction::F32ConvertI32S,
+ F32ConvertI32U => Instruction::F32ConvertI32U,
+ F32ConvertI64S => Instruction::F32ConvertI64S,
+ F32ConvertI64U => Instruction::F32ConvertI64U,
+ F32DemoteF64 => Instruction::F32DemoteF64,
+ F64ConvertI32S => Instruction::F64ConvertI32S,
+ F64ConvertI32U => Instruction::F64ConvertI32U,
+ F64ConvertI64S => Instruction::F64ConvertI64S,
+ F64ConvertI64U => Instruction::F64ConvertI64U,
+ F64PromoteF32 => Instruction::F64PromoteF32,
+ I32ReinterpretF32 => Instruction::I32ReinterpretF32,
+ I64ReinterpretF64 => Instruction::I64ReinterpretF64,
+ F32ReinterpretI32 => Instruction::F32ReinterpretI32,
+ F64ReinterpretI64 => Instruction::F64ReinterpretI64,
+ _ => {
+ return Err(crate::ParseError::UnsupportedOperator(format!(
+ "Unsupported instruction: {:?}",
+ op
+ )))
+ }
+ };
+
+ Ok(v)
+}
diff --git a/crates/parser/src/error.rs b/crates/parser/src/error.rs
new file mode 100644
index 0000000..c99fa01
--- /dev/null
+++ b/crates/parser/src/error.rs
@@ -0,0 +1,25 @@
+use alloc::string::{String, ToString};
+use wasmparser::Encoding;
+
+pub enum ParseError {
+ UnsupportedSection(String),
+ DuplicateSection(String),
+ EmptySection(String),
+ UnsupportedOperator(String),
+ ParseError { message: String, offset: usize },
+ InvalidEncoding(Encoding),
+ InvalidLocalCount { expected: u32, actual: u32 },
+ EndNotReached,
+ Other(String),
+}
+
+impl From<wasmparser::BinaryReaderError> for ParseError {
+ fn from(value: wasmparser::BinaryReaderError) -> Self {
+ Self::ParseError {
+ message: value.message().to_string(),
+ offset: value.offset(),
+ }
+ }
+}
+
+pub type Result<T, E = ParseError> = core::result::Result<T, E>;
diff --git a/crates/parser/src/lib.rs b/crates/parser/src/lib.rs
new file mode 100644
index 0000000..39bb1c6
--- /dev/null
+++ b/crates/parser/src/lib.rs
@@ -0,0 +1,73 @@
+#![no_std]
+#![forbid(unsafe_code)]
+#![cfg_attr(not(feature = "std"), feature(error_in_core))]
+
+extern crate alloc;
+#[cfg(feature = "std")]
+extern crate std;
+
+mod conversion;
+mod error;
+mod module;
+use alloc::boxed::Box;
+pub use error::*;
+use module::ModuleReader;
+use tinywasm_types::{Export, FuncType, Function};
+
+pub struct Parser {}
+
+impl Parser {
+ pub fn parse_module_bytes(wasm: &[u8]) -> Result<TinyWasmModule> {
+ let reader = ModuleReader::new();
+ reader.try_into()
+ }
+
+ pub fn parse_module_file(file_name: &str) -> Result<TinyWasmModule> {
+ let reader = ModuleReader::new();
+ reader.try_into()
+ }
+
+ #[cfg(feature = "std")]
+ pub fn parse_module_stream(stream: impl std::io::Read) -> Result<TinyWasmModule> {
+ let reader = ModuleReader::new();
+ reader.try_into()
+ }
+
+ pub fn read_module_bytes(bytes: &[u8]) -> Result<TinyWasmModule> {
+ unimplemented!()
+ }
+ pub fn read_module_file(file_name: &str) -> Result<TinyWasmModule> {
+ unimplemented!()
+ }
+ #[cfg(feature = "std")]
+ pub fn read_module_stream(stream: impl std::io::Read) -> Result<TinyWasmModule> {
+ unimplemented!()
+ }
+}
+
+pub struct TinyWasmModule {
+ pub version: Option<u16>,
+ pub start_func: Option<u32>,
+
+ pub types: Option<Box<[FuncType]>>,
+ pub funcs: Option<Box<[Function]>>,
+ pub exports: Option<Box<[Export]>>,
+ // pub tables: Option<TableType>,
+ // pub memories: Option<MemoryType>,
+ // pub globals: Option<GlobalType>,
+ // pub elements: Option<ElementSectionReader<'a>>,
+ // pub imports: Option<ImportSectionReader<'a>>,
+ // pub data_segments: Option<DataSectionReader<'a>>,
+}
+
+impl TryFrom<ModuleReader<'_>> for TinyWasmModule {
+ type Error = ParseError;
+
+ fn try_from(reader: ModuleReader<'_>) -> Result<Self> {
+ if !reader.end_reached {
+ return Err(ParseError::EndNotReached);
+ }
+
+ unimplemented!()
+ }
+}
diff --git a/crates/parser/src/module.rs b/crates/parser/src/module.rs
new file mode 100644
index 0000000..e2e1bde
--- /dev/null
+++ b/crates/parser/src/module.rs
@@ -0,0 +1,181 @@
+use alloc::{format, vec::Vec};
+use core::fmt::Debug;
+use tracing::debug;
+use wasmparser::{
+ ExportSectionReader, FunctionBody, FunctionSectionReader, Payload, TypeSectionReader, Validator,
+};
+
+use crate::{ParseError, Result};
+
+#[derive(Default)]
+pub struct ModuleReader<'a> {
+ pub version: Option<u16>,
+ pub start_func: Option<u32>,
+
+ pub type_section: Option<TypeSectionReader<'a>>,
+ pub function_section: Option<FunctionSectionReader<'a>>,
+ pub export_section: Option<ExportSectionReader<'a>>,
+ pub code_section: Option<CodeSection<'a>>,
+
+ // pub table_section: Option<TableSectionReader<'a>>,
+ // pub memory_section: Option<MemorySectionReader<'a>>,
+ // pub global_section: Option<GlobalSectionReader<'a>>,
+ // pub element_section: Option<ElementSectionReader<'a>>,
+ // pub data_section: Option<DataSectionReader<'a>>,
+ // pub import_section: Option<ImportSectionReader<'a>>,
+ pub end_reached: bool,
+}
+
+impl Debug for ModuleReader<'_> {
+ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+ f.debug_struct("ModuleReader")
+ .field("version", &self.version)
+ .field("type_section", &self.type_section)
+ .field("function_section", &self.function_section)
+ .field("code_section", &self.code_section)
+ .field("export_section", &self.export_section)
+ // .field("table_section", &self.table_section)
+ // .field("memory_section", &self.memory_section)
+ // .field("global_section", &self.global_section)
+ // .field("element_section", &self.element_section)
+ // .field("data_section", &self.data_section)
+ // .field("import_section", &self.import_section)
+ .finish()
+ }
+}
+
+impl<'a> ModuleReader<'a> {
+ pub fn new() -> ModuleReader<'a> {
+ Self::default()
+ }
+
+ pub fn process_payload(
+ &mut self,
+ payload: Payload<'a>,
+ validator: &mut Validator,
+ ) -> Result<()> {
+ use wasmparser::Payload::*;
+
+ match payload {
+ Version {
+ num,
+ encoding,
+ range,
+ } => {
+ validator.version(num, encoding, &range)?;
+ self.version = Some(num);
+ match encoding {
+ wasmparser::Encoding::Module => {}
+ wasmparser::Encoding::Component => {
+ return Err(ParseError::InvalidEncoding(encoding))
+ }
+ }
+ }
+ StartSection { func, range } => {
+ debug!("Found start section");
+ validator.start_section(func, &range)?;
+ self.start_func = Some(func);
+ }
+ TypeSection(reader) => {
+ debug!("Found type section");
+ validator.type_section(&reader)?;
+ self.type_section = Some(reader);
+ }
+ FunctionSection(reader) => {
+ debug!("Found function section");
+ validator.function_section(&reader)?;
+ self.function_section = Some(reader);
+ }
+ TableSection(_reader) => {
+ return Err(ParseError::UnsupportedSection("Table section".into()));
+ // debug!("Found table section");
+ // validator.table_section(&reader)?;
+ // self.table_section = Some(reader);
+ }
+ MemorySection(_reader) => {
+ return Err(ParseError::UnsupportedSection("Memory section".into()));
+ // debug!("Found memory section");
+ // validator.memory_section(&reader)?;
+ // self.memory_section = Some(reader);
+ }
+ GlobalSection(_reader) => {
+ return Err(ParseError::UnsupportedSection("Global section".into()));
+ // debug!("Found global section");
+ // validator.global_section(&reader)?;
+ // self.global_section = Some(reader);
+ }
+ ElementSection(_reader) => {
+ return Err(ParseError::UnsupportedSection("Element section".into()));
+ // debug!("Found element section");
+ // validator.element_section(&reader)?;
+ // self.element_section = Some(reader);
+ }
+ DataSection(_reader) => {
+ return Err(ParseError::UnsupportedSection("Data section".into()));
+ // debug!("Found data section");
+ // validator.data_section(&reader)?;
+ // self.data_section = Some(reader);
+ }
+ CodeSectionStart { count, range, .. } => {
+ debug!("Found code section ({} functions)", count);
+ if self.code_section.is_some() {
+ return Err(ParseError::DuplicateSection("Code section".into()));
+ }
+
+ validator.code_section_start(count, &range)?;
+ self.code_section = Some(CodeSection::new());
+ }
+ CodeSectionEntry(function) => {
+ debug!("Found code section entry");
+ validator.code_section_entry(&function)?;
+
+ if let Some(code_section) = &mut self.code_section {
+ code_section.functions.push(function);
+ } else {
+ return Err(ParseError::EmptySection("Code section".into()));
+ }
+ }
+ ImportSection(_reader) => {
+ return Err(ParseError::UnsupportedSection("Import section".into()));
+
+ // debug!("Found import section");
+ // validator.import_section(&reader)?;
+ // self.import_section = Some(reader);
+ }
+ ExportSection(reader) => {
+ debug!("Found export section");
+ validator.export_section(&reader)?;
+ self.export_section = Some(reader);
+ }
+ End(offset) => {
+ debug!("Reached end of module");
+ if self.end_reached {
+ return Err(ParseError::DuplicateSection("End section".into()));
+ }
+
+ validator.end(offset)?;
+ self.end_reached = true;
+ }
+ UnknownSection { .. } | _ => {
+ return Err(ParseError::UnsupportedSection(format!("Unknown section")))
+ }
+ };
+
+ Ok(())
+ }
+}
+
+/// A WebAssembly code section
+/// Can be cloned to read functions multiple times
+#[derive(Debug, Clone)]
+pub struct CodeSection<'a> {
+ pub(crate) functions: Vec<FunctionBody<'a>>,
+}
+
+impl<'a> CodeSection<'a> {
+ fn new() -> Self {
+ Self {
+ functions: Vec::new(),
+ }
+ }
+}