e94d799d2ce991e01f68170fc895eb8de897029f
[kazan.git] / spirv-parser-generator / src / generate.rs
1 // SPDX-License-Identifier: LGPL-2.1-or-later
2 // Copyright 2018 Jacob Lifshay
3
4 use ast;
5 use proc_macro2;
6 use std::borrow::Cow;
7 use std::collections::HashMap;
8 use std::fmt;
9 use std::io::{self, Read, Write};
10 use std::process::{Child, Command, ExitStatus, Stdio};
11 use std::thread;
12 use util::{self, NameFormat::*};
13 use which;
14 use Error;
15 use Options;
16
17 #[derive(Debug)]
18 enum FormatError {
19 IOError(io::Error),
20 WhichError(which::Error),
21 RustFmtFailed(ExitStatus),
22 }
23
24 impl fmt::Display for FormatError {
25 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
26 match self {
27 FormatError::IOError(v) => fmt::Display::fmt(v, f),
28 FormatError::WhichError(v) => fmt::Display::fmt(v, f),
29 FormatError::RustFmtFailed(v) => write!(f, "rustfmt failed: {:?}", v),
30 }
31 }
32 }
33
34 impl From<which::Error> for FormatError {
35 fn from(v: which::Error) -> Self {
36 FormatError::WhichError(v)
37 }
38 }
39
40 impl From<io::Error> for FormatError {
41 fn from(v: io::Error) -> Self {
42 FormatError::IOError(v)
43 }
44 }
45
46 fn format_source<'a>(options: &Options, source: &'a str) -> Result<Cow<'a, str>, FormatError> {
47 if !options.run_rustfmt {
48 return Ok(Cow::Borrowed(source));
49 }
50 let rustfmt_path = match options.rustfmt_path.clone() {
51 Some(v) => v,
52 None => which::which("rustfmt")?,
53 };
54 let mut command = Command::new(rustfmt_path)
55 .stdin(Stdio::piped())
56 .stdout(Stdio::piped())
57 .spawn()?;
58 let stdin = command.stdin.take().unwrap();
59 let reader_thread = thread::spawn(move || -> io::Result<(String, Child)> {
60 let mut output = String::new();
61 command.stdout.take().unwrap().read_to_string(&mut output)?;
62 Ok((output, command))
63 });
64 { stdin }.write_all(source.as_bytes())?;
65 let (output, mut command) = reader_thread.join().unwrap()?;
66 let exit_status = command.wait()?;
67 if exit_status.success() {
68 Ok(Cow::Owned(output))
69 } else {
70 Err(FormatError::RustFmtFailed(exit_status))
71 }
72 }
73
74 fn remove_initial_op(name: &str) -> &str {
75 const INITIAL_OP: &str = "Op";
76 assert!(name.starts_with(INITIAL_OP));
77 &name[INITIAL_OP.len()..]
78 }
79
80 fn new_id<T: AsRef<str>>(name: T, name_format: util::NameFormat) -> proc_macro2::Ident {
81 proc_macro2::Ident::new(
82 &name_format
83 .name_from_words(util::WordIterator::new(name.as_ref()))
84 .unwrap(),
85 proc_macro2::Span::call_site(),
86 )
87 }
88
89 fn new_enumerant_id<T1: AsRef<str>, T2: AsRef<str>>(
90 enum_name: T1,
91 enumerant_name: T2,
92 ) -> proc_macro2::Ident {
93 let enumerant_name_words = util::WordIterator::new(enumerant_name.as_ref());
94 let enumerant_name_first_word = enumerant_name_words.clone().next();
95 let name = if enumerant_name_first_word
96 .map(str::chars)
97 .as_mut()
98 .and_then(Iterator::next)
99 .filter(char::is_ascii_digit)
100 .is_some()
101 {
102 CamelCase
103 .name_from_words(
104 util::WordIterator::new(enum_name.as_ref()).chain(enumerant_name_words),
105 )
106 .unwrap()
107 } else {
108 CamelCase.name_from_words(enumerant_name_words).unwrap()
109 };
110 proc_macro2::Ident::new(&name, proc_macro2::Span::call_site())
111 }
112
113 fn new_combined_id<I: IntoIterator>(names: I, name_format: util::NameFormat) -> proc_macro2::Ident
114 where
115 I::Item: AsRef<str>,
116 {
117 let names: Vec<I::Item> = names.into_iter().collect();
118 proc_macro2::Ident::new(
119 &name_format
120 .name_from_words(
121 names
122 .iter()
123 .map(AsRef::as_ref)
124 .flat_map(util::WordIterator::new),
125 )
126 .unwrap(),
127 proc_macro2::Span::call_site(),
128 )
129 }
130
131 #[cfg_attr(feature = "cargo-clippy", allow(clippy::cyclomatic_complexity))]
132 pub(crate) fn generate(
133 core_grammar: ast::CoreGrammar,
134 parsed_extension_instruction_sets: HashMap<
135 super::ExtensionInstructionSet,
136 ast::ExtensionInstructionSet,
137 >,
138 options: &Options,
139 ) -> Result<String, Error> {
140 let mut out = Vec::new();
141 let ast::CoreGrammar {
142 copyright: core_grammar_copyright,
143 magic_number,
144 major_version,
145 minor_version,
146 revision: core_revision,
147 instructions: core_instructions,
148 operand_kinds,
149 } = core_grammar;
150 writeln!(&mut out, "// automatically generated file")?;
151 writeln!(&mut out, "//")?;
152 for i in &core_grammar_copyright {
153 assert_eq!(i.find('\r'), None);
154 assert_eq!(i.find('\n'), None);
155 if i == "" {
156 writeln!(&mut out, "//");
157 } else {
158 writeln!(&mut out, "// {}", i);
159 }
160 }
161 writeln!(
162 &mut out,
163 "{}",
164 stringify!(
165 use std::result;
166 use std::error;
167 use std::fmt;
168 use std::mem;
169 use std::str::Utf8Error;
170 use std::string::FromUtf8Error;
171
172 trait SPIRVParse: Sized {
173 fn spirv_parse<'a>(words: &'a [u32], parse_state: &mut ParseState)
174 -> Result<(Self, &'a [u32])>;
175 }
176
177 impl<T: SPIRVParse> SPIRVParse for Option<T> {
178 fn spirv_parse<'a>(
179 words: &'a [u32],
180 parse_state: &mut ParseState,
181 ) -> Result<(Self, &'a [u32])> {
182 if words.is_empty() {
183 Ok((None, words))
184 } else {
185 let (value, words) = T::spirv_parse(words, parse_state)?;
186 Ok((Some(value), words))
187 }
188 }
189 }
190
191 impl<T: SPIRVParse> SPIRVParse for Vec<T> {
192 fn spirv_parse<'a>(
193 mut words: &'a [u32],
194 parse_state: &mut ParseState,
195 ) -> Result<(Self, &'a [u32])> {
196 let mut retval = Vec::new();
197 while !words.is_empty() {
198 let result = T::spirv_parse(words, parse_state)?;
199 words = result.1;
200 retval.push(result.0);
201 }
202 Ok((retval, words))
203 }
204 }
205
206 impl<A: SPIRVParse, B: SPIRVParse> SPIRVParse for (A, B) {
207 fn spirv_parse<'a>(
208 words: &'a [u32],
209 parse_state: &mut ParseState,
210 ) -> Result<(Self, &'a [u32])> {
211 let (a, words) = A::spirv_parse(words, parse_state)?;
212 let (b, words) = B::spirv_parse(words, parse_state)?;
213 Ok(((a, b), words))
214 }
215 }
216
217 const BYTES_PER_WORD: usize = 4;
218
219 struct ByteIterator<'a> {
220 current_word: [u8; BYTES_PER_WORD],
221 current_word_index: usize,
222 words: &'a [u32],
223 }
224
225 impl<'a> ByteIterator<'a> {
226 fn new(words: &'a [u32]) -> Self {
227 Self {
228 current_word: [0; BYTES_PER_WORD],
229 current_word_index: BYTES_PER_WORD,
230 words,
231 }
232 }
233 fn take_unread_words(&mut self) -> &'a [u32] {
234 mem::replace(&mut self.words, &[])
235 }
236 }
237
238 impl<'a> Iterator for ByteIterator<'a> {
239 type Item = u8;
240 fn next(&mut self) -> Option<u8> {
241 if self.current_word_index >= BYTES_PER_WORD {
242 let (&current_word, words) = self.words.split_first()?;
243 self.words = words;
244 self.current_word = unsafe { mem::transmute(current_word.to_le()) };
245 self.current_word_index = 0;
246 }
247 let byte = self.current_word[self.current_word_index];
248 self.current_word_index += 1;
249 Some(byte)
250 }
251 }
252
253 impl SPIRVParse for String {
254 fn spirv_parse<'a>(
255 words: &'a [u32],
256 _parse_state: &mut ParseState,
257 ) -> Result<(Self, &'a [u32])> {
258 let mut byte_count_excluding_null_terminator = None;
259 for (index, byte) in ByteIterator::new(words).enumerate() {
260 if byte == 0 {
261 byte_count_excluding_null_terminator = Some(index);
262 break;
263 }
264 }
265 let byte_count_excluding_null_terminator =
266 byte_count_excluding_null_terminator.ok_or(Error::InstructionPrematurelyEnded)?;
267 let mut bytes = Vec::with_capacity(byte_count_excluding_null_terminator);
268 let mut byte_iter = ByteIterator::new(words);
269 for _ in 0..byte_count_excluding_null_terminator {
270 let byte = byte_iter.next().unwrap();
271 bytes.push(byte);
272 }
273 let _null_terminator = byte_iter.next().unwrap();
274 let words = byte_iter.take_unread_words();
275 for v in byte_iter {
276 if v != 0 {
277 return Err(Error::InvalidStringTermination);
278 }
279 }
280 assert_eq!(bytes.len(), byte_count_excluding_null_terminator);
281 Ok((String::from_utf8(bytes)?, words))
282 }
283 }
284
285 impl SPIRVParse for u32 {
286 fn spirv_parse<'a>(
287 words: &'a [u32],
288 _parse_state: &mut ParseState,
289 ) -> Result<(Self, &'a [u32])> {
290 let (&value, words) = words
291 .split_first()
292 .ok_or(Error::InstructionPrematurelyEnded)?;
293 Ok((value, words))
294 }
295 }
296
297 impl SPIRVParse for u64 {
298 fn spirv_parse<'a>(
299 words: &'a [u32],
300 _parse_state: &mut ParseState,
301 ) -> Result<(Self, &'a [u32])> {
302 let (&low, words) = words
303 .split_first()
304 .ok_or(Error::InstructionPrematurelyEnded)?;
305 let (&high, words) = words
306 .split_first()
307 .ok_or(Error::InstructionPrematurelyEnded)?;
308 Ok((((high as u64) << 32) | low as u64, words))
309 }
310 }
311
312 impl SPIRVParse for IdRef {
313 fn spirv_parse<'a>(
314 words: &'a [u32],
315 parse_state: &mut ParseState,
316 ) -> Result<(Self, &'a [u32])> {
317 let (value, words) = u32::spirv_parse(words, parse_state)?;
318 if value == 0 || value as usize >= parse_state.id_states.len() {
319 Err(Error::IdOutOfBounds(value))
320 } else {
321 Ok((IdRef(value), words))
322 }
323 }
324 }
325 )
326 )?;
327 writeln!(
328 &mut out,
329 "{}",
330 quote!{
331 pub const MAGIC_NUMBER: u32 = #magic_number;
332 pub const MAJOR_VERSION: u32 = #major_version;
333 pub const MINOR_VERSION: u32 = #minor_version;
334 pub const REVISION: u32 = #core_revision;
335 }
336 )?;
337 for operand_kind in &operand_kinds {
338 match operand_kind {
339 ast::OperandKind::BitEnum { kind, enumerants } => {
340 let kind_id = new_id(kind, CamelCase);
341 let mut enumerant_members = Vec::new();
342 let mut enumerant_member_names = Vec::new();
343 let mut enumerant_items = Vec::new();
344 let mut enumerant_parse_operations = Vec::new();
345 for enumerant in enumerants {
346 if enumerant.value.0 == 0 {
347 continue;
348 }
349 let member_name = new_id(&enumerant.enumerant, SnakeCase);
350 enumerant_member_names.push(member_name.clone());
351 let type_name =
352 new_combined_id(&[kind.as_ref(), &enumerant.enumerant], CamelCase);
353 let enumerant_parse_operation;
354 if enumerant.parameters.is_empty() {
355 enumerant_items.push(quote!{
356 #[derive(Clone, Debug, Default)]
357 pub struct #type_name;
358 });
359 enumerant_parse_operation = quote!{(Some(#type_name), words)};
360 } else {
361 let mut enumerant_member_declarations = Vec::new();
362 let mut enumerant_member_parse_initializers = Vec::new();
363 let mut parse_enumerant_members = Vec::new();
364 for (index, parameter) in enumerant.parameters.iter().enumerate() {
365 let name = new_id(format!("parameter_{}", index), SnakeCase);
366 let kind = new_id(&parameter.kind, CamelCase);
367 enumerant_member_declarations.push(quote!{
368 pub #kind,
369 });
370 enumerant_member_parse_initializers.push(quote!{
371 #name,
372 });
373 parse_enumerant_members.push(quote!{
374 let (#name, words) = #kind::spirv_parse(words, parse_state)?;
375 });
376 }
377 enumerant_items.push(quote!{
378 #[derive(Clone, Debug, Default)]
379 pub struct #type_name(#(#enumerant_member_declarations)*);
380 });
381 enumerant_parse_operation = quote!{
382 #(#parse_enumerant_members)*
383 (Some(#type_name(#(#enumerant_member_parse_initializers)*)), words)
384 };
385 }
386 enumerant_members.push(quote!{
387 pub #member_name: Option<#type_name>
388 });
389 let enumerant_value = enumerant.value;
390 enumerant_parse_operations.push(quote!{
391 let (#member_name, words) = if (mask & #enumerant_value) != 0 {
392 mask &= !#enumerant_value;
393 #enumerant_parse_operation
394 } else {
395 (None, words)
396 };
397 })
398 }
399 writeln!(
400 &mut out,
401 "{}",
402 quote!{
403 #[derive(Clone, Debug, Default)]
404 pub struct #kind_id {
405 #(#enumerant_members),*
406 }
407 #(#enumerant_items)*
408 }
409 )?;
410 let parse_body = quote!{
411 let (mut mask, words) = u32::spirv_parse(words, parse_state)?;
412 #(#enumerant_parse_operations)*
413 if mask != 0 {
414 Err(Error::InvalidEnumValue)
415 } else {
416 Ok((Self {
417 #(#enumerant_member_names,)*
418 }, words))
419 }
420 };
421 writeln!(
422 &mut out,
423 "{}",
424 quote!{
425 impl SPIRVParse for #kind_id {
426 fn spirv_parse<'a>(
427 words: &'a [u32],
428 parse_state: &mut ParseState,
429 ) -> Result<(Self, &'a [u32])> {
430 #parse_body
431 }
432 }
433 }
434 )?;
435 }
436 ast::OperandKind::ValueEnum { kind, enumerants } => {
437 let kind_id = new_id(&kind, CamelCase);
438 let mut generated_enumerants = Vec::new();
439 let mut enumerant_parse_cases = Vec::new();
440 for enumerant in enumerants {
441 let name = new_enumerant_id(&kind, &enumerant.enumerant);
442 let enumerant_value = enumerant.value;
443 if enumerant.parameters.is_empty() {
444 generated_enumerants.push(quote!{#name});
445 enumerant_parse_cases.push(quote!{
446 #enumerant_value => Ok((#kind_id::#name, words)),
447 });
448 } else {
449 let mut enumerant_member_declarations = Vec::new();
450 let mut enumerant_member_parse_initializers = Vec::new();
451 let mut parse_enumerant_members = Vec::new();
452 for parameter in enumerant.parameters.iter() {
453 let name = new_id(parameter.name.as_ref().unwrap(), SnakeCase);
454 let kind = new_id(&parameter.kind, CamelCase);
455 enumerant_member_declarations.push(quote!{
456 #name: #kind,
457 });
458 enumerant_member_parse_initializers.push(quote!{
459 #name,
460 });
461 parse_enumerant_members.push(quote!{
462 let (#name, words) = #kind::spirv_parse(words, parse_state)?;
463 });
464 }
465 generated_enumerants.push(quote!{
466 #name {
467 #(#enumerant_member_declarations)*
468 }
469 });
470 enumerant_parse_cases.push(quote!{
471 #enumerant_value => {
472 #(#parse_enumerant_members)*
473 Ok((#kind_id::#name {
474 #(#enumerant_member_parse_initializers)*
475 }, words))
476 },
477 });
478 }
479 }
480 writeln!(
481 &mut out,
482 "{}",
483 quote!{
484 #[derive(Clone, Debug)]
485 pub enum #kind_id {
486 #(#generated_enumerants,)*
487 }
488 }
489 )?;
490 writeln!(
491 &mut out,
492 "{}",
493 quote!{
494 impl SPIRVParse for #kind_id {
495 fn spirv_parse<'a>(
496 words: &'a [u32],
497 parse_state: &mut ParseState,
498 ) -> Result<(Self, &'a [u32])> {
499 let (enumerant, words) = u32::spirv_parse(words, parse_state)?;
500 match enumerant {
501 #(#enumerant_parse_cases)*
502 _ => Err(Error::InvalidEnumValue),
503 }
504 }
505 }
506 }
507 )?;
508 }
509 ast::OperandKind::Id { kind, doc: _ } => {
510 let base = if *kind == ast::Kind::IdRef {
511 quote!{u32}
512 } else {
513 quote!{IdRef}
514 };
515 let kind_id = new_id(kind, CamelCase);
516 writeln!(
517 &mut out,
518 "{}",
519 quote!{
520 #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Default)]
521 #[repr(transparent)]
522 pub struct #kind_id(pub #base);
523 }
524 )?;
525 if *kind != ast::Kind::IdRef {
526 writeln!(
527 &mut out,
528 "{}",
529 quote!{
530 impl SPIRVParse for #kind_id {
531 fn spirv_parse<'a>(
532 words: &'a [u32],
533 parse_state: &mut ParseState,
534 ) -> Result<(Self, &'a [u32])> {
535 IdRef::spirv_parse(words, parse_state).map(|(value, words)| (#kind_id(value), words))
536 }
537 }
538 }
539 )?;
540 writeln!(
541 &mut out,
542 "{}",
543 quote!{
544 impl fmt::Display for #kind_id {
545 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
546 fmt::Display::fmt(&self.0, f)
547 }
548 }
549 }
550 )?;
551 }
552 }
553 ast::OperandKind::Literal { kind, doc: _ } => {
554 let kind_id = new_id(kind, CamelCase);
555 writeln!(
556 &mut out,
557 "{}",
558 match kind {
559 ast::LiteralKind::LiteralInteger
560 | ast::LiteralKind::LiteralContextDependentNumber => unreachable!(),
561 ast::LiteralKind::LiteralInteger32
562 | ast::LiteralKind::LiteralContextDependentNumber32 => {
563 quote!{pub type #kind_id = u32;}
564 }
565 ast::LiteralKind::LiteralInteger64
566 | ast::LiteralKind::LiteralContextDependentNumber64 => {
567 quote!{pub type #kind_id = u64;}
568 }
569 ast::LiteralKind::LiteralString => quote!{pub type #kind_id = String;},
570 ast::LiteralKind::LiteralExtInstInteger => {
571 quote!{pub type #kind_id = u32;}
572 }
573 ast::LiteralKind::LiteralSpecConstantOpInteger => continue,
574 }
575 )?;
576 }
577 ast::OperandKind::Composite { kind, bases } => {
578 let kind = new_id(kind, CamelCase);
579 let bases = bases.into_iter().map(|base| new_id(base, CamelCase));
580 writeln!(&mut out, "{}", quote!{pub type #kind = (#(#bases),*);})?;
581 }
582 }
583 }
584 {
585 let mut instruction_enumerants = Vec::new();
586 let mut spec_constant_op_instruction_enumerants = Vec::new();
587 let mut instruction_parse_cases = Vec::new();
588 for instruction in core_instructions.iter() {
589 let opcode = instruction.opcode;
590 let opname = new_id(remove_initial_op(instruction.opname.as_ref()), CamelCase);
591 instruction_parse_cases.push(match &instruction.opname {
592 ast::InstructionName::OpTypeInt => {
593 let body = quote!{
594 let id_state = match width {
595 8 | 16 | 32 => IdState::Type(IdStateType(BitWidth::Width32OrLess)),
596 64 => IdState::Type(IdStateType(BitWidth::Width64)),
597 _ => return Err(Error::UnsupportedIntSize),
598 };
599 parse_state.define_id(id_result, id_state)?;
600 if words.is_empty() {
601 Ok(Instruction::TypeInt {
602 id_result,
603 width,
604 signedness,
605 })
606 } else {
607 Err(Error::InstructionTooLong)
608 }
609 };
610 quote!{
611 #opcode => {
612 let (id_result, words) = IdResult::spirv_parse(words, parse_state)?;
613 let (width, words) = LiteralInteger32::spirv_parse(words, parse_state)?;
614 let (signedness, words) = LiteralInteger32::spirv_parse(words, parse_state)?;
615 #body
616 }
617 }
618 }
619 ast::InstructionName::OpTypeFloat => {
620 quote!{
621 #opcode => {
622 let (id_result, words) = IdResult::spirv_parse(words, parse_state)?;
623 let (width, words) = LiteralInteger32::spirv_parse(words, parse_state)?;
624 let id_state = match width {
625 16 | 32 => IdState::Type(IdStateType(BitWidth::Width32OrLess)),
626 64 => IdState::Type(IdStateType(BitWidth::Width64)),
627 _ => return Err(Error::UnsupportedFloatSize),
628 };
629 parse_state.define_id(id_result, id_state)?;
630 if words.is_empty() {
631 Ok(Instruction::TypeFloat {
632 id_result,
633 width,
634 })
635 } else {
636 Err(Error::InstructionTooLong)
637 }
638 }
639 }
640 }
641 ast::InstructionName::OpSwitch32 => {
642 let body32 = quote!{
643 IdState::Value(IdStateValue(BitWidth::Width32OrLess)) => {
644 let (target, words) = Vec::<PairLiteralInteger32IdRef>::spirv_parse(words, parse_state)?;
645 if words.is_empty() {
646 Ok(Instruction::Switch32 {
647 selector,
648 default,
649 target,
650 })
651 } else {
652 Err(Error::InstructionTooLong)
653 }
654 }
655 };
656 let body64 = quote!{
657 IdState::Value(IdStateValue(BitWidth::Width64)) => {
658 let (target, words) = Vec::<PairLiteralInteger64IdRef>::spirv_parse(words, parse_state)?;
659 if words.is_empty() {
660 Ok(Instruction::Switch64 {
661 selector,
662 default,
663 target,
664 })
665 } else {
666 Err(Error::InstructionTooLong)
667 }
668 }
669 };
670 quote!{
671 #opcode => {
672 let (selector, words) = IdRef::spirv_parse(words, parse_state)?;
673 let (default, words) = IdRef::spirv_parse(words, parse_state)?;
674 match parse_state.id_states[selector.0 as usize] {
675 #body32
676 #body64
677 _ => Err(Error::SwitchSelectorIsInvalid(selector)),
678 }
679 }
680 }
681 }
682 ast::InstructionName::OpSwitch64 => quote!{},
683 ast::InstructionName::OpConstant32 => {
684 let body32 = quote!{
685 IdStateType(BitWidth::Width32OrLess) => {
686 let (value, words) = LiteralContextDependentNumber32::spirv_parse(words, parse_state)?;
687 if words.is_empty() {
688 Ok(Instruction::Constant32 {
689 id_result_type,
690 id_result,
691 value,
692 })
693 } else {
694 Err(Error::InstructionTooLong)
695 }
696 }
697 };
698 let body64 = quote!{
699 IdStateType(BitWidth::Width64) => {
700 let (value, words) = LiteralContextDependentNumber64::spirv_parse(words, parse_state)?;
701 if words.is_empty() {
702 Ok(Instruction::Constant64 {
703 id_result_type,
704 id_result,
705 value,
706 })
707 } else {
708 Err(Error::InstructionTooLong)
709 }
710 }
711 };
712 quote!{
713 #opcode => {
714 let (id_result_type, words) = IdResultType::spirv_parse(words, parse_state)?;
715 let (id_result, words) = IdResult::spirv_parse(words, parse_state)?;
716 parse_state.define_value(id_result_type, id_result)?;
717 match parse_state.get_type(id_result_type.0)? {
718 #body32
719 #body64
720 }
721 }
722 }
723 }
724 ast::InstructionName::OpConstant64 => quote!{},
725 ast::InstructionName::OpSpecConstant32 => {
726 let body32 = quote!{
727 IdStateType(BitWidth::Width32OrLess) => {
728 let (value, words) = LiteralContextDependentNumber32::spirv_parse(words, parse_state)?;
729 if words.is_empty() {
730 Ok(Instruction::SpecConstant32 {
731 id_result_type,
732 id_result,
733 value,
734 })
735 } else {
736 Err(Error::InstructionTooLong)
737 }
738 }
739 };
740 let body64 = quote!{
741 IdStateType(BitWidth::Width64) => {
742 let (value, words) = LiteralContextDependentNumber64::spirv_parse(words, parse_state)?;
743 if words.is_empty() {
744 Ok(Instruction::SpecConstant64 {
745 id_result_type,
746 id_result,
747 value,
748 })
749 } else {
750 Err(Error::InstructionTooLong)
751 }
752 }
753 };
754 quote!{
755 #opcode => {
756 let (id_result_type, words) = IdResultType::spirv_parse(words, parse_state)?;
757 let (id_result, words) = IdResult::spirv_parse(words, parse_state)?;
758 parse_state.define_value(id_result_type, id_result)?;
759 match parse_state.get_type(id_result_type.0)? {
760 #body32
761 #body64
762 }
763 }
764 }
765 }
766 ast::InstructionName::OpSpecConstant64 => quote!{},
767 ast::InstructionName::OpSpecConstantOp => {
768 quote!{#opcode => {
769 let (operation, words) = OpSpecConstantOp::spirv_parse(words, parse_state)?;
770 if words.is_empty() {
771 Ok(Instruction::#opname { operation })
772 } else {
773 Err(Error::InstructionTooLong)
774 }
775 }}
776 }
777 _ => {
778 let mut parse_operations = Vec::new();
779 let mut operand_names = Vec::new();
780 for operand in &instruction.operands {
781 let kind = new_id(&operand.kind, CamelCase);
782 let name = new_id(operand.name.as_ref().unwrap(), SnakeCase);
783 let kind = match operand.quantifier {
784 None => quote!{#kind},
785 Some(ast::Quantifier::Optional) => quote!{Option::<#kind>},
786 Some(ast::Quantifier::Variadic) => quote!{Vec::<#kind>},
787 };
788 parse_operations.push(quote!{
789 let (#name, words) = #kind::spirv_parse(words, parse_state)?;
790 });
791 operand_names.push(name);
792 }
793 if let Some([operand1, operand2]) = instruction.operands.get(..2) {
794 if operand1.kind == ast::Kind::IdResultType && operand2.kind == ast::Kind::IdResult {
795 let operand1_name = new_id(operand1.name.as_ref().unwrap(), SnakeCase);
796 let operand2_name = new_id(operand2.name.as_ref().unwrap(), SnakeCase);
797 parse_operations.push(quote!{
798 parse_state.define_value(#operand1_name, #operand2_name)?;
799 });
800 }
801 }
802 quote!{#opcode => {
803 #(#parse_operations)*
804 if words.is_empty() {
805 Ok(Instruction::#opname {
806 #(#operand_names,)*
807 })
808 } else {
809 Err(Error::InstructionTooLong)
810 }
811 }}
812 }
813 });
814 let instruction_enumerant =
815 if instruction.opname == ast::InstructionName::OpSpecConstantOp {
816 quote!{
817 #opname {
818 operation: OpSpecConstantOp,
819 }
820 }
821 } else if instruction.operands.is_empty() {
822 quote!{#opname}
823 } else {
824 let mut fields = Vec::new();
825 for operand in instruction.operands.iter() {
826 let kind = new_id(&operand.kind, CamelCase);
827 let name = new_id(operand.name.as_ref().unwrap(), SnakeCase);
828 let kind = match &operand.quantifier {
829 None => quote!{#kind},
830 Some(ast::Quantifier::Optional) => quote!{Option<#kind>},
831 Some(ast::Quantifier::Variadic) => quote!{Vec<#kind>},
832 };
833 fields.push(quote!{#name: #kind});
834 }
835 quote!{
836 #opname {
837 #(#fields,)*
838 }
839 }
840 };
841 if ast::OP_SPEC_CONSTANT_OP_SUPPORTED_INSTRUCTIONS.contains(&instruction.opname) {
842 spec_constant_op_instruction_enumerants.push(instruction_enumerant.clone());
843 }
844 instruction_enumerants.push(instruction_enumerant);
845 }
846 writeln!(
847 &mut out,
848 "{}",
849 quote!{
850 #[derive(Clone, Debug)]
851 pub enum OpSpecConstantOp {
852 #(#spec_constant_op_instruction_enumerants,)*
853 }
854 }
855 )?;
856 writeln!(
857 &mut out,
858 "{}",
859 quote!{
860 #[derive(Clone, Debug)]
861 pub enum Instruction {
862 #(#instruction_enumerants,)*
863 }
864 }
865 )?;
866 writeln!(
867 &mut out,
868 "{}",
869 stringify!(
870 #[derive(Copy, Clone, Debug)]
871 pub struct Header {
872 pub version: (u32, u32),
873 pub generator: u32,
874 pub bound: u32,
875 pub instruction_schema: u32,
876 }
877
878 impl fmt::Display for Header {
879 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
880 writeln!(f, "; SPIR-V")?;
881 writeln!(f, "; Version: {}.{}", self.version.0, self.version.1)?;
882 writeln!(f, "; Generator: {:#X}", self.generator)?;
883 writeln!(f, "; Bound: {}", self.bound)?;
884 writeln!(f, "; Schema: {}", self.instruction_schema)
885 }
886 }
887
888 struct InstructionIndentAndResult(Option<IdResult>);
889
890 impl fmt::Display for InstructionIndentAndResult {
891 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
892 write!(f, "{:>15}", self.0.map(|v| format!("{} = ", v.0)).unwrap_or_default())
893 }
894 }
895
896 impl fmt::Display for IdRef {
897 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
898 write!(f, "#{}", self.0)
899 }
900 }
901
902 #[derive(Clone, Debug)]
903 pub enum Error {
904 MissingHeader,
905 InvalidHeader,
906 UnsupportedVersion(u32, u32),
907 ZeroInstructionLength,
908 SourcePrematurelyEnded,
909 UnknownOpcode(u16),
910 Utf8Error(Utf8Error),
911 InstructionPrematurelyEnded,
912 InvalidStringTermination,
913 InstructionTooLong,
914 InvalidEnumValue,
915 IdOutOfBounds(u32),
916 IdAlreadyDefined(IdResult),
917 UnsupportedFloatSize,
918 UnsupportedIntSize,
919 UndefinedType(IdRef),
920 SwitchSelectorIsInvalid(IdRef),
921 }
922
923 impl From<Utf8Error> for Error {
924 fn from(v: Utf8Error) -> Self {
925 Error::Utf8Error(v)
926 }
927 }
928
929 impl From<FromUtf8Error> for Error {
930 fn from(v: FromUtf8Error) -> Self {
931 Error::Utf8Error(v.utf8_error())
932 }
933 }
934
935 impl fmt::Display for Error {
936 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
937 match *self {
938 Error::MissingHeader => write!(f, "SPIR-V source is missing the file header"),
939 Error::InvalidHeader => write!(f, "SPIR-V source has an invalid file header"),
940 Error::UnsupportedVersion(major, minor) => write!(
941 f,
942 "SPIR-V source has an unsupported version: {}.{}",
943 major,
944 minor
945 ),
946 Error::ZeroInstructionLength => write!(f, "SPIR-V instruction has a length of zero"),
947 Error::SourcePrematurelyEnded => write!(f, "SPIR-V source prematurely ended"),
948 Error::UnknownOpcode(opcode) => {
949 write!(f, "SPIR-V instruction has an unknown opcode: {}", opcode)
950 }
951 Error::Utf8Error(error) => fmt::Display::fmt(&error, f),
952 Error::InstructionPrematurelyEnded => write!(f, "SPIR-V instruction prematurely ended"),
953 Error::InvalidStringTermination => write!(f, "SPIR-V LiteralString has an invalid termination word"),
954 Error::InstructionTooLong => write!(f, "SPIR-V instruction is too long"),
955 Error::InvalidEnumValue => write!(f, "enum has invalid value"),
956 Error::IdOutOfBounds(id) => write!(f, "id is out of bounds: {}", id),
957 Error::IdAlreadyDefined(id) => write!(f, "id is already defined: {}", id),
958 Error::UnsupportedFloatSize => write!(f, "unsupported float size"),
959 Error::UnsupportedIntSize => write!(f, "unsupported int size"),
960 Error::UndefinedType(id) => write!(f, "undefined type {}", id),
961 Error::SwitchSelectorIsInvalid(id) => write!(f, "Switch selector is invalid: {}", id),
962 }
963 }
964 }
965
966 impl error::Error for Error {}
967
968 type Result<T> = result::Result<T, Error>;
969
970 #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
971 enum BitWidth {
972 Width32OrLess,
973 Width64,
974 }
975
976 #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
977 struct IdStateType(BitWidth);
978
979 #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
980 struct IdStateValue(BitWidth);
981
982 #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
983 enum IdState {
984 Unknown,
985 Type(IdStateType),
986 Value(IdStateValue),
987 }
988
989 #[derive(Clone, Debug)]
990 struct ParseState {
991 id_states: Vec<IdState>,
992 }
993
994 impl ParseState {
995 fn define_id(&mut self, id_result: IdResult, new_id_state: IdState) -> Result<()> {
996 let id_state = &mut self.id_states[(id_result.0).0 as usize];
997 if *id_state != IdState::Unknown {
998 return Err(Error::IdAlreadyDefined(id_result));
999 }
1000 *id_state = new_id_state;
1001 Ok(())
1002 }
1003 fn get_type(&self, id: IdRef) -> Result<IdStateType> {
1004 if let IdState::Type(retval) = self.id_states[id.0 as usize] {
1005 Ok(retval)
1006 } else {
1007 Err(Error::UndefinedType(id))
1008 }
1009 }
1010 fn define_value(&mut self, id_result_type: IdResultType, id_result: IdResult) -> Result<()> {
1011 if let IdState::Type(IdStateType(bit_width)) = self.id_states[(id_result_type.0).0 as usize] {
1012 self.define_id(id_result, IdState::Value(IdStateValue(bit_width)))?;
1013 }
1014 Ok(())
1015 }
1016 }
1017
1018 #[derive(Clone, Debug)]
1019 pub struct Parser<'a> {
1020 words: &'a [u32],
1021 header: Header,
1022 parse_state: ParseState,
1023 }
1024
1025 fn parse_version(v: u32) -> Result<(u32, u32)> {
1026 if (v & 0xFF0000FF) != 0 {
1027 return Err(Error::InvalidHeader);
1028 }
1029 let major = (v >> 16) & 0xFF;
1030 let minor = (v >> 8) & 0xFF;
1031 Ok((major, minor))
1032 }
1033
1034 impl<'a> Parser<'a> {
1035 pub fn header(&self) -> &Header {
1036 &self.header
1037 }
1038 pub fn start(mut words: &'a [u32]) -> Result<Self> {
1039 let header = words.get(0..5).ok_or(Error::MissingHeader)?;
1040 words = &words[5..];
1041 let header = match *header {
1042 [MAGIC_NUMBER, version, generator, bound, instruction_schema @ 0] if bound >= 1 => {
1043 let version = parse_version(version)?;
1044 if version.0 != MAJOR_VERSION || version.1 > MINOR_VERSION {
1045 return Err(Error::UnsupportedVersion(version.0, version.1));
1046 }
1047 Header {
1048 version,
1049 generator,
1050 bound,
1051 instruction_schema,
1052 }
1053 }
1054 _ => return Err(Error::InvalidHeader),
1055 };
1056 Ok(Self {
1057 words,
1058 header,
1059 parse_state: ParseState {
1060 id_states: vec![IdState::Unknown; header.bound as usize],
1061 },
1062 })
1063 }
1064 fn next_helper(&mut self, length_and_opcode: u32) -> Result<Instruction> {
1065 let length = (length_and_opcode >> 16) as usize;
1066 let opcode = length_and_opcode as u16;
1067 if length == 0 {
1068 return Err(Error::ZeroInstructionLength);
1069 }
1070 let instruction_words = self.words.get(1..length).ok_or(Error::SourcePrematurelyEnded)?;
1071 self.words = &self.words[length..];
1072 parse_instruction(opcode, instruction_words, &mut self.parse_state)
1073 }
1074 }
1075
1076 impl<'a> Iterator for Parser<'a> {
1077 type Item = Result<Instruction>;
1078 fn next(&mut self) -> Option<Result<Instruction>> {
1079 let length_and_opcode = self.words.get(0)?;
1080 Some(self.next_helper(*length_and_opcode))
1081 }
1082 }
1083 )
1084 )?;
1085 writeln!(
1086 &mut out,
1087 "{}",
1088 quote!{
1089 fn parse_instruction(opcode: u16, words: &[u32], parse_state: &mut ParseState) -> Result<Instruction> {
1090 match opcode {
1091 #(#instruction_parse_cases)*
1092 opcode => Err(Error::UnknownOpcode(opcode)),
1093 }
1094 }
1095 }
1096 )?;
1097 writeln!(
1098 &mut out,
1099 "{}",
1100 quote!{
1101 impl SPIRVParse for OpSpecConstantOp {
1102 fn spirv_parse<'a>(
1103 words: &'a [u32],
1104 parse_state: &mut ParseState
1105 ) -> Result<(Self, &'a [u32])> {
1106 let (id_result_type, words) = IdResultType::spirv_parse(words, parse_state)?;
1107 let (id_result, words) = IdResult::spirv_parse(words, parse_state)?;
1108 let (opcode, words) = u32::spirv_parse(words, parse_state)?;
1109 unimplemented!()
1110 }
1111 }
1112 }
1113 )?;
1114 }
1115 let source = String::from_utf8(out).unwrap();
1116 let source = match format_source(&options, &source) {
1117 Ok(source) => source.into_owned(),
1118 Err(error) => {
1119 eprintln!("formatting source failed: {}", error);
1120 source.clone()
1121 }
1122 };
1123 Ok(source)
1124 }