From f6912acdbd546c021412fb79f26da7f61ea2d9a8 Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Tue, 18 Feb 2020 17:27:12 -0500 Subject: [PATCH] Add parsing states --- src/lib.rs | 2 +- src/parse.rs | 140 ++++++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 123 insertions(+), 19 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 9165bec25e..ec39a4bf6c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -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}; diff --git a/src/parse.rs b/src/parse.rs index 08e482c180..77ed9d798f 100644 --- a/src/parse.rs +++ b/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) -> Result { - 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 { + data: I, + state: ModuleState, +} + +impl> Parser { + 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 { + self.data.next().ok_or(ParseError::IncompleteData) + } + + fn next_inst(&mut self) -> Result { + 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 { + 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 { @@ -33,10 +137,10 @@ pub fn parse_u8_slice(data: &[u8]) -> Result { 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)]