4f709609d33d677ab761386a09ff0e690c7109ab
[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::collections::HashSet;
9 use std::fmt;
10 use std::io::{self, Read, Write};
11 use std::iter;
12 use std::process::{Child, Command, ExitStatus, Stdio};
13 use std::thread;
14 use util::{self, NameFormat::*};
15 use which;
16 use Error;
17 use Options;
18
19 #[derive(Debug)]
20 enum FormatError {
21 IOError(io::Error),
22 WhichError(which::Error),
23 RustFmtFailed(ExitStatus),
24 }
25
26 impl fmt::Display for FormatError {
27 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
28 match self {
29 FormatError::IOError(v) => fmt::Display::fmt(v, f),
30 FormatError::WhichError(v) => fmt::Display::fmt(v, f),
31 FormatError::RustFmtFailed(v) => write!(f, "rustfmt failed: {:?}", v),
32 }
33 }
34 }
35
36 impl From<which::Error> for FormatError {
37 fn from(v: which::Error) -> Self {
38 FormatError::WhichError(v)
39 }
40 }
41
42 impl From<io::Error> for FormatError {
43 fn from(v: io::Error) -> Self {
44 FormatError::IOError(v)
45 }
46 }
47
48 fn format_source<'a>(options: &Options, source: &'a str) -> Result<Cow<'a, str>, FormatError> {
49 if !options.run_rustfmt {
50 return Ok(Cow::Borrowed(source));
51 }
52 let rustfmt_path = match options.rustfmt_path.clone() {
53 Some(v) => v,
54 None => which::which("rustfmt")?,
55 };
56 let mut command = Command::new(rustfmt_path)
57 .stdin(Stdio::piped())
58 .stdout(Stdio::piped())
59 .spawn()?;
60 let stdin = command.stdin.take().unwrap();
61 let reader_thread = thread::spawn(move || -> io::Result<(String, Child)> {
62 let mut output = String::new();
63 command.stdout.take().unwrap().read_to_string(&mut output)?;
64 Ok((output, command))
65 });
66 { stdin }.write_all(source.as_bytes())?;
67 let (output, mut command) = reader_thread.join().unwrap()?;
68 let exit_status = command.wait()?;
69 if exit_status.success() {
70 Ok(Cow::Owned(output))
71 } else {
72 Err(FormatError::RustFmtFailed(exit_status))
73 }
74 }
75
76 fn remove_initial_op(name: &str) -> &str {
77 const INITIAL_OP: &str = "Op";
78 assert!(name.starts_with(INITIAL_OP));
79 &name[INITIAL_OP.len()..]
80 }
81
82 fn new_id<T: AsRef<str>>(name: T, name_format: util::NameFormat) -> proc_macro2::Ident {
83 proc_macro2::Ident::new(
84 &name_format
85 .name_from_words(util::WordIterator::new(name.as_ref()))
86 .unwrap(),
87 proc_macro2::Span::call_site(),
88 )
89 }
90
91 fn new_enumerant_id<T1: AsRef<str>, T2: AsRef<str>>(
92 enum_name: T1,
93 enumerant_name: T2,
94 ) -> proc_macro2::Ident {
95 let enumerant_name_words = util::WordIterator::new(enumerant_name.as_ref());
96 let enumerant_name_first_word = enumerant_name_words.clone().next();
97 let name = if enumerant_name_first_word
98 .map(str::chars)
99 .as_mut()
100 .and_then(Iterator::next)
101 .filter(char::is_ascii_digit)
102 .is_some()
103 {
104 CamelCase
105 .name_from_words(
106 util::WordIterator::new(enum_name.as_ref()).chain(enumerant_name_words),
107 )
108 .unwrap()
109 } else {
110 CamelCase.name_from_words(enumerant_name_words).unwrap()
111 };
112 proc_macro2::Ident::new(&name, proc_macro2::Span::call_site())
113 }
114
115 fn new_combined_id<I: IntoIterator>(names: I, name_format: util::NameFormat) -> proc_macro2::Ident
116 where
117 I::Item: AsRef<str>,
118 {
119 let names: Vec<I::Item> = names.into_iter().collect();
120 proc_macro2::Ident::new(
121 &name_format
122 .name_from_words(
123 names
124 .iter()
125 .map(AsRef::as_ref)
126 .flat_map(util::WordIterator::new),
127 )
128 .unwrap(),
129 proc_macro2::Span::call_site(),
130 )
131 }
132
133 struct ParsedExtensionInstructionSet {
134 ast: ast::ExtensionInstructionSet,
135 enumerant_name: proc_macro2::Ident,
136 spirv_instruction_set_name: &'static str,
137 }
138
139 #[cfg_attr(feature = "cargo-clippy", allow(clippy::cyclomatic_complexity))]
140 pub(crate) fn generate(
141 core_grammar: ast::CoreGrammar,
142 parsed_extension_instruction_sets: HashMap<
143 super::ExtensionInstructionSet,
144 ast::ExtensionInstructionSet,
145 >,
146 options: &Options,
147 ) -> Result<String, Error> {
148 let mut out = Vec::new();
149 let ast::CoreGrammar {
150 copyright: core_grammar_copyright,
151 magic_number,
152 major_version,
153 minor_version,
154 revision: core_revision,
155 instructions: core_instructions,
156 operand_kinds,
157 } = core_grammar;
158 let parsed_extension_instruction_sets: Vec<_> = parsed_extension_instruction_sets
159 .into_iter()
160 .map(|(key, ast)| match key {
161 super::ExtensionInstructionSet::GLSLStd450 => ParsedExtensionInstructionSet {
162 ast,
163 enumerant_name: new_id("GLSLStd450", CamelCase),
164 spirv_instruction_set_name: "GLSL.std.450",
165 },
166 super::ExtensionInstructionSet::OpenCLStd => ParsedExtensionInstructionSet {
167 ast,
168 enumerant_name: new_id("OpenCLStd", CamelCase),
169 spirv_instruction_set_name: "OpenCL.std",
170 },
171 })
172 .collect();
173 writeln!(&mut out, "// automatically generated file")?;
174 {
175 let mut copyright_set = HashSet::new();
176 for copyright in iter::once(&core_grammar_copyright).chain(
177 parsed_extension_instruction_sets
178 .iter()
179 .map(|v| &v.ast.copyright),
180 ) {
181 if !copyright_set.insert(copyright) {
182 continue;
183 }
184 writeln!(&mut out, "//")?;
185 for line in copyright.iter() {
186 assert_eq!(line.find('\r'), None);
187 assert_eq!(line.find('\n'), None);
188 if line == "" {
189 writeln!(&mut out, "//")?;
190 } else {
191 writeln!(&mut out, "// {}", line)?;
192 }
193 }
194 }
195 }
196 writeln!(
197 &mut out,
198 "{}",
199 stringify!(
200 use std::borrow::Cow;
201 use std::error;
202 use std::fmt;
203 use std::mem;
204 use std::ops::Deref;
205 use std::result;
206 use std::str::Utf8Error;
207 use std::string::FromUtf8Error;
208
209 trait SPIRVParse: Sized {
210 fn spirv_parse<'a>(words: &'a [u32], parse_state: &mut ParseState)
211 -> Result<(Self, &'a [u32])>;
212 }
213
214 trait SPIRVDisplay {
215 fn spirv_display(&self, f: &mut fmt::Formatter) -> fmt::Result;
216 }
217
218 impl<T: SPIRVParse> SPIRVParse for Option<T> {
219 fn spirv_parse<'a>(
220 words: &'a [u32],
221 parse_state: &mut ParseState,
222 ) -> Result<(Self, &'a [u32])> {
223 if words.is_empty() {
224 Ok((None, words))
225 } else {
226 let (value, words) = T::spirv_parse(words, parse_state)?;
227 Ok((Some(value), words))
228 }
229 }
230 }
231
232 impl<T: SPIRVDisplay> SPIRVDisplay for Option<T> {
233 fn spirv_display(&self, f: &mut fmt::Formatter) -> fmt::Result {
234 match self {
235 Some(v) => v.spirv_display(f),
236 None => Ok(()),
237 }
238 }
239 }
240
241 impl<T: SPIRVParse> SPIRVParse for Vec<T> {
242 fn spirv_parse<'a>(
243 mut words: &'a [u32],
244 parse_state: &mut ParseState,
245 ) -> Result<(Self, &'a [u32])> {
246 let mut retval = Vec::new();
247 while !words.is_empty() {
248 let result = T::spirv_parse(words, parse_state)?;
249 words = result.1;
250 retval.push(result.0);
251 }
252 Ok((retval, words))
253 }
254 }
255
256 impl<T: SPIRVDisplay> SPIRVDisplay for Vec<T> {
257 fn spirv_display(&self, f: &mut fmt::Formatter) -> fmt::Result {
258 for i in self {
259 i.spirv_display(f)?;
260 }
261 Ok(())
262 }
263 }
264
265 impl<A: SPIRVParse, B: SPIRVParse> SPIRVParse for (A, B) {
266 fn spirv_parse<'a>(
267 words: &'a [u32],
268 parse_state: &mut ParseState,
269 ) -> Result<(Self, &'a [u32])> {
270 let (a, words) = A::spirv_parse(words, parse_state)?;
271 let (b, words) = B::spirv_parse(words, parse_state)?;
272 Ok(((a, b), words))
273 }
274 }
275
276 impl<A: SPIRVDisplay, B: SPIRVDisplay> SPIRVDisplay for (A, B) {
277 fn spirv_display(&self, f: &mut fmt::Formatter) -> fmt::Result {
278 self.0.spirv_display(f)?;
279 self.1.spirv_display(f)
280 }
281 }
282
283 const BYTES_PER_WORD: usize = 4;
284
285 struct ByteIterator<'a> {
286 current_word: [u8; BYTES_PER_WORD],
287 current_word_index: usize,
288 words: &'a [u32],
289 }
290
291 impl<'a> ByteIterator<'a> {
292 fn new(words: &'a [u32]) -> Self {
293 Self {
294 current_word: [0; BYTES_PER_WORD],
295 current_word_index: BYTES_PER_WORD,
296 words,
297 }
298 }
299 fn take_unread_words(&mut self) -> &'a [u32] {
300 mem::replace(&mut self.words, &[])
301 }
302 }
303
304 impl<'a> Iterator for ByteIterator<'a> {
305 type Item = u8;
306 fn next(&mut self) -> Option<u8> {
307 if self.current_word_index >= BYTES_PER_WORD {
308 let (&current_word, words) = self.words.split_first()?;
309 self.words = words;
310 self.current_word = unsafe { mem::transmute(current_word.to_le()) };
311 self.current_word_index = 0;
312 }
313 let byte = self.current_word[self.current_word_index];
314 self.current_word_index += 1;
315 Some(byte)
316 }
317 }
318
319 impl SPIRVParse for String {
320 fn spirv_parse<'a>(
321 words: &'a [u32],
322 _parse_state: &mut ParseState,
323 ) -> Result<(Self, &'a [u32])> {
324 let mut byte_count_excluding_null_terminator = None;
325 for (index, byte) in ByteIterator::new(words).enumerate() {
326 if byte == 0 {
327 byte_count_excluding_null_terminator = Some(index);
328 break;
329 }
330 }
331 let byte_count_excluding_null_terminator =
332 byte_count_excluding_null_terminator.ok_or(Error::InstructionPrematurelyEnded)?;
333 let mut bytes = Vec::with_capacity(byte_count_excluding_null_terminator);
334 let mut byte_iter = ByteIterator::new(words);
335 for _ in 0..byte_count_excluding_null_terminator {
336 let byte = byte_iter.next().unwrap();
337 bytes.push(byte);
338 }
339 let _null_terminator = byte_iter.next().unwrap();
340 let words = byte_iter.take_unread_words();
341 for v in byte_iter {
342 if v != 0 {
343 return Err(Error::InvalidStringTermination);
344 }
345 }
346 assert_eq!(bytes.len(), byte_count_excluding_null_terminator);
347 Ok((String::from_utf8(bytes)?, words))
348 }
349 }
350
351 impl SPIRVDisplay for String {
352 fn spirv_display(&self, f: &mut fmt::Formatter) -> fmt::Result {
353 write!(f, " {:?}", self)
354 }
355 }
356
357 impl SPIRVParse for u32 {
358 fn spirv_parse<'a>(
359 words: &'a [u32],
360 _parse_state: &mut ParseState,
361 ) -> Result<(Self, &'a [u32])> {
362 let (&value, words) = words
363 .split_first()
364 .ok_or(Error::InstructionPrematurelyEnded)?;
365 Ok((value, words))
366 }
367 }
368
369 impl SPIRVDisplay for u32 {
370 fn spirv_display(&self, f: &mut fmt::Formatter) -> fmt::Result {
371 write!(f, " {}", self)
372 }
373 }
374
375 impl SPIRVParse for u64 {
376 fn spirv_parse<'a>(
377 words: &'a [u32],
378 _parse_state: &mut ParseState,
379 ) -> Result<(Self, &'a [u32])> {
380 let (&low, words) = words
381 .split_first()
382 .ok_or(Error::InstructionPrematurelyEnded)?;
383 let (&high, words) = words
384 .split_first()
385 .ok_or(Error::InstructionPrematurelyEnded)?;
386 Ok(((u64::from(high) << 32) | u64::from(low), words))
387 }
388 }
389
390 impl SPIRVDisplay for u64 {
391 fn spirv_display(&self, f: &mut fmt::Formatter) -> fmt::Result {
392 write!(f, " {}", self)
393 }
394 }
395
396 impl SPIRVParse for IdRef {
397 fn spirv_parse<'a>(
398 words: &'a [u32],
399 parse_state: &mut ParseState,
400 ) -> Result<(Self, &'a [u32])> {
401 let (value, words) = u32::spirv_parse(words, parse_state)?;
402 if value == 0 || value as usize >= parse_state.id_states.len() {
403 Err(Error::IdOutOfBounds(value))
404 } else {
405 Ok((IdRef(value), words))
406 }
407 }
408 }
409
410 impl SPIRVDisplay for IdRef {
411 fn spirv_display(&self, f: &mut fmt::Formatter) -> fmt::Result {
412 write!(f, " {}", self)
413 }
414 }
415 )
416 )?;
417 writeln!(
418 &mut out,
419 "{}",
420 quote!{
421 pub const MAGIC_NUMBER: u32 = #magic_number;
422 pub const MAJOR_VERSION: u32 = #major_version;
423 pub const MINOR_VERSION: u32 = #minor_version;
424 pub const REVISION: u32 = #core_revision;
425 }
426 )?;
427 for operand_kind in &operand_kinds {
428 match operand_kind {
429 ast::OperandKind::BitEnum { kind, enumerants } => {
430 let kind_id = new_id(kind, CamelCase);
431 let mut enumerant_members = Vec::new();
432 let mut enumerant_member_names = Vec::new();
433 let mut enumerant_items = Vec::new();
434 let mut enumerant_parse_operations = Vec::new();
435 let mut enumerant_display_mask_operations = Vec::new();
436 let mut enumerant_display_operations = Vec::new();
437 let mut none_name = "None";
438 for enumerant in enumerants {
439 if enumerant.value.0 == 0 {
440 none_name = enumerant.enumerant.as_ref();
441 continue;
442 }
443 let enumerant_name = &enumerant.enumerant;
444 let member_name = new_id(&enumerant.enumerant, SnakeCase);
445 let member_name = &member_name;
446 enumerant_member_names.push(member_name.clone());
447 let type_name =
448 new_combined_id(&[kind.as_ref(), &enumerant.enumerant], CamelCase);
449 let enumerant_parse_operation;
450 if enumerant.parameters.is_empty() {
451 enumerant_items.push(quote!{
452 #[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Hash)]
453 pub struct #type_name;
454 });
455 enumerant_parse_operation = quote!{(Some(#type_name), words)};
456 enumerant_display_mask_operations.push(quote!{
457 if self.#member_name.is_some() {
458 if any_members {
459 write!(f, "|{}", #enumerant_name)?;
460 } else {
461 write!(f, " {}", #enumerant_name)?;
462 any_members = true;
463 }
464 }
465 });
466 enumerant_display_operations.push(quote!{});
467 } else {
468 let mut enumerant_parameter_declarations = Vec::new();
469 let mut enumerant_parameter_names = Vec::new();
470 let mut parse_enumerant_members = Vec::new();
471 let mut display_enumerant_members = Vec::new();
472 for (index, parameter) in enumerant.parameters.iter().enumerate() {
473 let name = new_id(format!("parameter_{}", index), SnakeCase);
474 let kind = new_id(&parameter.kind, CamelCase);
475 enumerant_parameter_declarations.push(quote!{
476 pub #kind,
477 });
478 enumerant_parameter_names.push(quote!{
479 #name,
480 });
481 parse_enumerant_members.push(quote!{
482 let (#name, words) = #kind::spirv_parse(words, parse_state)?;
483 });
484 display_enumerant_members.push(quote!{
485 #name.spirv_display(f)?;
486 });
487 }
488 enumerant_items.push(quote!{
489 #[derive(Clone, Debug, Default, Eq, PartialEq, Hash)]
490 pub struct #type_name(#(#enumerant_parameter_declarations)*);
491 });
492 let enumerant_parameter_names = &enumerant_parameter_names;
493 enumerant_parse_operation = quote!{
494 #(#parse_enumerant_members)*
495 (Some(#type_name(#(#enumerant_parameter_names)*)), words)
496 };
497 enumerant_display_mask_operations.push(quote!{
498 if self.#member_name.is_some() {
499 if any_members {
500 write!(f, "|{}", #enumerant_name)?;
501 } else {
502 write!(f, " {}", #enumerant_name)?;
503 any_members = true;
504 }
505 }
506 });
507 enumerant_display_operations.push(quote!{
508 if let Some(#type_name(#(#enumerant_parameter_names)*)) = &self.#member_name {
509 #(#display_enumerant_members)*
510 }
511 });
512 };
513 enumerant_members.push(quote!{
514 pub #member_name: Option<#type_name>
515 });
516 let enumerant_value = enumerant.value;
517 enumerant_parse_operations.push(quote!{
518 let (#member_name, words) = if (mask & #enumerant_value) != 0 {
519 mask &= !#enumerant_value;
520 #enumerant_parse_operation
521 } else {
522 (None, words)
523 };
524 })
525 }
526 writeln!(
527 &mut out,
528 "{}",
529 quote!{
530 #[derive(Clone, Debug, Default, Eq, PartialEq, Hash)]
531 pub struct #kind_id {
532 #(#enumerant_members),*
533 }
534 #(#enumerant_items)*
535 }
536 )?;
537 let parse_body = quote!{
538 let (mut mask, words) = u32::spirv_parse(words, parse_state)?;
539 #(#enumerant_parse_operations)*
540 if mask != 0 {
541 Err(Error::InvalidEnumValue)
542 } else {
543 Ok((Self {
544 #(#enumerant_member_names,)*
545 }, words))
546 }
547 };
548 writeln!(
549 &mut out,
550 "{}",
551 quote!{
552 impl SPIRVParse for #kind_id {
553 fn spirv_parse<'a>(
554 words: &'a [u32],
555 parse_state: &mut ParseState,
556 ) -> Result<(Self, &'a [u32])> {
557 #parse_body
558 }
559 }
560 }
561 )?;
562 writeln!(
563 &mut out,
564 "{}",
565 quote!{
566 impl SPIRVDisplay for #kind_id {
567 fn spirv_display(&self, f: &mut fmt::Formatter) -> fmt::Result {
568 let mut any_members = false;
569 #(#enumerant_display_mask_operations)*
570 if !any_members {
571 write!(f, " {}", #none_name)?;
572 }
573 #(#enumerant_display_operations)*
574 Ok(())
575 }
576 }
577 }
578 )?;
579 }
580 ast::OperandKind::ValueEnum { kind, enumerants } => {
581 let mut has_any_parameters = false;
582 for enumerant in enumerants {
583 if !enumerant.parameters.is_empty() {
584 has_any_parameters = true;
585 }
586 }
587 let kind_id = new_id(&kind, CamelCase);
588 let mut generated_enumerants = Vec::new();
589 let mut enumerant_parse_cases = Vec::new();
590 let mut enumerant_display_cases = Vec::new();
591 for enumerant in enumerants {
592 let name = new_enumerant_id(&kind, &enumerant.enumerant);
593 let enumerant_value = enumerant.value;
594 let display_name = &enumerant.enumerant;
595 if enumerant.parameters.is_empty() {
596 generated_enumerants.push(quote!{#name});
597 enumerant_parse_cases.push(quote!{
598 #enumerant_value => Ok((#kind_id::#name, words)),
599 });
600 enumerant_display_cases.push(quote!{
601 #kind_id::#name => write!(f, " {}", #display_name),
602 });
603 } else {
604 let mut enumerant_member_declarations = Vec::new();
605 let mut enumerant_member_names = Vec::new();
606 let mut parse_enumerant_members = Vec::new();
607 let mut display_enumerant_members = Vec::new();
608 for parameter in enumerant.parameters.iter() {
609 let name = new_id(parameter.name.as_ref().unwrap(), SnakeCase);
610 let kind = new_id(&parameter.kind, CamelCase);
611 enumerant_member_declarations.push(quote!{
612 #name: #kind,
613 });
614 enumerant_member_names.push(quote!{
615 #name,
616 });
617 parse_enumerant_members.push(quote!{
618 let (#name, words) = #kind::spirv_parse(words, parse_state)?;
619 });
620 display_enumerant_members.push(quote!{
621 #name.spirv_display(f)?;
622 });
623 }
624 generated_enumerants.push(quote!{
625 #name {
626 #(#enumerant_member_declarations)*
627 }
628 });
629 let enumerant_member_names = &enumerant_member_names;
630 enumerant_parse_cases.push(quote!{
631 #enumerant_value => {
632 #(#parse_enumerant_members)*
633 Ok((#kind_id::#name {
634 #(#enumerant_member_names)*
635 }, words))
636 },
637 });
638 enumerant_display_cases.push(quote!{
639 #kind_id::#name {
640 #(#enumerant_member_names)*
641 } => {
642 write!(f, " {}", #display_name)?;
643 #(#display_enumerant_members)*
644 Ok(())
645 }
646 });
647 }
648 }
649 let mut derives = vec![
650 quote!{Clone},
651 quote!{Debug},
652 quote!{Eq},
653 quote!{PartialEq},
654 quote!{Hash},
655 ];
656 if !has_any_parameters {
657 derives.push(quote!{Copy});
658 }
659 writeln!(
660 &mut out,
661 "{}",
662 quote!{
663 #[derive(#(#derives),*)]
664 pub enum #kind_id {
665 #(#generated_enumerants,)*
666 }
667 }
668 )?;
669 writeln!(
670 &mut out,
671 "{}",
672 quote!{
673 impl SPIRVParse for #kind_id {
674 fn spirv_parse<'a>(
675 words: &'a [u32],
676 parse_state: &mut ParseState,
677 ) -> Result<(Self, &'a [u32])> {
678 let (enumerant, words) = u32::spirv_parse(words, parse_state)?;
679 match enumerant {
680 #(#enumerant_parse_cases)*
681 _ => Err(Error::InvalidEnumValue),
682 }
683 }
684 }
685 }
686 )?;
687 writeln!(
688 &mut out,
689 "{}",
690 quote!{
691 impl SPIRVDisplay for #kind_id {
692 fn spirv_display(&self, f: &mut fmt::Formatter) -> fmt::Result {
693 match self {
694 #(#enumerant_display_cases)*
695 }
696 }
697 }
698 }
699 )?;
700 }
701 ast::OperandKind::Id { kind, .. } => {
702 let base = if *kind == ast::Kind::IdRef {
703 quote!{u32}
704 } else {
705 quote!{IdRef}
706 };
707 let kind_id = new_id(kind, CamelCase);
708 writeln!(
709 &mut out,
710 "{}",
711 quote!{
712 #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Default)]
713 #[repr(transparent)]
714 pub struct #kind_id(pub #base);
715 }
716 )?;
717 if *kind != ast::Kind::IdRef {
718 writeln!(
719 &mut out,
720 "{}",
721 quote!{
722 impl SPIRVParse for #kind_id {
723 fn spirv_parse<'a>(
724 words: &'a [u32],
725 parse_state: &mut ParseState,
726 ) -> Result<(Self, &'a [u32])> {
727 IdRef::spirv_parse(words, parse_state).map(|(value, words)| (#kind_id(value), words))
728 }
729 }
730 }
731 )?;
732 writeln!(
733 &mut out,
734 "{}",
735 quote!{
736 impl fmt::Display for #kind_id {
737 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
738 fmt::Display::fmt(&self.0, f)
739 }
740 }
741 }
742 )?;
743 writeln!(
744 &mut out,
745 "{}",
746 quote!{
747 impl SPIRVDisplay for #kind_id {
748 fn spirv_display(&self, f: &mut fmt::Formatter) -> fmt::Result {
749 self.0.spirv_display(f)
750 }
751 }
752 }
753 )?;
754 }
755 }
756 ast::OperandKind::Literal { kind, .. } => {
757 let kind_id = new_id(kind, CamelCase);
758 writeln!(
759 &mut out,
760 "{}",
761 match kind {
762 ast::LiteralKind::LiteralInteger
763 | ast::LiteralKind::LiteralContextDependentNumber => unreachable!(),
764 ast::LiteralKind::LiteralInteger32
765 | ast::LiteralKind::LiteralContextDependentNumber32 => {
766 quote!{pub type #kind_id = u32;}
767 }
768 ast::LiteralKind::LiteralInteger64
769 | ast::LiteralKind::LiteralContextDependentNumber64 => {
770 quote!{pub type #kind_id = u64;}
771 }
772 ast::LiteralKind::LiteralString => quote!{pub type #kind_id = String;},
773 ast::LiteralKind::LiteralExtInstInteger => {
774 quote!{pub type #kind_id = u32;}
775 }
776 ast::LiteralKind::LiteralSpecConstantOpInteger => continue,
777 }
778 )?;
779 }
780 ast::OperandKind::Composite { kind, bases } => {
781 let kind = new_id(kind, CamelCase);
782 let bases = bases.iter().map(|base| new_id(base, CamelCase));
783 writeln!(&mut out, "{}", quote!{pub type #kind = (#(#bases),*);})?;
784 }
785 }
786 }
787 {
788 let mut instruction_enumerants = Vec::new();
789 let mut spec_constant_op_instruction_enumerants = Vec::new();
790 let mut instruction_parse_cases = Vec::new();
791 let mut instruction_display_cases = Vec::new();
792 let mut instruction_spec_constant_parse_cases = Vec::new();
793 let mut instruction_spec_constant_display_cases = Vec::new();
794 let mut instruction_extension_enumerants = Vec::new();
795 let mut instruction_extension_parse_cases = Vec::new();
796 let mut instruction_extension_display_cases = Vec::new();
797 for parsed_extension_instruction_set in &parsed_extension_instruction_sets {
798 let extension_instruction_set = &parsed_extension_instruction_set.enumerant_name;
799 for instruction in &parsed_extension_instruction_set.ast.instructions {
800 let instruction_enumerant_name = new_combined_id(
801 &[
802 parsed_extension_instruction_set.spirv_instruction_set_name,
803 instruction.opname.as_ref(),
804 ],
805 CamelCase,
806 );
807 let opcode = instruction.opcode;
808 let mut fields = Vec::new();
809 for operand in instruction.operands.iter() {
810 let kind = new_id(&operand.kind, CamelCase);
811 let name = new_id(operand.name.as_ref().unwrap(), SnakeCase);
812 let kind = match &operand.quantifier {
813 None => quote!{#kind},
814 Some(ast::Quantifier::Optional) => quote!{Option<#kind>},
815 Some(ast::Quantifier::Variadic) => quote!{Vec<#kind>},
816 };
817 fields.push(quote!{#name: #kind});
818 }
819 let instruction_extension_enumerant = quote!{
820 #instruction_enumerant_name {
821 id_result_type: IdResultType,
822 id_result: IdResult,
823 set: IdRef,
824 #(#fields,)*
825 }
826 };
827 instruction_extension_enumerants.push(instruction_extension_enumerant);
828 let mut parse_operations = Vec::new();
829 let mut display_operations = Vec::new();
830 let mut operand_names = Vec::new();
831 for operand in &instruction.operands {
832 let kind = new_id(&operand.kind, CamelCase);
833 let name = new_id(operand.name.as_ref().unwrap(), SnakeCase);
834 let kind = match operand.quantifier {
835 None => quote!{#kind},
836 Some(ast::Quantifier::Optional) => quote!{Option::<#kind>},
837 Some(ast::Quantifier::Variadic) => quote!{Vec::<#kind>},
838 };
839 parse_operations.push(quote!{
840 let (#name, words) = #kind::spirv_parse(words, parse_state)?;
841 });
842 display_operations.push(quote!{
843 #name.spirv_display(f)?;
844 });
845 operand_names.push(name);
846 }
847 let operand_names = &operand_names;
848 let body = quote!{
849 #(#parse_operations)*
850 if words.is_empty() {
851 Ok(Instruction::#instruction_enumerant_name {
852 id_result_type,
853 id_result,
854 set,
855 #(#operand_names,)*
856 })
857 } else {
858 Err(Error::InstructionTooLong)
859 }
860 };
861 let instruction_extension_parse_case = quote!{
862 (ExtensionInstructionSet::#extension_instruction_set, #opcode) => {
863 #body
864 }
865 };
866 instruction_extension_parse_cases.push(instruction_extension_parse_case);
867 let display_opname = &instruction.opname;
868 let instruction_extension_display_case = quote!{
869 Instruction::#instruction_enumerant_name {
870 id_result_type,
871 id_result,
872 set,
873 #(#operand_names,)*
874 } => {
875 write!(
876 f,
877 "{}OpExtInst {} {} {}",
878 InstructionIndentAndResult(Some(*id_result)),
879 id_result_type,
880 set,
881 #display_opname,
882 )?;
883 #(#display_operations)*
884 writeln!(f)
885 }
886 };
887 instruction_extension_display_cases.push(instruction_extension_display_case);
888 }
889 }
890 let instruction_extension_parse_cases = &instruction_extension_parse_cases;
891 for instruction in core_instructions.iter() {
892 let opcode = instruction.opcode;
893 let opname = new_id(remove_initial_op(instruction.opname.as_ref()), CamelCase);
894 let display_opname = instruction.opname.as_ref();
895 let display_opname_without_initial_op = remove_initial_op(display_opname);
896 let instruction_parse_case;
897 let instruction_display_case;
898 match &instruction.opname {
899 ast::InstructionName::OpExtInstImport => {
900 let body = quote!{
901 parse_state.define_id(
902 id_result,
903 IdState::ExtensionInstructionSet(ExtensionInstructionSet::from(&*name)),
904 )?;
905 if words.is_empty() {
906 Ok(Instruction::ExtInstImport { id_result, name })
907 } else {
908 Err(Error::InstructionTooLong)
909 }
910 };
911 instruction_parse_case = quote!{#opcode => {
912 let (id_result, words) = IdResult::spirv_parse(words, parse_state)?;
913 let (name, words) = LiteralString::spirv_parse(words, parse_state)?;
914 #body
915 }};
916 instruction_display_case = quote!{
917 Instruction::ExtInstImport { id_result, name } => {
918 writeln!(f, "{}{} {:?}", InstructionIndentAndResult(Some(*id_result)), #display_opname, name)
919 }
920 };
921 }
922 ast::InstructionName::OpExtInst => {
923 let body = quote!{
924 let extension_instruction_set;
925 match parse_state.id_states[set.0 as usize].clone() {
926 IdState::ExtensionInstructionSet(ExtensionInstructionSet::Other(_)) => {
927 let (operands, words) = Vec::<LiteralInteger32>::spirv_parse(words, parse_state)?;
928 if words.is_empty() {
929 return Ok(Instruction::ExtInst {
930 id_result_type,
931 id_result,
932 set,
933 instruction,
934 operands,
935 });
936 } else {
937 return Err(Error::InstructionTooLong);
938 }
939 }
940 IdState::ExtensionInstructionSet(v) => {
941 extension_instruction_set = v;
942 }
943 _ => return Err(Error::IdIsNotExtInstImport(set)),
944 };
945 match (extension_instruction_set, instruction) {
946 #(#instruction_extension_parse_cases)*
947 (extension_instruction_set, instruction) => Err(Error::UnknownExtensionOpcode(extension_instruction_set, instruction)),
948 }
949 };
950 instruction_parse_case = quote!{
951 #opcode => {
952 let (id_result_type, words) = IdResultType::spirv_parse(words, parse_state)?;
953 let (id_result, words) = IdResult::spirv_parse(words, parse_state)?;
954 parse_state.define_value(id_result_type, id_result)?;
955 let (set, words) = IdRef::spirv_parse(words, parse_state)?;
956 let (instruction, words) = LiteralExtInstInteger::spirv_parse(words, parse_state)?;
957 #body
958 }
959 };
960 instruction_display_case = quote!{
961 Instruction::ExtInst {
962 id_result_type,
963 id_result,
964 set,
965 instruction,
966 operands,
967 } => {
968 write!(f, "{}{}", InstructionIndentAndResult(Some(*id_result)), #display_opname)?;
969 id_result_type.spirv_display(f)?;
970 set.spirv_display(f)?;
971 instruction.spirv_display(f)?;
972 operands.spirv_display(f)?;
973 writeln!(f)
974 }
975 };
976 }
977 ast::InstructionName::OpTypeInt => {
978 let body = quote!{
979 let (signedness, words) = LiteralInteger32::spirv_parse(words, parse_state)?;
980 let id_state = match width {
981 8 | 16 | 32 => IdState::Type(IdStateType(BitWidth::Width32OrLess)),
982 64 => IdState::Type(IdStateType(BitWidth::Width64)),
983 _ => return Err(Error::UnsupportedIntSize),
984 };
985 parse_state.define_id(id_result, id_state)?;
986 if words.is_empty() {
987 Ok(Instruction::TypeInt {
988 id_result,
989 width,
990 signedness,
991 })
992 } else {
993 Err(Error::InstructionTooLong)
994 }
995 };
996 instruction_parse_case = quote!{
997 #opcode => {
998 let (id_result, words) = IdResult::spirv_parse(words, parse_state)?;
999 let (width, words) = LiteralInteger32::spirv_parse(words, parse_state)?;
1000 #body
1001 }
1002 };
1003 instruction_display_case = quote!{
1004 Instruction::TypeInt {
1005 id_result,
1006 width,
1007 signedness,
1008 } => {
1009 write!(
1010 f,
1011 "{}{}",
1012 InstructionIndentAndResult(Some(*id_result)),
1013 "OpTypeInt"
1014 )?;
1015 width.spirv_display(f)?;
1016 signedness.spirv_display(f)?;
1017 writeln!(f)
1018 }
1019 };
1020 }
1021 ast::InstructionName::OpTypeFloat => {
1022 instruction_parse_case = quote!{
1023 #opcode => {
1024 let (id_result, words) = IdResult::spirv_parse(words, parse_state)?;
1025 let (width, words) = LiteralInteger32::spirv_parse(words, parse_state)?;
1026 let id_state = match width {
1027 16 | 32 => IdState::Type(IdStateType(BitWidth::Width32OrLess)),
1028 64 => IdState::Type(IdStateType(BitWidth::Width64)),
1029 _ => return Err(Error::UnsupportedFloatSize),
1030 };
1031 parse_state.define_id(id_result, id_state)?;
1032 if words.is_empty() {
1033 Ok(Instruction::TypeFloat {
1034 id_result,
1035 width,
1036 })
1037 } else {
1038 Err(Error::InstructionTooLong)
1039 }
1040 }
1041 };
1042 instruction_display_case = quote!{
1043 Instruction::TypeFloat { id_result, width } => {
1044 write!(
1045 f,
1046 "{}{}",
1047 InstructionIndentAndResult(Some(*id_result)),
1048 "OpTypeFloat"
1049 )?;
1050 width.spirv_display(f)?;
1051 writeln!(f)
1052 }
1053 };
1054 }
1055 ast::InstructionName::OpSwitch32 => {
1056 let body32 = quote!{
1057 IdState::Value(IdStateValue(BitWidth::Width32OrLess)) => {
1058 let (target, words) = Vec::<PairLiteralInteger32IdRef>::spirv_parse(words, parse_state)?;
1059 if words.is_empty() {
1060 Ok(Instruction::Switch32 {
1061 selector,
1062 default,
1063 target,
1064 })
1065 } else {
1066 Err(Error::InstructionTooLong)
1067 }
1068 }
1069 };
1070 let body64 = quote!{
1071 IdState::Value(IdStateValue(BitWidth::Width64)) => {
1072 let (target, words) = Vec::<PairLiteralInteger64IdRef>::spirv_parse(words, parse_state)?;
1073 if words.is_empty() {
1074 Ok(Instruction::Switch64 {
1075 selector,
1076 default,
1077 target,
1078 })
1079 } else {
1080 Err(Error::InstructionTooLong)
1081 }
1082 }
1083 };
1084 instruction_parse_case = quote!{
1085 #opcode => {
1086 let (selector, words) = IdRef::spirv_parse(words, parse_state)?;
1087 let (default, words) = IdRef::spirv_parse(words, parse_state)?;
1088 match &parse_state.id_states[selector.0 as usize] {
1089 #body32
1090 #body64
1091 _ => Err(Error::SwitchSelectorIsInvalid(selector)),
1092 }
1093 }
1094 };
1095 instruction_display_case = quote!{
1096 Instruction::Switch32 {
1097 selector,
1098 default,
1099 target,
1100 } => {
1101 write!(
1102 f,
1103 "{}{}",
1104 InstructionIndentAndResult(None),
1105 "OpSwitch"
1106 )?;
1107 selector.spirv_display(f)?;
1108 default.spirv_display(f)?;
1109 target.spirv_display(f)?;
1110 writeln!(f)
1111 }
1112 Instruction::Switch64 {
1113 selector,
1114 default,
1115 target,
1116 } => {
1117 write!(
1118 f,
1119 "{}{}",
1120 InstructionIndentAndResult(None),
1121 "OpSwitch"
1122 )?;
1123 selector.spirv_display(f)?;
1124 default.spirv_display(f)?;
1125 target.spirv_display(f)?;
1126 writeln!(f)
1127 }
1128 };
1129 }
1130 ast::InstructionName::OpSwitch64 => {
1131 instruction_parse_case = quote!{};
1132 instruction_display_case = quote!{};
1133 }
1134 ast::InstructionName::OpConstant32 => {
1135 let body32 = quote!{
1136 IdStateType(BitWidth::Width32OrLess) => {
1137 let (value, words) = LiteralContextDependentNumber32::spirv_parse(words, parse_state)?;
1138 if words.is_empty() {
1139 Ok(Instruction::Constant32 {
1140 id_result_type,
1141 id_result,
1142 value,
1143 })
1144 } else {
1145 Err(Error::InstructionTooLong)
1146 }
1147 }
1148 };
1149 let body64 = quote!{
1150 IdStateType(BitWidth::Width64) => {
1151 let (value, words) = LiteralContextDependentNumber64::spirv_parse(words, parse_state)?;
1152 if words.is_empty() {
1153 Ok(Instruction::Constant64 {
1154 id_result_type,
1155 id_result,
1156 value,
1157 })
1158 } else {
1159 Err(Error::InstructionTooLong)
1160 }
1161 }
1162 };
1163 instruction_parse_case = quote!{
1164 #opcode => {
1165 let (id_result_type, words) = IdResultType::spirv_parse(words, parse_state)?;
1166 let (id_result, words) = IdResult::spirv_parse(words, parse_state)?;
1167 parse_state.define_value(id_result_type, id_result)?;
1168 match parse_state.get_type(id_result_type.0)? {
1169 #body32
1170 #body64
1171 }
1172 }
1173 };
1174 instruction_display_case = quote!{
1175 Instruction::Constant32 {
1176 id_result_type,
1177 id_result,
1178 value,
1179 } => {
1180 write!(
1181 f,
1182 "{}{}",
1183 InstructionIndentAndResult(Some(*id_result)),
1184 "OpConstant"
1185 )?;
1186 id_result_type.spirv_display(f)?;
1187 writeln!(f, " {:#010X}", value)
1188 }
1189 Instruction::Constant64 {
1190 id_result_type,
1191 id_result,
1192 value,
1193 } => {
1194 write!(
1195 f,
1196 "{}{}",
1197 InstructionIndentAndResult(Some(*id_result)),
1198 "OpConstant"
1199 )?;
1200 id_result_type.spirv_display(f)?;
1201 writeln!(f, " {:#018X}", value)
1202 }
1203 };
1204 }
1205 ast::InstructionName::OpConstant64 => {
1206 instruction_parse_case = quote!{};
1207 instruction_display_case = quote!{};
1208 }
1209 ast::InstructionName::OpSpecConstant32 => {
1210 let body32 = quote!{
1211 IdStateType(BitWidth::Width32OrLess) => {
1212 let (value, words) = LiteralContextDependentNumber32::spirv_parse(words, parse_state)?;
1213 if words.is_empty() {
1214 Ok(Instruction::SpecConstant32 {
1215 id_result_type,
1216 id_result,
1217 value,
1218 })
1219 } else {
1220 Err(Error::InstructionTooLong)
1221 }
1222 }
1223 };
1224 let body64 = quote!{
1225 IdStateType(BitWidth::Width64) => {
1226 let (value, words) = LiteralContextDependentNumber64::spirv_parse(words, parse_state)?;
1227 if words.is_empty() {
1228 Ok(Instruction::SpecConstant64 {
1229 id_result_type,
1230 id_result,
1231 value,
1232 })
1233 } else {
1234 Err(Error::InstructionTooLong)
1235 }
1236 }
1237 };
1238 instruction_parse_case = quote!{
1239 #opcode => {
1240 let (id_result_type, words) = IdResultType::spirv_parse(words, parse_state)?;
1241 let (id_result, words) = IdResult::spirv_parse(words, parse_state)?;
1242 parse_state.define_value(id_result_type, id_result)?;
1243 match parse_state.get_type(id_result_type.0)? {
1244 #body32
1245 #body64
1246 }
1247 }
1248 };
1249 instruction_display_case = quote!{
1250 Instruction::SpecConstant32 {
1251 id_result_type,
1252 id_result,
1253 value,
1254 } => {
1255 write!(
1256 f,
1257 "{}{}",
1258 InstructionIndentAndResult(Some(*id_result)),
1259 "OpSpecConstant"
1260 )?;
1261 id_result_type.spirv_display(f)?;
1262 writeln!(f, " {:#010X}", value)
1263 }
1264 Instruction::SpecConstant64 {
1265 id_result_type,
1266 id_result,
1267 value,
1268 } => {
1269 write!(
1270 f,
1271 "{}{}",
1272 InstructionIndentAndResult(Some(*id_result)),
1273 "OpSpecConstant"
1274 )?;
1275 id_result_type.spirv_display(f)?;
1276 writeln!(f, " {:#018X}", value)
1277 }
1278 };
1279 }
1280 ast::InstructionName::OpSpecConstant64 => {
1281 instruction_parse_case = quote!{};
1282 instruction_display_case = quote!{};
1283 }
1284 ast::InstructionName::OpSpecConstantOp => {
1285 instruction_parse_case = quote!{#opcode => {
1286 let (operation, words) = OpSpecConstantOp::spirv_parse(words, parse_state)?;
1287 if words.is_empty() {
1288 Ok(Instruction::#opname { operation })
1289 } else {
1290 Err(Error::InstructionTooLong)
1291 }
1292 }};
1293 instruction_display_case = quote!{
1294 Instruction::#opname { operation } => fmt::Display::fmt(operation, f),
1295 };
1296 }
1297 _ => {
1298 let mut parse_operations = Vec::new();
1299 let mut display_operations = Vec::new();
1300 let mut operand_names = Vec::new();
1301 let mut result_name = None;
1302 for operand in &instruction.operands {
1303 let kind = new_id(&operand.kind, CamelCase);
1304 let name = new_id(operand.name.as_ref().unwrap(), SnakeCase);
1305 let kind = match operand.quantifier {
1306 None => quote!{#kind},
1307 Some(ast::Quantifier::Optional) => quote!{Option::<#kind>},
1308 Some(ast::Quantifier::Variadic) => quote!{Vec::<#kind>},
1309 };
1310 parse_operations.push(quote!{
1311 let (#name, words) = #kind::spirv_parse(words, parse_state)?;
1312 });
1313 operand_names.push(name.clone());
1314 if operand.kind == ast::Kind::IdResult {
1315 assert_eq!(result_name, None);
1316 result_name = Some(name);
1317 } else {
1318 display_operations.push(quote!{
1319 #name.spirv_display(f)?;
1320 });
1321 }
1322 }
1323 if let Some([operand1, operand2]) = instruction.operands.get(..2) {
1324 if operand1.kind == ast::Kind::IdResultType
1325 && operand2.kind == ast::Kind::IdResult
1326 {
1327 let operand1_name = new_id(operand1.name.as_ref().unwrap(), SnakeCase);
1328 let operand2_name = new_id(operand2.name.as_ref().unwrap(), SnakeCase);
1329 parse_operations.push(quote!{
1330 parse_state.define_value(#operand1_name, #operand2_name)?;
1331 });
1332 }
1333 }
1334 let operand_names = &operand_names;
1335 instruction_parse_case = quote!{#opcode => {
1336 #(#parse_operations)*
1337 if words.is_empty() {
1338 Ok(Instruction::#opname {
1339 #(#operand_names,)*
1340 })
1341 } else {
1342 Err(Error::InstructionTooLong)
1343 }
1344 }};
1345 let result_value = match result_name {
1346 None => quote!{None},
1347 Some(result_name) => quote!{Some(*#result_name)},
1348 };
1349 instruction_display_case = quote!{
1350 Instruction::#opname { #(#operand_names,)* } => {
1351 write!(f, "{}{}", InstructionIndentAndResult(#result_value), #display_opname)?;
1352 #(#display_operations)*
1353 writeln!(f)
1354 }
1355 };
1356 }
1357 }
1358 instruction_parse_cases.push(instruction_parse_case);
1359 instruction_display_cases.push(instruction_display_case);
1360 let instruction_enumerant =
1361 if instruction.opname == ast::InstructionName::OpSpecConstantOp {
1362 quote!{
1363 #opname {
1364 operation: OpSpecConstantOp,
1365 }
1366 }
1367 } else if instruction.operands.is_empty() {
1368 quote!{#opname}
1369 } else {
1370 let mut fields = Vec::new();
1371 for operand in instruction.operands.iter() {
1372 let kind = new_id(&operand.kind, CamelCase);
1373 let name = new_id(operand.name.as_ref().unwrap(), SnakeCase);
1374 let kind = match &operand.quantifier {
1375 None => quote!{#kind},
1376 Some(ast::Quantifier::Optional) => quote!{Option<#kind>},
1377 Some(ast::Quantifier::Variadic) => quote!{Vec<#kind>},
1378 };
1379 fields.push(quote!{#name: #kind});
1380 }
1381 quote!{
1382 #opname {
1383 #(#fields,)*
1384 }
1385 }
1386 };
1387 if ast::OP_SPEC_CONSTANT_OP_SUPPORTED_INSTRUCTIONS.contains(&instruction.opname) {
1388 let opcode = u32::from(opcode);
1389 spec_constant_op_instruction_enumerants.push(instruction_enumerant.clone());
1390 let mut parse_operations = Vec::new();
1391 let mut display_operations = Vec::new();
1392 let mut operand_names = Vec::new();
1393 operand_names.push(new_id("id_result_type", SnakeCase));
1394 operand_names.push(new_id("id_result", SnakeCase));
1395 for operand in instruction.operands.iter().skip(2) {
1396 let kind = new_id(&operand.kind, CamelCase);
1397 let name = new_id(operand.name.as_ref().unwrap(), SnakeCase);
1398 let kind = match operand.quantifier {
1399 None => quote!{#kind},
1400 Some(ast::Quantifier::Optional) => quote!{Option::<#kind>},
1401 Some(ast::Quantifier::Variadic) => quote!{Vec::<#kind>},
1402 };
1403 parse_operations.push(quote!{
1404 let (#name, words) = #kind::spirv_parse(words, parse_state)?;
1405 });
1406 display_operations.push(quote!{
1407 #name.spirv_display(f)?;
1408 });
1409 operand_names.push(name);
1410 }
1411 if let Some([operand1, operand2]) = instruction.operands.get(..2) {
1412 assert_eq!(operand1.kind, ast::Kind::IdResultType);
1413 assert_eq!(operand2.kind, ast::Kind::IdResult);
1414 let operand1_name = new_id(operand1.name.as_ref().unwrap(), SnakeCase);
1415 let operand2_name = new_id(operand2.name.as_ref().unwrap(), SnakeCase);
1416 parse_operations.push(quote!{
1417 parse_state.define_value(#operand1_name, #operand2_name)?;
1418 });
1419 } else {
1420 assert!(
1421 false,
1422 "spec constant op is missing id_result_type and id_result"
1423 );
1424 }
1425 let operand_names = &operand_names;
1426 instruction_spec_constant_parse_cases.push(quote!{#opcode => {
1427 #(#parse_operations)*
1428 if words.is_empty() {
1429 Ok((OpSpecConstantOp::#opname {
1430 #(#operand_names,)*
1431 }, words))
1432 } else {
1433 Err(Error::InstructionTooLong)
1434 }
1435 }});
1436 instruction_spec_constant_display_cases.push(quote!{
1437 OpSpecConstantOp::#opname {
1438 #(#operand_names,)*
1439 } => {
1440 write!(f, "{}{}", InstructionIndentAndResult(Some(*id_result)), "OpSpecConstantOp")?;
1441 id_result_type.spirv_display(f)?;
1442 write!(f, " {}", #display_opname_without_initial_op)?;
1443 #(#display_operations)*
1444 writeln!(f)
1445 }
1446 });
1447 }
1448 instruction_enumerants.push(instruction_enumerant);
1449 }
1450 writeln!(
1451 &mut out,
1452 "{}",
1453 quote!{
1454 #[derive(Clone, Debug)]
1455 pub enum OpSpecConstantOp {
1456 #(#spec_constant_op_instruction_enumerants,)*
1457 }
1458 }
1459 )?;
1460 writeln!(
1461 &mut out,
1462 "{}",
1463 quote!{
1464 impl fmt::Display for OpSpecConstantOp {
1465 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1466 match self {
1467 #(#instruction_spec_constant_display_cases)*
1468 }
1469 }
1470 }
1471 }
1472 )?;
1473 writeln!(
1474 &mut out,
1475 "{}",
1476 quote!{
1477 #[derive(Clone, Debug)]
1478 pub enum Instruction {
1479 #(#instruction_enumerants,)*
1480 #(#instruction_extension_enumerants,)*
1481 }
1482 }
1483 )?;
1484 writeln!(
1485 &mut out,
1486 "{}",
1487 stringify!(
1488 #[derive(Copy, Clone, Debug)]
1489 pub struct Header {
1490 pub version: (u32, u32),
1491 pub generator: u32,
1492 pub bound: u32,
1493 pub instruction_schema: u32,
1494 }
1495
1496 impl fmt::Display for Header {
1497 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1498 writeln!(f, "; SPIR-V")?;
1499 writeln!(f, "; Version: {}.{}", self.version.0, self.version.1)?;
1500 writeln!(f, "; Generator: {:#X}", self.generator)?;
1501 writeln!(f, "; Bound: {}", self.bound)?;
1502 writeln!(f, "; Schema: {}", self.instruction_schema)
1503 }
1504 }
1505
1506 struct InstructionIndentAndResult(Option<IdResult>);
1507
1508 impl fmt::Display for InstructionIndentAndResult {
1509 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1510 write!(f, "{:>15}", self.0.map(|v| format!("{} = ", v.0)).unwrap_or_default())
1511 }
1512 }
1513
1514 impl fmt::Display for IdRef {
1515 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1516 write!(f, "%{}", self.0)
1517 }
1518 }
1519
1520 #[derive(Clone, Debug)]
1521 pub enum Error {
1522 MissingHeader,
1523 InvalidHeader,
1524 BoundTooBig(u32),
1525 UnsupportedVersion(u32, u32),
1526 ZeroInstructionLength,
1527 SourcePrematurelyEnded,
1528 UnknownOpcode(u16),
1529 UnknownSpecConstantOpcode(u32),
1530 UnknownExtensionOpcode(ExtensionInstructionSet, u32),
1531 Utf8Error(Utf8Error),
1532 InstructionPrematurelyEnded,
1533 InvalidStringTermination,
1534 InstructionTooLong,
1535 InvalidEnumValue,
1536 IdOutOfBounds(u32),
1537 IdAlreadyDefined(IdResult),
1538 UnsupportedFloatSize,
1539 UnsupportedIntSize,
1540 UndefinedType(IdRef),
1541 SwitchSelectorIsInvalid(IdRef),
1542 IdIsNotExtInstImport(IdRef),
1543 }
1544
1545 impl From<Utf8Error> for Error {
1546 fn from(v: Utf8Error) -> Self {
1547 Error::Utf8Error(v)
1548 }
1549 }
1550
1551 impl From<FromUtf8Error> for Error {
1552 fn from(v: FromUtf8Error) -> Self {
1553 Error::Utf8Error(v.utf8_error())
1554 }
1555 }
1556
1557 impl fmt::Display for Error {
1558 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1559 match *self {
1560 Error::MissingHeader => write!(f, "SPIR-V source is missing the file header"),
1561 Error::InvalidHeader => write!(f, "SPIR-V source has an invalid file header"),
1562 Error::BoundTooBig(bound) => write!(
1563 f,
1564 "SPIR-V source has an invalid file header; the id bound is way bigger than needed: {}",
1565 bound,
1566 ),
1567 Error::UnsupportedVersion(major, minor) => write!(
1568 f,
1569 "SPIR-V source has an unsupported version: {}.{}",
1570 major,
1571 minor
1572 ),
1573 Error::ZeroInstructionLength => write!(f, "SPIR-V instruction has a length of zero"),
1574 Error::SourcePrematurelyEnded => write!(f, "SPIR-V source prematurely ended"),
1575 Error::UnknownOpcode(opcode) => {
1576 write!(f, "SPIR-V instruction has an unknown opcode: {}", opcode)
1577 }
1578 Error::UnknownSpecConstantOpcode(opcode) => {
1579 write!(f, "SPIR-V OpSpecConstantOp instruction has an unknown opcode: {}", opcode)
1580 }
1581 Error::UnknownExtensionOpcode(ref extension_instruction_set, opcode) => {
1582 write!(f, "SPIR-V OpExtInst instruction has an unknown opcode: {} in {}", opcode, extension_instruction_set)
1583 }
1584 Error::Utf8Error(error) => fmt::Display::fmt(&error, f),
1585 Error::InstructionPrematurelyEnded => write!(f, "SPIR-V instruction prematurely ended"),
1586 Error::InvalidStringTermination => write!(f, "SPIR-V LiteralString has an invalid termination word"),
1587 Error::InstructionTooLong => write!(f, "SPIR-V instruction is too long"),
1588 Error::InvalidEnumValue => write!(f, "enum has invalid value"),
1589 Error::IdOutOfBounds(id) => write!(f, "id is out of bounds: {}", id),
1590 Error::IdAlreadyDefined(id) => write!(f, "id is already defined: {}", id),
1591 Error::UnsupportedFloatSize => write!(f, "unsupported float size"),
1592 Error::UnsupportedIntSize => write!(f, "unsupported int size"),
1593 Error::UndefinedType(id) => write!(f, "undefined type {}", id),
1594 Error::SwitchSelectorIsInvalid(id) => write!(f, "Switch selector is invalid: {}", id),
1595 Error::IdIsNotExtInstImport(id) => write!(f, "id is not the result of an OpExtInstImport instruction: {}", id),
1596 }
1597 }
1598 }
1599
1600 impl error::Error for Error {}
1601
1602 type Result<T> = result::Result<T, Error>;
1603
1604 #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
1605 enum BitWidth {
1606 Width32OrLess,
1607 Width64,
1608 }
1609
1610 #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
1611 struct IdStateType(BitWidth);
1612
1613 #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
1614 struct IdStateValue(BitWidth);
1615
1616 #[derive(Clone, Debug, Eq, PartialEq, Hash)]
1617 enum IdState {
1618 Unknown,
1619 Type(IdStateType),
1620 Value(IdStateValue),
1621 ExtensionInstructionSet(ExtensionInstructionSet),
1622 }
1623
1624 #[derive(Clone, Debug)]
1625 struct ParseState {
1626 id_states: Vec<IdState>,
1627 }
1628
1629 impl ParseState {
1630 fn define_id(&mut self, id_result: IdResult, new_id_state: IdState) -> Result<()> {
1631 let id_state = &mut self.id_states[(id_result.0).0 as usize];
1632 if *id_state != IdState::Unknown {
1633 return Err(Error::IdAlreadyDefined(id_result));
1634 }
1635 *id_state = new_id_state;
1636 Ok(())
1637 }
1638 fn get_type(&self, id: IdRef) -> Result<IdStateType> {
1639 if let IdState::Type(retval) = self.id_states[id.0 as usize] {
1640 Ok(retval)
1641 } else {
1642 Err(Error::UndefinedType(id))
1643 }
1644 }
1645 fn define_value(&mut self, id_result_type: IdResultType, id_result: IdResult) -> Result<()> {
1646 if let IdState::Type(IdStateType(bit_width)) = self.id_states[(id_result_type.0).0 as usize] {
1647 self.define_id(id_result, IdState::Value(IdStateValue(bit_width)))?;
1648 }
1649 Ok(())
1650 }
1651 }
1652
1653 #[derive(Clone, Debug)]
1654 pub struct Parser<'a> {
1655 words: &'a [u32],
1656 header: Header,
1657 parse_state: ParseState,
1658 }
1659
1660 fn parse_version(v: u32) -> Result<(u32, u32)> {
1661 if (v & 0xFF0000FF) != 0 {
1662 return Err(Error::InvalidHeader);
1663 }
1664 let major = (v >> 16) & 0xFF;
1665 let minor = (v >> 8) & 0xFF;
1666 Ok((major, minor))
1667 }
1668
1669 impl<'a> Parser<'a> {
1670 pub fn header(&self) -> &Header {
1671 &self.header
1672 }
1673 pub fn start(mut words: &'a [u32]) -> Result<Self> {
1674 let header = words.get(0..5).ok_or(Error::MissingHeader)?;
1675 words = &words[5..];
1676 let header = match *header {
1677 [MAGIC_NUMBER, version, generator, bound, instruction_schema @ 0] if bound >= 1 => {
1678 let version = parse_version(version)?;
1679 if version.0 != MAJOR_VERSION || version.1 > MINOR_VERSION {
1680 return Err(Error::UnsupportedVersion(version.0, version.1));
1681 }
1682 Header {
1683 version,
1684 generator,
1685 bound,
1686 instruction_schema,
1687 }
1688 }
1689 _ => return Err(Error::InvalidHeader),
1690 };
1691 if header.bound as usize > words.len() && header.bound > 0x10000 {
1692 Err(Error::BoundTooBig(header.bound))
1693 } else {
1694 Ok(Self {
1695 words,
1696 header,
1697 parse_state: ParseState {
1698 id_states: vec![IdState::Unknown; header.bound as usize],
1699 },
1700 })
1701 }
1702 }
1703 fn next_helper(&mut self, length_and_opcode: u32) -> Result<Instruction> {
1704 let length = (length_and_opcode >> 16) as usize;
1705 let opcode = length_and_opcode as u16;
1706 if length == 0 {
1707 return Err(Error::ZeroInstructionLength);
1708 }
1709 let instruction_words = self.words.get(1..length).ok_or(Error::SourcePrematurelyEnded)?;
1710 self.words = &self.words[length..];
1711 parse_instruction(opcode, instruction_words, &mut self.parse_state)
1712 }
1713 }
1714
1715 impl<'a> Iterator for Parser<'a> {
1716 type Item = Result<Instruction>;
1717 fn next(&mut self) -> Option<Result<Instruction>> {
1718 let length_and_opcode = self.words.get(0)?;
1719 Some(self.next_helper(*length_and_opcode))
1720 }
1721 }
1722 )
1723 )?;
1724 writeln!(
1725 &mut out,
1726 "{}",
1727 quote!{
1728 fn parse_instruction(opcode: u16, words: &[u32], parse_state: &mut ParseState) -> Result<Instruction> {
1729 match opcode {
1730 #(#instruction_parse_cases)*
1731 opcode => Err(Error::UnknownOpcode(opcode)),
1732 }
1733 }
1734 }
1735 )?;
1736 writeln!(
1737 &mut out,
1738 "{}",
1739 quote!{
1740 impl fmt::Display for Instruction {
1741 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1742 match self {
1743 #(#instruction_display_cases)*
1744 #(#instruction_extension_display_cases)*
1745 }
1746 }
1747 }
1748 }
1749 )?;
1750 let body = quote!{
1751 let (id_result_type, words) = IdResultType::spirv_parse(words, parse_state)?;
1752 let (id_result, words) = IdResult::spirv_parse(words, parse_state)?;
1753 let (opcode, words) = u32::spirv_parse(words, parse_state)?;
1754 match opcode {
1755 #(#instruction_spec_constant_parse_cases)*
1756 opcode => Err(Error::UnknownSpecConstantOpcode(opcode)),
1757 }
1758 };
1759 writeln!(
1760 &mut out,
1761 "{}",
1762 quote!{
1763 impl SPIRVParse for OpSpecConstantOp {
1764 fn spirv_parse<'a>(
1765 words: &'a [u32],
1766 parse_state: &mut ParseState
1767 ) -> Result<(Self, &'a [u32])> {
1768 #body
1769 }
1770 }
1771 }
1772 )?;
1773 }
1774 {
1775 let extension_instruction_set_enumerants: Vec<_> = parsed_extension_instruction_sets
1776 .iter()
1777 .map(|v| &v.enumerant_name)
1778 .collect();
1779 let extension_instruction_set_enumerants = &extension_instruction_set_enumerants;
1780 let spirv_instruction_set_names: Vec<_> = parsed_extension_instruction_sets
1781 .iter()
1782 .map(|v| v.spirv_instruction_set_name)
1783 .collect();
1784 let spirv_instruction_set_names = &spirv_instruction_set_names;
1785 for parsed_extension_instruction_set in parsed_extension_instruction_sets.iter() {
1786 let version_name = new_combined_id(
1787 &[
1788 parsed_extension_instruction_set.spirv_instruction_set_name,
1789 "version",
1790 ],
1791 UppercaseSnakeCase,
1792 );
1793 let version = parsed_extension_instruction_set.ast.version;
1794 let revision_name = new_combined_id(
1795 &[
1796 parsed_extension_instruction_set.spirv_instruction_set_name,
1797 "revision",
1798 ],
1799 UppercaseSnakeCase,
1800 );
1801 let revision = parsed_extension_instruction_set.ast.revision;
1802 writeln!(
1803 &mut out,
1804 "{}",
1805 quote!{
1806 pub const #version_name: u32 = #version;
1807 pub const #revision_name: u32 = #revision;
1808 }
1809 )?;
1810 }
1811 writeln!(
1812 &mut out,
1813 "{}",
1814 quote!{
1815 #[derive(Clone, Eq, PartialEq, Hash, Debug)]
1816 pub enum ExtensionInstructionSet {
1817 #(#extension_instruction_set_enumerants,)*
1818 Other(String),
1819 }
1820 }
1821 )?;
1822 writeln!(
1823 &mut out,
1824 "{}",
1825 quote!{
1826 impl<'a> From<Cow<'a, str>> for ExtensionInstructionSet {
1827 fn from(s: Cow<'a, str>) -> ExtensionInstructionSet {
1828 match s.as_ref() {
1829 #(#spirv_instruction_set_names => return ExtensionInstructionSet::#extension_instruction_set_enumerants,)*
1830 _ => {}
1831 }
1832 ExtensionInstructionSet::Other(s.into_owned())
1833 }
1834 }
1835 }
1836 )?;
1837 writeln!(
1838 &mut out,
1839 "{}",
1840 quote!{
1841 impl Deref for ExtensionInstructionSet {
1842 type Target = str;
1843 fn deref(&self) -> &str {
1844 match self {
1845 #(ExtensionInstructionSet::#extension_instruction_set_enumerants => #spirv_instruction_set_names,)*
1846 ExtensionInstructionSet::Other(s) => &**s,
1847 }
1848 }
1849 }
1850 }
1851 )?;
1852 writeln!(
1853 &mut out,
1854 "{}",
1855 stringify!(
1856 impl AsRef<str> for ExtensionInstructionSet {
1857 fn as_ref(&self) -> &str {
1858 &**self
1859 }
1860 }
1861
1862 impl From<ExtensionInstructionSet> for String {
1863 fn from(v: ExtensionInstructionSet) -> String {
1864 match v {
1865 ExtensionInstructionSet::Other(v) => v,
1866 v => String::from(v.as_ref()),
1867 }
1868 }
1869 }
1870
1871 impl<'a> From<&'a str> for ExtensionInstructionSet {
1872 fn from(s: &'a str) -> Self {
1873 Cow::Borrowed(s).into()
1874 }
1875 }
1876
1877 impl From<String> for ExtensionInstructionSet {
1878 fn from(s: String) -> Self {
1879 Self::from(Cow::Owned(s))
1880 }
1881 }
1882
1883 impl fmt::Display for ExtensionInstructionSet {
1884 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1885 let s: &str = &**self;
1886 fmt::Display::fmt(s, f)
1887 }
1888 }
1889 )
1890 )?;
1891 }
1892 let source = String::from_utf8(out).unwrap();
1893 let source = match format_source(&options, &source) {
1894 Ok(source) => source.into_owned(),
1895 Err(error) => {
1896 eprintln!("formatting source failed: {}", error);
1897 source.clone()
1898 }
1899 };
1900 Ok(source)
1901 }