glsl/pp: fix extension enable/disable options
[mesa.git] / src / glsl / pp / sl_pp_if.c
1 /**************************************************************************
2 *
3 * Copyright 2009 VMware, Inc.
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
16 * of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 **************************************************************************/
27
28 #include <stdlib.h>
29 #include <string.h>
30 #include "sl_pp_expression.h"
31 #include "sl_pp_process.h"
32
33
34 static int
35 _macro_is_defined(struct sl_pp_context *context,
36 int macro_name)
37 {
38 unsigned int i;
39 struct sl_pp_macro *macro;
40
41 for (i = 0; i < context->num_extensions; i++) {
42 if (macro_name == context->extensions[i].name) {
43 return context->extensions[i].enabled;
44 }
45 }
46
47 for (macro = context->macro; macro; macro = macro->next) {
48 if (macro_name == macro->name) {
49 return 1;
50 }
51 }
52
53 return 0;
54 }
55
56 static int
57 _parse_defined(struct sl_pp_context *context,
58 struct sl_pp_token_buffer *buffer,
59 struct sl_pp_process_state *state)
60 {
61 struct sl_pp_token_info input;
62 int parens = 0;
63 int defined;
64 struct sl_pp_token_info result;
65
66 if (sl_pp_token_buffer_skip_white(buffer, &input)) {
67 return -1;
68 }
69
70 if (input.token == SL_PP_LPAREN) {
71 if (sl_pp_token_buffer_skip_white(buffer, &input)) {
72 return -1;
73 }
74 parens = 1;
75 }
76
77 if (input.token != SL_PP_IDENTIFIER) {
78 strcpy(context->error_msg, "expected an identifier");
79 return -1;
80 }
81
82 defined = _macro_is_defined(context, input.data.identifier);
83
84 if (parens) {
85 if (sl_pp_token_buffer_skip_white(buffer, &input)) {
86 return -1;
87 }
88 if (input.token != SL_PP_RPAREN) {
89 strcpy(context->error_msg, "expected `)'");
90 return -1;
91 }
92 }
93
94 result.token = SL_PP_UINT;
95 result.data._uint = (defined ? context->dict._1 : context->dict._0);
96
97 if (sl_pp_process_out(state, &result)) {
98 strcpy(context->error_msg, "out of memory");
99 return -1;
100 }
101
102 return 0;
103 }
104
105 static unsigned int
106 _evaluate_if_stack(struct sl_pp_context *context)
107 {
108 unsigned int i;
109
110 for (i = context->if_ptr; i < SL_PP_MAX_IF_NESTING; i++) {
111 if (!(context->if_stack[i] & 1)) {
112 return 0;
113 }
114 }
115 return 1;
116 }
117
118 static int
119 _parse_if(struct sl_pp_context *context,
120 struct sl_pp_token_buffer *buffer)
121 {
122 struct sl_pp_process_state state;
123 int found_end = 0;
124 struct sl_pp_token_info eof;
125 int result;
126
127 if (!context->if_ptr) {
128 strcpy(context->error_msg, "`#if' nesting too deep");
129 return -1;
130 }
131
132 memset(&state, 0, sizeof(state));
133 while (!found_end) {
134 struct sl_pp_token_info input;
135
136 sl_pp_token_buffer_get(buffer, &input);
137 switch (input.token) {
138 case SL_PP_WHITESPACE:
139 break;
140
141 case SL_PP_IDENTIFIER:
142 if (input.data.identifier == context->dict.defined) {
143 if (_parse_defined(context, buffer, &state)) {
144 free(state.out);
145 return -1;
146 }
147 } else {
148 sl_pp_token_buffer_unget(buffer, &input);
149 if (sl_pp_macro_expand(context, buffer, NULL, &state, sl_pp_macro_expand_unknown_to_0)) {
150 free(state.out);
151 return -1;
152 }
153 }
154 break;
155
156 case SL_PP_NEWLINE:
157 case SL_PP_EOF:
158 found_end = 1;
159 break;
160
161 default:
162 if (sl_pp_process_out(&state, &input)) {
163 strcpy(context->error_msg, "out of memory");
164 free(state.out);
165 return -1;
166 }
167 }
168 }
169
170 eof.token = SL_PP_EOF;
171 if (sl_pp_process_out(&state, &eof)) {
172 strcpy(context->error_msg, "out of memory");
173 free(state.out);
174 return -1;
175 }
176
177 if (sl_pp_execute_expression(context, state.out, &result)) {
178 free(state.out);
179 return -1;
180 }
181
182 free(state.out);
183
184 context->if_ptr--;
185 context->if_stack[context->if_ptr] = result ? 1 : 0;
186 context->if_value = _evaluate_if_stack(context);
187
188 return 0;
189 }
190
191 static int
192 _parse_else(struct sl_pp_context *context)
193 {
194 if (context->if_ptr == SL_PP_MAX_IF_NESTING) {
195 strcpy(context->error_msg, "no matching `#if'");
196 return -1;
197 }
198
199 /* Bit b1 indicates we already went through #else. */
200 if (context->if_stack[context->if_ptr] & 2) {
201 strcpy(context->error_msg, "no matching `#if'");
202 return -1;
203 }
204
205 /* Invert current condition value and mark that we are in the #else block. */
206 context->if_stack[context->if_ptr] = (1 - (context->if_stack[context->if_ptr] & 1)) | 2;
207 context->if_value = _evaluate_if_stack(context);
208
209 return 0;
210 }
211
212 int
213 sl_pp_process_if(struct sl_pp_context *context,
214 struct sl_pp_token_buffer *buffer)
215 {
216 return _parse_if(context, buffer);
217 }
218
219 int
220 sl_pp_process_ifdef(struct sl_pp_context *context,
221 const struct sl_pp_token_info *input,
222 unsigned int first,
223 unsigned int last)
224 {
225 unsigned int i;
226
227 if (!context->if_ptr) {
228 strcpy(context->error_msg, "`#if' nesting too deep");
229 return -1;
230 }
231
232 for (i = first; i < last; i++) {
233 switch (input[i].token) {
234 case SL_PP_IDENTIFIER:
235 context->if_ptr--;
236 context->if_stack[context->if_ptr] = _macro_is_defined(context, input[i].data.identifier);
237 context->if_value = _evaluate_if_stack(context);
238 return 0;
239
240 case SL_PP_WHITESPACE:
241 break;
242
243 default:
244 strcpy(context->error_msg, "expected an identifier");
245 return -1;
246 }
247 }
248
249 strcpy(context->error_msg, "expected an identifier");
250 return -1;
251 }
252
253 int
254 sl_pp_process_ifndef(struct sl_pp_context *context,
255 const struct sl_pp_token_info *input,
256 unsigned int first,
257 unsigned int last)
258 {
259 unsigned int i;
260
261 if (!context->if_ptr) {
262 strcpy(context->error_msg, "`#if' nesting too deep");
263 return -1;
264 }
265
266 for (i = first; i < last; i++) {
267 switch (input[i].token) {
268 case SL_PP_IDENTIFIER:
269 context->if_ptr--;
270 context->if_stack[context->if_ptr] = !_macro_is_defined(context, input[i].data.identifier);
271 context->if_value = _evaluate_if_stack(context);
272 return 0;
273
274 case SL_PP_WHITESPACE:
275 break;
276
277 default:
278 strcpy(context->error_msg, "expected an identifier");
279 return -1;
280 }
281 }
282
283 strcpy(context->error_msg, "expected an identifier");
284 return -1;
285 }
286
287 int
288 sl_pp_process_elif(struct sl_pp_context *context,
289 struct sl_pp_token_buffer *buffer)
290 {
291 if (_parse_else(context)) {
292 return -1;
293 }
294
295 if (context->if_stack[context->if_ptr] & 1) {
296 context->if_ptr++;
297 if (_parse_if(context, buffer)) {
298 return -1;
299 }
300 }
301
302 /* We are still in the #if block. */
303 context->if_stack[context->if_ptr] = context->if_stack[context->if_ptr] & ~2;
304
305 return 0;
306 }
307
308 int
309 sl_pp_process_else(struct sl_pp_context *context,
310 const struct sl_pp_token_info *input,
311 unsigned int first,
312 unsigned int last)
313 {
314 return _parse_else(context);
315 }
316
317 int
318 sl_pp_process_endif(struct sl_pp_context *context,
319 const struct sl_pp_token_info *input,
320 unsigned int first,
321 unsigned int last)
322 {
323 if (context->if_ptr == SL_PP_MAX_IF_NESTING) {
324 strcpy(context->error_msg, "no matching `#if'");
325 return -1;
326 }
327
328 context->if_ptr++;
329 context->if_value = _evaluate_if_stack(context);
330
331 return 0;
332 }