1 // SPDX-License-Identifier: LGPL-2.1-or-later
2 // Copyright 2018 Jacob Lifshay
4 // allow unneeded_field_pattern to ensure fields aren't accidently missed
5 #![cfg_attr(feature = "cargo-clippy", allow(clippy::unneeded_field_pattern))]
9 extern crate proc_macro2;
11 extern crate serde_derive;
13 extern crate serde_json;
16 use std::collections::HashMap;
22 use std::path::PathBuf;
28 pub const SPIRV_CORE_GRAMMAR_JSON_FILE_NAME: &str = "spirv.core.grammar.json";
30 #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
31 pub enum ExtensionInstructionSet {
36 impl ExtensionInstructionSet {
37 pub fn get_grammar_json_file_name(self) -> &'static str {
39 ExtensionInstructionSet::GLSLStd450 => "extinst.glsl.std.450.grammar.json",
40 ExtensionInstructionSet::OpenCLStd => "extinst.opencl.std.100.grammar.json",
48 JSONError(serde_json::Error),
49 DeducingNameForInstructionOperandFailed,
50 DeducingNameForEnumerantParameterFailed,
53 impl From<io::Error> for Error {
54 fn from(v: io::Error) -> Error {
59 impl From<serde_json::Error> for Error {
60 fn from(v: serde_json::Error) -> Error {
61 if let serde_json::error::Category::Io = v.classify() {
62 Error::IOError(v.into())
69 impl fmt::Display for Error {
70 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
72 Error::IOError(v) => fmt::Display::fmt(v, f),
73 Error::JSONError(v) => fmt::Display::fmt(v, f),
74 Error::DeducingNameForInstructionOperandFailed => {
75 write!(f, "deducing name for InstructionOperand failed")
77 Error::DeducingNameForEnumerantParameterFailed => {
78 write!(f, "deducing name for EnumerantParameter failed")
84 impl error::Error for Error {}
86 impl From<Error> for io::Error {
87 fn from(error: Error) -> Self {
89 Error::IOError(v) => v,
90 Error::JSONError(v) => v.into(),
91 error @ Error::DeducingNameForInstructionOperandFailed
92 | error @ Error::DeducingNameForEnumerantParameterFailed => {
93 io::Error::new(io::ErrorKind::Other, format!("{}", error))
104 pub fn to_str(&self) -> &str {
107 pub fn into_string(self) -> String {
110 pub fn write<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
111 write!(writer, "{}", self.text)
113 pub fn write_to_file<T: AsRef<Path>>(&self, path: T) -> Result<(), io::Error> {
114 self.write(File::create(path)?)
120 rustfmt_path: Option<PathBuf>,
123 impl Default for Options {
124 fn default() -> Self {
133 spirv_core_grammar_json_path: PathBuf,
134 extension_instruction_sets: HashMap<ExtensionInstructionSet, PathBuf>,
138 fn get_spirv_grammar_path<T: AsRef<Path>>(name: T) -> PathBuf {
139 Path::new(env!("CARGO_MANIFEST_DIR"))
140 .join("../external/SPIRV-Headers/include/spirv/unified1")
145 pub fn with_default_paths(extension_instruction_sets: &[ExtensionInstructionSet]) -> Input {
146 let mut retval = Self::new(get_spirv_grammar_path("spirv.core.grammar.json"));
147 for &extension_instruction_set in extension_instruction_sets {
148 retval = retval.add_extension_instruction_set(
149 extension_instruction_set,
150 get_spirv_grammar_path(extension_instruction_set.get_grammar_json_file_name()),
155 pub fn new<T: AsRef<Path>>(spirv_core_grammar_json_path: T) -> Input {
157 spirv_core_grammar_json_path: spirv_core_grammar_json_path.as_ref().into(),
158 extension_instruction_sets: HashMap::new(),
159 options: Options::default(),
163 pub fn add_extension_instruction_set<T: AsRef<Path>>(
165 extension_instruction_set: ExtensionInstructionSet,
169 self.extension_instruction_sets
170 .insert(extension_instruction_set, path.as_ref().into())
172 "duplicate extension instruction set: {:?}",
173 extension_instruction_set
177 pub fn generate(self) -> Result<Output, Error> {
179 spirv_core_grammar_json_path,
180 extension_instruction_sets,
183 let mut core_grammar: ast::CoreGrammar =
184 serde_json::from_reader(File::open(spirv_core_grammar_json_path)?)?;
185 core_grammar.fixup()?;
186 let mut parsed_extension_instruction_sets: HashMap<
187 ExtensionInstructionSet,
188 ast::ExtensionInstructionSet,
189 > = Default::default();
190 for (extension_instruction_set, path) in extension_instruction_sets {
191 let mut parsed_extension_instruction_set: ast::ExtensionInstructionSet =
192 serde_json::from_reader(File::open(path)?)?;
193 parsed_extension_instruction_set.fixup()?;
194 assert!(parsed_extension_instruction_sets
195 .insert(extension_instruction_set, parsed_extension_instruction_set)
199 text: generate::generate(core_grammar, parsed_extension_instruction_sets, &options)?,
209 fn parse_core_grammar() -> Result<(), Error> {
210 Input::with_default_paths(&[]).generate()?;
215 fn parse_core_grammar_with_opencl() -> Result<(), Error> {
216 Input::with_default_paths(&[ExtensionInstructionSet::OpenCLStd]).generate()?;
221 fn parse_core_grammar_with_opencl_and_glsl() -> Result<(), Error> {
222 Input::with_default_paths(&[
223 ExtensionInstructionSet::OpenCLStd,
224 ExtensionInstructionSet::GLSLStd450,
231 fn parse_core_grammar_with_glsl() -> Result<(), Error> {
232 Input::with_default_paths(&[ExtensionInstructionSet::GLSLStd450]).generate()?;