glsl_lang_pp/
processor.rs

1use std::collections::HashMap;
2
3use lang_util::{FileId, SmolStr};
4
5mod definition;
6use definition::Definition;
7
8pub mod event;
9
10pub mod expand;
11
12mod expr;
13
14pub mod fs;
15
16pub mod nodes;
17use nodes::{Define, DefineObject, Version};
18
19use crate::{
20    exts::Registry,
21    processor::nodes::{ExtensionBehavior, ExtensionName},
22};
23
24pub mod str;
25
26/// Operating mode for #include directives
27#[derive(Debug, Clone, Copy, PartialEq, Eq)]
28pub enum IncludeMode {
29    /// No #include directives are allowed
30    None,
31    /// GL_ARB_shading_language_include runtime includes
32    ArbInclude { warn: bool },
33    /// GL_GOOGLE_include_directive compile-time includes
34    GoogleInclude { warn: bool },
35}
36
37impl IncludeMode {
38    pub fn warn(self) -> bool {
39        match self {
40            IncludeMode::None => false,
41            IncludeMode::ArbInclude { warn } | IncludeMode::GoogleInclude { warn } => warn,
42        }
43    }
44}
45
46impl Default for IncludeMode {
47    fn default() -> Self {
48        Self::None
49    }
50}
51
52/// Current state of the preprocessor
53#[derive(Debug, Clone, PartialEq, Eq)]
54pub struct ProcessorState {
55    include_mode: IncludeMode,
56    definitions: HashMap<SmolStr, Definition>,
57    version: Version,
58    cpp_style_line: bool,
59}
60
61impl ProcessorState {
62    pub fn builder() -> ProcessorStateBuilder<'static> {
63        ProcessorStateBuilder::default()
64    }
65
66    fn get_definition(&self, name: &str) -> Option<&Definition> {
67        self.definitions.get(name)
68    }
69
70    // TODO: Return a proper error type?
71    pub fn definition(&mut self, definition: Define, file_id: FileId) -> bool {
72        let entry = self.definitions.entry(definition.name().into());
73
74        match entry {
75            std::collections::hash_map::Entry::Occupied(mut occupied) => {
76                if occupied.get().protected() {
77                    false
78                } else {
79                    occupied.insert(Definition::Regular(definition.into(), file_id));
80                    true
81                }
82            }
83            std::collections::hash_map::Entry::Vacant(vacant) => {
84                vacant.insert(Definition::Regular(definition.into(), file_id));
85                true
86            }
87        }
88    }
89
90    fn add_extension(&mut self, name: &ExtensionName, behavior: ExtensionBehavior) {
91        // Process include extensions
92        let target_include_mode = if *name == ext_name!("GL_ARB_shading_language_include") {
93            Some(IncludeMode::ArbInclude {
94                warn: behavior == ExtensionBehavior::Warn,
95            })
96        } else if *name == ext_name!("GL_GOOGLE_include_directive") {
97            Some(IncludeMode::GoogleInclude {
98                warn: behavior == ExtensionBehavior::Warn,
99            })
100        } else {
101            None
102        };
103
104        if let Some(target) = target_include_mode {
105            if behavior.is_active() {
106                self.include_mode = target;
107
108                // GL_GOOGLE_include_directive enable GL_GOOGLE_cpp_style_line
109                if let IncludeMode::GoogleInclude { .. } = target {
110                    self.cpp_style_line = true;
111                }
112            } else {
113                // TODO: Implement current mode as a stack?
114                self.include_mode = IncludeMode::None;
115            }
116        }
117
118        // Process others
119        if *name == ext_name!("GL_GOOGLE_cpp_style_line_directive") {
120            if behavior.is_active() {
121                self.cpp_style_line = true;
122            } else {
123                // TODO: Notify instead of silently ignoring?
124                if !matches!(self.include_mode, IncludeMode::GoogleInclude { .. }) {
125                    self.cpp_style_line = false;
126                }
127            }
128        }
129    }
130
131    fn extension(&mut self, extension: &nodes::Extension) {
132        self.add_extension(&extension.name, extension.behavior);
133    }
134
135    fn cpp_style_line(&self) -> bool {
136        self.cpp_style_line
137    }
138}
139
140impl Default for ProcessorState {
141    fn default() -> Self {
142        ProcessorStateBuilder::default().finish()
143    }
144}
145
146#[derive(Clone)]
147pub struct ProcessorStateBuilder<'r> {
148    core_profile: bool,
149    compatibility_profile: bool,
150    es_profile: bool,
151    extensions: Vec<(ExtensionName, ExtensionBehavior)>,
152    definitions: Vec<Define>,
153    registry: &'r Registry,
154}
155
156impl<'r> ProcessorStateBuilder<'r> {
157    pub fn new(registry: &'r Registry) -> Self {
158        let default = ProcessorStateBuilder::default();
159        Self {
160            registry,
161            ..default
162        }
163    }
164
165    pub fn registry<'s>(self, registry: &'s Registry) -> ProcessorStateBuilder<'s> {
166        ProcessorStateBuilder::<'s> {
167            registry,
168            core_profile: self.core_profile,
169            compatibility_profile: self.compatibility_profile,
170            es_profile: self.es_profile,
171            extensions: self.extensions,
172            definitions: self.definitions,
173        }
174    }
175
176    pub fn core_profile(self, core_profile: bool) -> Self {
177        Self {
178            core_profile,
179            ..self
180        }
181    }
182
183    pub fn compatibility_profile(self, compatibility_profile: bool) -> Self {
184        Self {
185            compatibility_profile,
186            ..self
187        }
188    }
189
190    pub fn es_profile(self, es_profile: bool) -> Self {
191        Self { es_profile, ..self }
192    }
193
194    pub fn extension(
195        mut self,
196        name: impl Into<ExtensionName>,
197        behavior: impl Into<ExtensionBehavior>,
198    ) -> Self {
199        self.extensions.push((name.into(), behavior.into()));
200        self
201    }
202
203    pub fn definition(mut self, definition: impl Into<Define>) -> Self {
204        self.definitions.push(definition.into());
205        self
206    }
207
208    pub fn finish(self) -> ProcessorState {
209        let one = DefineObject::one();
210
211        let mut state =
212            ProcessorState {
213                // No #include extensions enabled
214                include_mode: IncludeMode::None,
215                // Spec 3.3, "There is a built-in macro definition for each profile the implementation
216                // supports. All implementations provide the following macro:
217                // `#define GL_core_profile 1`
218                definitions: self
219                    .core_profile
220                    .then(|| Define::object("GL_core_profile".into(), one.clone(), true))
221                    .into_iter()
222                    .chain(self.compatibility_profile.then(|| {
223                        Define::object("GL_compatibility_profile".into(), one.clone(), true)
224                    }))
225                    .chain(
226                        self.es_profile
227                            .then(|| Define::object("GL_es_profile".into(), one.clone(), true)),
228                    )
229                    .chain(self.definitions)
230                    .map(|definition| Definition::Regular(definition.into(), FileId::default()))
231                    .chain([Definition::Line, Definition::File, Definition::Version])
232                    .chain(self.registry.all().map(|spec| {
233                        Definition::Regular(
234                            Define::object(spec.name().as_ref().into(), one.clone(), true).into(),
235                            FileId::default(),
236                        )
237                    }))
238                    .map(|definition| (definition.name().into(), definition))
239                    .collect(),
240                version: Version::default(),
241                cpp_style_line: false,
242            };
243
244        for (name, behavior) in self.extensions {
245            state.add_extension(&name, behavior);
246        }
247
248        state
249    }
250}
251
252impl From<ProcessorStateBuilder<'_>> for ProcessorState {
253    fn from(builder: ProcessorStateBuilder<'_>) -> Self {
254        builder.finish()
255    }
256}
257
258impl Default for ProcessorStateBuilder<'static> {
259    fn default() -> Self {
260        Self {
261            core_profile: true,
262            compatibility_profile: false,
263            es_profile: false,
264            extensions: Default::default(),
265            definitions: Default::default(),
266            registry: &*crate::exts::DEFAULT_REGISTRY,
267        }
268    }
269}