1use core::{
2 fmt::{Display, self},
3 error::Error,
4 slice,
5};
6
7use crate::{
8 stream::*,
9 op,
10 core::*,
11};
12
13#[derive(Debug)]
17pub enum ParseError {
18 EndOfStream,
19 InvalidType {
20 expected: &'static str,
21 found: op::Code,
22 },
23 UnknownOpCode(op::Code),
24 WrongOpCode {
25 expected: &'static str,
26 found: op::Code,
27 },
28 InvalidIdResult(op::IdRef),
29 ExpectedTypeDeclaration(op::IdRef),
30 ExpectedContextResultType,
31 InvalidIntLiteralWidth(u32),
32 InvalidFloatLiteralWidth(u32),
33 UnknownVariant {
34 kind: &'static str,
35 value: u32,
36 },
37 InvalidPairWordCount(u32),
38}
39
40#[derive(Clone)]
41pub struct ResultStorage<'a> {
42 data: Vec<Option<InstructionStream<'a>>>,
43}
44
45impl Default for ResultStorage<'_> {
46
47 #[inline]
48 fn default() -> Self {
49 Self {
50 data: vec![],
51 }
52 }
53}
54
55impl<'a> ResultStorage<'a>
56{
57
58 #[inline]
59 pub fn insert(&mut self,
60 id: op::IdResult,
61 mut stream: InstructionStream<'a>
62 )
63 {
64 stream.reset();
65 let idx = id.0 as usize;
66 if idx >= self.data.len() {
67 self.data.resize_with(idx + 1, || None);
68 }
69 self.data[idx] = Some(stream);
70 }
71
72 #[inline]
73 pub fn get(&self, id: op::IdRef) -> Option<InstructionStream<'a>> {
74 self.data.get(id.0 as usize)
75 .and_then(|&value| value)
76 }
77
78 #[inline]
79 pub fn contains(&self, id: op::IdRef) -> bool {
80 self.data.get(id.0 as usize)
81 .and_then(|value| value.as_ref())
82 .is_some()
83 }
84}
85
86#[derive(Clone)]
87pub struct Module<'a> {
88 stream: Stream<'a>,
89 results: ResultStorage<'a>,
90}
91
92pub type ParseResult<T> = Result<T, ParseError>;
93
94impl<'a> Module<'a> {
95
96 #[inline]
97 pub fn new(spirv: &'a [u32]) -> Self {
98 Self {
99 stream: Stream::new(spirv),
100 results: Default::default(),
101 }
102 }
103
104 #[inline]
105 pub fn parse_next(&mut self) -> ParseResult<bool> {
106 let Some(mut instruction) = self.stream
107 .next()
108 else {
109 return Ok(false)
110 };
111 let inst_info = op::INST_INFOS[instruction.code().0 as usize];
112 if inst_info.has_id_result {
113 if inst_info.has_id_result_type {
114 let _ = instruction.read()?;
115 }
116 let id = op::IdResult(instruction.read()?);
117 self.results.insert(
118 id,
119 instruction,
120 );
121 }
122 Ok(true)
123 }
124
125 #[inline]
126 pub fn parse_full(&mut self) -> ParseResult<()> {
127 while self.parse_next()? {}
128 Ok(())
129 }
130
131 #[inline]
132 pub fn all_instructions(&self) -> impl Iterator<Item = InstructionStream<'a>> {
133 let mut stream = self.stream;
134 stream.reset();
135 stream
136 }
137
138 #[inline]
139 pub fn remaining_instructions(&self) -> impl Iterator<Item = InstructionStream<'a>> {
140 self.stream
141 }
142
143 #[inline]
144 pub fn results(&self) -> impl Iterator<Item = (op::IdRef, InstructionStream<'a>)> {
145 self.results.data
146 .iter()
147 .enumerate()
148 .filter_map(|(i, result)| {
149 result
150 .map(|result| (op::IdRef::from_word(i as u32), result))
151 })
152 }
153
154 #[inline]
155 pub fn get_result(&self, id: op::IdRef) -> Option<InstructionStream<'a>> {
156 self.results.get(id)
157 }
158}
159
160#[derive(Default, Clone, Copy)]
161pub struct ParseContext {
162 pub result_type: Option<op::IdResultType>,
163}
164
165pub trait WordExt<'a>: Word {
166
167 #[inline]
168 fn parse_one(
169 stream: &mut InstructionStream<'a>,
170 ) -> ParseResult<Self> {
171 Ok(Self::from_word(stream.read()?))
172 }
173
174 #[inline]
175 fn parse_optional(
176 stream: &mut InstructionStream<'a>,
177 ) -> ParseResult<Option<Self>> {
178 if stream.is_eos() {
179 Ok(None)
180 } else {
181 Ok(Some(Self::from_word(stream.read()?)))
182 }
183 }
184
185 #[inline]
186 fn parse_eos(
187 stream: &mut InstructionStream<'a>,
188 ) -> ParseResult<&'a [Self]> {
189 let words = stream.read_words(None)?;
190 Ok(unsafe {
191 slice::from_raw_parts(
192 words.as_ptr().cast(),
193 words.len(),
194 )
195 })
196 }
197}
198
199impl<'a, T: Word> WordExt<'a> for T {}
200
201impl<'a> CompilerStr<'a> {
202
203 #[inline]
204 pub fn parse_one(
205 stream: &mut InstructionStream<'a>,
206 ) -> ParseResult<Self> {
207 stream.read_string()
208 }
209
210 #[inline]
211 pub fn parse_optional(
212 stream: &mut InstructionStream<'a>,
213 ) -> ParseResult<Option<Self>> {
214 if stream.is_eos() {
215 Ok(None)
216 } else {
217 Ok(Some(stream.read_string()?))
218 }
219 }
220}
221
222impl Display for ParseError {
223
224 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
225 match self {
226 Self::EndOfStream => write!(f, "end of stream"),
227 Self::InvalidType { expected, found } => write!(f,
228 "invalid type; expected {expected}, found {found}",
229 ),
230 Self::UnknownOpCode(code) => write!(f,
231 "unknown op code {code}"
232 ),
233 Self::WrongOpCode { expected, found } => write!(f,
234 "wrong op code; expected {expected}, found {found}",
235 ),
236 Self::InvalidIdResult(id) => write!(f,
237 "invalid id result {id}",
238 ),
239 Self::ExpectedTypeDeclaration(id) => write!(f,
240 "expected type declaration, found id {id}",
241 ),
242 Self::ExpectedContextResultType => write!(f,
243 "expected context result type, found None",
244 ),
245 Self::InvalidIntLiteralWidth(width) => write!(f,
246 "invalid int literal width {width}",
247 ),
248 Self::InvalidFloatLiteralWidth(width) => write!(f,
249 "invalid float literal width {width}",
250 ),
251 Self::UnknownVariant { kind, value } => write!(f,
252 "unknown {kind} variant {value}",
253 ),
254 Self::InvalidPairWordCount(count) => write!(f,
255 "invalid pair word count {count}: count is not a multiple of 2"
256 ),
257 }
258 }
259}
260
261impl Error for ParseError {}