glsl_lang_lexer/full/
directives.rs1use std::cmp;
2
3use glsl_lang_pp::processor::{
4 event::{DirectiveKind, EventDirective},
5 nodes::VersionProfile,
6};
7use glsl_lang_types::ast::{
8 self, PreprocessorExtensionBehaviorData, PreprocessorExtensionNameData,
9 PreprocessorVersionProfileData,
10};
11use lang_util::NodeContent;
12
13#[derive(Default, Debug, Clone)]
14pub struct Directives {
15 directives: Vec<EventDirective>,
16}
17
18impl Directives {
19 pub fn directives(&self) -> &[EventDirective] {
20 &self.directives
21 }
22
23 fn get_declaration(
24 directive: &EventDirective,
25 highest_version: &mut Option<(u16, Option<VersionProfile>)>,
26 ) -> Option<ast::ExternalDeclaration> {
27 let start = directive.text_range().start();
28 let end = directive.text_range().end();
29
30 match directive.kind() {
31 DirectiveKind::Version(version) => {
32 let version_number = version.number;
33 let profile = version.parsed_profile;
34
35 let had_highest_version;
36 let (highest_version_number, highest_profile) = match highest_version {
37 Some(version_data) => {
38 had_highest_version = true;
39 version_data
40 }
41 None => {
42 had_highest_version = false;
43 highest_version.insert((version_number, profile))
44 }
45 };
46
47 *highest_version_number = cmp::max(version_number, *highest_version_number);
48 *highest_profile = cmp::max(
49 Some(profile.unwrap_or(VersionProfile::None)),
51 *highest_profile,
52 );
53
54 (!had_highest_version).then_some(
55 ast::ExternalDeclarationData::Preprocessor(
56 ast::PreprocessorData::Version(
57 ast::PreprocessorVersionData {
58 version: version_number,
59 profile: match profile {
60 None | Some(VersionProfile::None) => None,
61 Some(VersionProfile::Core) => {
62 Some(PreprocessorVersionProfileData::Core.into())
63 }
64 Some(VersionProfile::Compatibility) => {
65 Some(PreprocessorVersionProfileData::Compatibility.into())
66 }
67 Some(VersionProfile::Es) => {
68 Some(PreprocessorVersionProfileData::Es.into())
69 }
70 },
71 }
72 .into(),
73 )
74 .spanned(start, end),
75 )
76 .spanned(start, end),
77 )
78 }
79
80 DirectiveKind::Pragma(pragma) => Some(
81 ast::ExternalDeclarationData::Preprocessor(
82 ast::PreprocessorData::Pragma(
83 ast::PreprocessorPragmaData {
84 command: pragma.raw().to_owned(),
85 }
86 .into(),
87 )
88 .spanned(start, end),
89 )
90 .spanned(start, end),
91 ),
92
93 DirectiveKind::Extension(extension) => Some(
94 ast::ExternalDeclarationData::Preprocessor(
95 ast::PreprocessorData::Extension(
96 ast::PreprocessorExtensionData {
97 name: match extension.name {
98 glsl_lang_pp::processor::nodes::ExtensionName::All => {
99 PreprocessorExtensionNameData::All
100 }
101 glsl_lang_pp::processor::nodes::ExtensionName::Specific(
102 ref name,
103 ) => PreprocessorExtensionNameData::Specific(name.as_ref().into()),
104 }
105 .into(),
106 behavior: Some(
107 match extension.behavior {
108 glsl_lang_pp::processor::nodes::ExtensionBehavior::Require => {
109 PreprocessorExtensionBehaviorData::Require
110 }
111 glsl_lang_pp::processor::nodes::ExtensionBehavior::Enable => {
112 PreprocessorExtensionBehaviorData::Enable
113 }
114 glsl_lang_pp::processor::nodes::ExtensionBehavior::Warn => {
115 PreprocessorExtensionBehaviorData::Warn
116 }
117 glsl_lang_pp::processor::nodes::ExtensionBehavior::Disable => {
118 PreprocessorExtensionBehaviorData::Disable
119 }
120 }
121 .into(),
122 ),
123 }
124 .into(),
125 )
126 .spanned(start, end),
127 )
128 .spanned(start, end),
129 ),
130
131 _ => None,
132 }
133 }
134
135 pub fn inject(mut self, root: &mut ast::TranslationUnit) -> Directives {
136 let mut directive_idx = 0;
137 let mut declaration_idx = 0;
138 let mut highest_version = None;
139 let mut version_directive_declaration_idx = None;
140
141 let mut start = None;
143 while declaration_idx < root.0.len() && directive_idx < self.directives.len() {
144 let current_declaration = &root.0[declaration_idx];
146
147 let actual_start =
149 if let Some(current_start) = current_declaration.span.map(|span| span.start()) {
150 current_start
151 } else if let Some(start) = start {
152 start
154 } else {
155 declaration_idx += 1;
157 continue;
158 };
159
160 let end = if let Some(current_end) = current_declaration.span.map(|span| span.end()) {
162 current_end
163 } else {
164 actual_start
166 };
167
168 while directive_idx < self.directives.len() {
170 let current_directive = &self.directives[directive_idx];
172 let span = current_directive.text_range();
173
174 if span.end().offset <= actual_start.offset
177 || actual_start.source_id != span.source_id()
178 {
179 if let Some(declaration) =
180 Self::get_declaration(current_directive, &mut highest_version)
181 {
182 root.0.insert(declaration_idx, declaration);
184
185 if matches!(current_directive.kind(), DirectiveKind::Version(_)) {
186 version_directive_declaration_idx.get_or_insert(declaration_idx);
187 }
188
189 declaration_idx += 1;
190
191 self.directives.remove(directive_idx);
193 } else {
194 directive_idx += 1;
196 }
197 } else {
198 break;
200 }
201 }
202
203 declaration_idx += 1;
205
206 start = Some(end);
208 }
209
210 while directive_idx < self.directives.len() {
212 let current_directive = &self.directives[directive_idx];
213
214 if let Some(declaration) =
215 Self::get_declaration(current_directive, &mut highest_version)
216 {
217 root.0.push(declaration);
218
219 if matches!(current_directive.kind(), DirectiveKind::Version(_)) {
220 version_directive_declaration_idx.get_or_insert(root.0.len() - 1);
221 }
222
223 self.directives.remove(directive_idx);
224 } else {
225 directive_idx += 1;
226 }
227 }
228
229 if let (
232 Some(version_directive_declaration_idx),
233 Some((highest_version_number, highest_profile)),
234 ) = (version_directive_declaration_idx, highest_version)
235 {
236 if let ast::ExternalDeclarationData::Preprocessor(preprocessor_data) =
237 &mut root.0[version_directive_declaration_idx].content
238 {
239 if let ast::PreprocessorData::Version(preprocessor_version) =
240 &mut preprocessor_data.content
241 {
242 preprocessor_version.version = highest_version_number;
243 preprocessor_version.profile = match highest_profile {
244 None | Some(VersionProfile::None) => None,
245 Some(VersionProfile::Core) => {
246 Some(PreprocessorVersionProfileData::Core.into())
247 }
248 Some(VersionProfile::Compatibility) => {
249 Some(PreprocessorVersionProfileData::Compatibility.into())
250 }
251 Some(VersionProfile::Es) => Some(PreprocessorVersionProfileData::Es.into()),
252 };
253 }
254 }
255 }
256
257 self
258 }
259}
260
261impl From<Vec<EventDirective>> for Directives {
262 fn from(directives: Vec<EventDirective>) -> Self {
263 Self { directives }
264 }
265}
266
267impl From<Directives> for Vec<EventDirective> {
268 fn from(directives: Directives) -> Self {
269 directives.directives
270 }
271}