mirror of
https://github.com/gfx-rs/wgpu.git
synced 2026-04-22 03:02:01 -04:00
Add parsing states
This commit is contained in:
@@ -4,7 +4,7 @@ pub mod msl;
|
||||
mod parse;
|
||||
mod storage;
|
||||
|
||||
pub use parse::{parse, parse_u8_slice, ParseError};
|
||||
pub use parse::{Parser, ParseError, parse_u8_slice};
|
||||
|
||||
use crate::storage::{Storage, Token};
|
||||
|
||||
|
||||
140
src/parse.rs
140
src/parse.rs
@@ -3,27 +3,131 @@ use crate::storage::Storage;
|
||||
#[derive(Debug)]
|
||||
pub enum ParseError {
|
||||
InvalidHeader,
|
||||
InvalidWordCount,
|
||||
UnexpectedInstruction(ModuleState, spirv::Op),
|
||||
UnknownInstruction,
|
||||
InvalidOperandCount(spirv::Op, u16),
|
||||
IncompleteData,
|
||||
}
|
||||
|
||||
pub fn parse(mut data: impl Iterator<Item = u32>) -> Result<super::Module, ParseError> {
|
||||
let header = {
|
||||
if data.next().ok_or(ParseError::IncompleteData)? != spirv::MAGIC_NUMBER {
|
||||
return Err(ParseError::InvalidHeader);
|
||||
struct Instruction {
|
||||
op: spirv::Op,
|
||||
wc: u16,
|
||||
}
|
||||
|
||||
impl Instruction {
|
||||
fn expect(&self, count: u16) -> Result<(), ParseError> {
|
||||
if self.wc == count {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(ParseError::InvalidOperandCount(self.op, self.wc))
|
||||
}
|
||||
let version_raw = data.next().ok_or(ParseError::IncompleteData)?.to_le_bytes();
|
||||
super::Header {
|
||||
version: (version_raw[2], version_raw[1], version_raw[0]),
|
||||
generator: 0,
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
|
||||
pub enum ModuleState {
|
||||
Empty,
|
||||
Capability,
|
||||
Extension,
|
||||
ExtInstImport,
|
||||
MemoryModel,
|
||||
EntryPoint,
|
||||
ExecutionMode,
|
||||
Source,
|
||||
Name,
|
||||
ModuleProcessed,
|
||||
Annotation,
|
||||
Type,
|
||||
FunctionDecl,
|
||||
FunctionDef,
|
||||
}
|
||||
|
||||
pub struct Parser<I> {
|
||||
data: I,
|
||||
state: ModuleState,
|
||||
}
|
||||
|
||||
impl<I: Iterator<Item = u32>> Parser<I> {
|
||||
pub fn new(data: I) -> Self {
|
||||
Parser {
|
||||
data,
|
||||
state: ModuleState::Empty,
|
||||
}
|
||||
};
|
||||
Ok(super::Module {
|
||||
header,
|
||||
struct_declarations: Storage::new(),
|
||||
functions: Storage::new(),
|
||||
entry_points: Vec::new(),
|
||||
})
|
||||
}
|
||||
|
||||
fn next(&mut self) -> Result<u32, ParseError> {
|
||||
self.data.next().ok_or(ParseError::IncompleteData)
|
||||
}
|
||||
|
||||
fn next_inst(&mut self) -> Result<Instruction, ParseError> {
|
||||
const LAST_KNOWN_OPCODE: spirv::Op = spirv::Op::MemberDecorateStringGOOGLE;
|
||||
|
||||
let word = self.next()?;
|
||||
let (wc, opcode) = ((word >> 16) as u16, (word & 0xffff) as u16);
|
||||
if wc == 0 {
|
||||
return Err(ParseError::InvalidWordCount);
|
||||
}
|
||||
if opcode > LAST_KNOWN_OPCODE as u16 {
|
||||
return Err(ParseError::UnknownInstruction);
|
||||
}
|
||||
|
||||
Ok(Instruction {
|
||||
op: unsafe {
|
||||
std::mem::transmute(opcode as u32)
|
||||
},
|
||||
wc,
|
||||
})
|
||||
}
|
||||
|
||||
fn switch(&mut self, state: ModuleState, inst: &Instruction, word_count: u16) -> Result<(), ParseError> {
|
||||
if state < self.state {
|
||||
return Err(ParseError::UnexpectedInstruction(self.state, inst.op))
|
||||
} else {
|
||||
self.state = state;
|
||||
inst.expect(word_count)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse(&mut self) -> Result<super::Module, ParseError> {
|
||||
let header = {
|
||||
if self.next()? != spirv::MAGIC_NUMBER {
|
||||
return Err(ParseError::InvalidHeader);
|
||||
}
|
||||
let version_raw = self.next()?.to_le_bytes();
|
||||
let generator = self.next()?;
|
||||
let _bound = self.next()?;
|
||||
let _schema = self.next()?;
|
||||
super::Header {
|
||||
version: (version_raw[2], version_raw[1], version_raw[0]),
|
||||
generator,
|
||||
}
|
||||
};
|
||||
|
||||
while let Ok(inst) = self.next_inst() {
|
||||
use spirv::Op;
|
||||
match inst.op {
|
||||
Op::Capability => {
|
||||
self.switch(ModuleState::Capability, &inst, 2)?;
|
||||
let _capability = self.next()?;
|
||||
}
|
||||
Op::MemoryModel => {
|
||||
self.switch(ModuleState::MemoryModel, &inst, 3)?;
|
||||
let _addressing_model = self.next()?;
|
||||
let _memory_model = self.next()?;
|
||||
},
|
||||
_ => return Err(ParseError::UnexpectedInstruction(self.state, inst.op))
|
||||
//TODO
|
||||
}
|
||||
}
|
||||
|
||||
Ok(super::Module {
|
||||
header,
|
||||
struct_declarations: Storage::new(),
|
||||
functions: Storage::new(),
|
||||
entry_points: Vec::new(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_u8_slice(data: &[u8]) -> Result<super::Module, ParseError> {
|
||||
@@ -33,10 +137,10 @@ pub fn parse_u8_slice(data: &[u8]) -> Result<super::Module, ParseError> {
|
||||
return Err(ParseError::IncompleteData);
|
||||
}
|
||||
|
||||
parse(data
|
||||
let words = data
|
||||
.chunks(4)
|
||||
.map(|c| u32::from_le_bytes(c.try_into().unwrap()))
|
||||
)
|
||||
.map(|c| u32::from_le_bytes(c.try_into().unwrap()));
|
||||
Parser::new(words).parse()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
Reference in New Issue
Block a user