working on parser generator
[kazan.git] / spirv-parser-generator / src / lib.rs
1 // SPDX-License-Identifier: LGPL-2.1-or-later
2 // Copyright 2018 Jacob Lifshay
3
4 #[macro_use]
5 extern crate serde_derive;
6 extern crate serde;
7 extern crate serde_json;
8
9 use std::collections::HashMap;
10 use std::error;
11 use std::fmt;
12 use std::fs::File;
13 use std::io;
14 use std::path::Path;
15 use std::path::PathBuf;
16
17 mod ast;
18 mod util;
19
20 pub const SPIRV_CORE_GRAMMAR_JSON_FILE_NAME: &str = "spirv.core.grammar.json";
21
22 #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
23 pub enum ExtensionInstructionSet {
24 GLSLStd450,
25 OpenCLStd,
26 }
27
28 impl ExtensionInstructionSet {
29 pub fn get_grammar_json_file_name(self) -> &'static str {
30 match self {
31 ExtensionInstructionSet::GLSLStd450 => "extinst.glsl.std.450.grammar.json",
32 ExtensionInstructionSet::OpenCLStd => "extinst.opencl.std.100.grammar.json",
33 }
34 }
35 }
36
37 #[derive(Debug)]
38 pub enum Error {
39 IOError(io::Error),
40 JSONError(serde_json::Error),
41 DeducingNameForInstructionOperandFailed,
42 DeducingNameForEnumerantParameterFailed,
43 }
44
45 impl From<io::Error> for Error {
46 fn from(v: io::Error) -> Error {
47 Error::IOError(v)
48 }
49 }
50
51 impl From<serde_json::Error> for Error {
52 fn from(v: serde_json::Error) -> Error {
53 if let serde_json::error::Category::Io = v.classify() {
54 Error::IOError(v.into())
55 } else {
56 Error::JSONError(v)
57 }
58 }
59 }
60
61 impl fmt::Display for Error {
62 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
63 match self {
64 Error::IOError(v) => fmt::Display::fmt(v, f),
65 Error::JSONError(v) => fmt::Display::fmt(v, f),
66 Error::DeducingNameForInstructionOperandFailed => {
67 write!(f, "deducing name for InstructionOperand failed")
68 }
69 Error::DeducingNameForEnumerantParameterFailed => {
70 write!(f, "deducing name for EnumerantParameter failed")
71 }
72 }
73 }
74 }
75
76 impl error::Error for Error {}
77
78 impl From<Error> for io::Error {
79 fn from(error: Error) -> Self {
80 match error {
81 Error::IOError(v) => v,
82 Error::JSONError(v) => v.into(),
83 error @ Error::DeducingNameForInstructionOperandFailed
84 | error @ Error::DeducingNameForEnumerantParameterFailed => {
85 io::Error::new(io::ErrorKind::Other, format!("{}", error))
86 }
87 }
88 }
89 }
90
91 pub struct Output {}
92
93 pub struct Input {
94 spirv_core_grammar_json_path: PathBuf,
95 extension_instruction_sets: HashMap<ExtensionInstructionSet, PathBuf>,
96 }
97
98 impl Input {
99 pub fn new<T: AsRef<Path>>(spirv_core_grammar_json_path: T) -> Input {
100 Input {
101 spirv_core_grammar_json_path: spirv_core_grammar_json_path.as_ref().into(),
102 extension_instruction_sets: HashMap::new(),
103 }
104 }
105 pub fn add_extension_instruction_set<T: AsRef<Path>>(
106 mut self,
107 extension_instruction_set: ExtensionInstructionSet,
108 path: T,
109 ) -> Self {
110 assert!(
111 self.extension_instruction_sets
112 .insert(extension_instruction_set, path.as_ref().into())
113 .is_none(),
114 "duplicate extension instruction set: {:?}",
115 extension_instruction_set
116 );
117 self
118 }
119 pub fn generate(self) -> Result<Output, Error> {
120 let Input {
121 spirv_core_grammar_json_path,
122 extension_instruction_sets,
123 } = self;
124 let mut core_grammar: ast::CoreGrammar =
125 serde_json::from_reader(File::open(spirv_core_grammar_json_path)?)?;
126 core_grammar.guess_names()?;
127 let mut parsed_extension_instruction_sets: HashMap<
128 ExtensionInstructionSet,
129 ast::ExtensionInstructionSet,
130 > = Default::default();
131 for (extension_instruction_set, path) in extension_instruction_sets {
132 let mut parsed_extension_instruction_set: ast::ExtensionInstructionSet =
133 serde_json::from_reader(File::open(path)?)?;
134 parsed_extension_instruction_set.guess_names()?;
135 assert!(
136 parsed_extension_instruction_sets
137 .insert(extension_instruction_set, parsed_extension_instruction_set)
138 .is_none()
139 );
140 }
141 unimplemented!()
142 }
143 }
144
145 #[cfg(test)]
146 mod tests {
147 use super::*;
148 fn get_spirv_grammar_path<T: AsRef<Path>>(name: T) -> PathBuf {
149 Path::new(env!("CARGO_MANIFEST_DIR"))
150 .join("../external/SPIRV-Headers/include/spirv/unified1")
151 .join(name)
152 }
153
154 fn create_input(extension_instruction_sets: &[ExtensionInstructionSet]) -> Input {
155 let mut retval = Input::new(get_spirv_grammar_path("spirv.core.grammar.json"));
156 for &extension_instruction_set in extension_instruction_sets {
157 retval = retval.add_extension_instruction_set(
158 extension_instruction_set,
159 get_spirv_grammar_path(extension_instruction_set.get_grammar_json_file_name()),
160 );
161 }
162 retval
163 }
164
165 #[test]
166 fn parse_core_grammar() -> Result<(), Error> {
167 create_input(&[]).generate()?;
168 Ok(())
169 }
170
171 #[test]
172 fn parse_core_grammar_with_opencl() -> Result<(), Error> {
173 create_input(&[ExtensionInstructionSet::OpenCLStd]).generate()?;
174 Ok(())
175 }
176
177 #[test]
178 fn parse_core_grammar_with_opencl_and_glsl() -> Result<(), Error> {
179 create_input(&[
180 ExtensionInstructionSet::OpenCLStd,
181 ExtensionInstructionSet::GLSLStd450,
182 ])
183 .generate()?;
184 Ok(())
185 }
186
187 #[test]
188 fn parse_core_grammar_with_glsl() -> Result<(), Error> {
189 create_input(&[ExtensionInstructionSet::GLSLStd450]).generate()?;
190 Ok(())
191 }
192 }