nv50: fix build-predicate function
[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_context.h"
31 #include "sl_pp_expression.h"
32 #include "sl_pp_macro.h"
33 #include "sl_pp_process.h"
34 #include "sl_pp_token.h"
35
36
37 static int
38 _macro_is_defined(struct sl_pp_context *context,
39 int macro_name)
40 {
41 unsigned int i;
42 struct sl_pp_macro *macro;
43
44 for (i = 0; i < context->num_extensions; i++) {
45 if (macro_name == context->extensions[i].name) {
46 return 1;
47 }
48 }
49
50 for (macro = context->macro; macro; macro = macro->next) {
51 if (macro_name == macro->name) {
52 return 1;
53 }
54 }
55
56 return 0;
57 }
58
59 static int
60 _parse_defined(struct sl_pp_context *context,
61 struct sl_pp_token_buffer *buffer,
62 struct sl_pp_process_state *state)
63 {
64 struct sl_pp_token_info input;
65 int parens = 0;
66 int defined;
67 struct sl_pp_token_info result;
68
69 if (sl_pp_token_buffer_skip_white(buffer, &input)) {
70 return -1;
71 }
72
73 if (input.token == SL_PP_LPAREN) {
74 if (sl_pp_token_buffer_skip_white(buffer, &input)) {
75 return -1;
76 }
77 parens = 1;
78 }
79
80 if (input.token != SL_PP_IDENTIFIER) {
81 strcpy(context->error_msg, "expected an identifier");
82 return -1;
83 }
84
85 defined = _macro_is_defined(context, input.data.identifier);
86
87 if (parens) {
88 if (sl_pp_token_buffer_skip_white(buffer, &input)) {
89 return -1;
90 }
91 if (input.token != SL_PP_RPAREN) {
92 strcpy(context->error_msg, "expected `)'");
93 return -1;
94 }
95 }
96
97 result.token = SL_PP_UINT;
98 result.data._uint = (defined ? context->dict._1 : context->dict._0);
99
100 if (sl_pp_process_out(state, &result)) {
101 strcpy(context->error_msg, "out of memory");
102 return -1;
103 }
104
105 return 0;
106 }
107
108 static unsigned int
109 _evaluate_if_stack(struct sl_pp_context *context)
110 {
111 unsigned int i;
112
113 for (i = context->if_ptr; i < SL_PP_MAX_IF_NESTING; i++) {
114 if (!context->if_stack[i].u.condition) {
115 return 0;
116 }
117 }
118 return 1;
119 }
120
121 static int
122 _parse_if(struct sl_pp_context *context,
123 struct sl_pp_token_buffer *buffer)
124 {
125 struct sl_pp_process_state state;
126 int found_end = 0;
127 struct sl_pp_token_info eof;
128 int result;
129
130 if (!context->if_ptr) {
131 strcpy(context->error_msg, "`#if' nesting too deep");
132 return -1;
133 }
134
135 memset(&state, 0, sizeof(state));
136 while (!found_end) {
137 struct sl_pp_token_info input;
138
139 sl_pp_token_buffer_get(buffer, &input);
140 switch (input.token) {
141 case SL_PP_WHITESPACE:
142 break;
143
144 case SL_PP_IDENTIFIER:
145 if (input.data.identifier == context->dict.defined) {
146 if (_parse_defined(context, buffer, &state)) {
147 free(state.out);
148 return -1;
149 }
150 } else {
151 sl_pp_token_buffer_unget(buffer, &input);
152 if (sl_pp_macro_expand(context, buffer, NULL, &state, sl_pp_macro_expand_unknown_to_0)) {
153 free(state.out);
154 return -1;
155 }
156 }
157 break;
158
159 case SL_PP_NEWLINE:
160 case SL_PP_EOF:
161 found_end = 1;
162 break;
163
164 default:
165 if (sl_pp_process_out(&state, &input)) {
166 strcpy(context->error_msg, "out of memory");
167 free(state.out);
168 return -1;
169 }
170 }
171 }
172
173 eof.token = SL_PP_EOF;
174 if (sl_pp_process_out(&state, &eof)) {
175 strcpy(context->error_msg, "out of memory");
176 free(state.out);
177 return -1;
178 }
179
180 if (sl_pp_execute_expression(context, state.out, &result)) {
181 free(state.out);
182 return -1;
183 }
184
185 free(state.out);
186
187 context->if_ptr--;
188 context->if_stack[context->if_ptr].value = 0;
189 context->if_stack[context->if_ptr].u.condition = result ? 1 : 0;
190 context->if_value = _evaluate_if_stack(context);
191
192 return 0;
193 }
194
195 static int
196 _parse_else(struct sl_pp_context *context)
197 {
198 union sl_pp_if_state *state = &context->if_stack[context->if_ptr];
199
200 if (context->if_ptr == SL_PP_MAX_IF_NESTING) {
201 strcpy(context->error_msg, "no matching `#if'");
202 return -1;
203 }
204
205 if (state->u.went_thru_else) {
206 strcpy(context->error_msg, "no matching `#if'");
207 return -1;
208 }
209
210 /* Once we had a true condition, the subsequent #elifs should always be false. */
211 state->u.had_true_cond |= state->u.condition;
212
213 /* Update current condition value and mark that we are in the #else block. */
214 state->u.condition = !(state->u.had_true_cond | state->u.condition);
215 state->u.went_thru_else = 1;
216 context->if_value = _evaluate_if_stack(context);
217
218 return 0;
219 }
220
221 int
222 sl_pp_process_if(struct sl_pp_context *context,
223 struct sl_pp_token_buffer *buffer)
224 {
225 return _parse_if(context, buffer);
226 }
227
228 int
229 sl_pp_process_ifdef(struct sl_pp_context *context,
230 const struct sl_pp_token_info *input,
231 unsigned int first,
232 unsigned int last)
233 {
234 unsigned int i;
235
236 if (!context->if_ptr) {
237 strcpy(context->error_msg, "`#if' nesting too deep");
238 return -1;
239 }
240
241 for (i = first; i < last; i++) {
242 switch (input[i].token) {
243 case SL_PP_IDENTIFIER:
244 context->if_ptr--;
245 context->if_stack[context->if_ptr].value = 0;
246 context->if_stack[context->if_ptr].u.condition = _macro_is_defined(context, input[i].data.identifier);
247 context->if_value = _evaluate_if_stack(context);
248 return 0;
249
250 case SL_PP_WHITESPACE:
251 break;
252
253 default:
254 strcpy(context->error_msg, "expected an identifier");
255 return -1;
256 }
257 }
258
259 strcpy(context->error_msg, "expected an identifier");
260 return -1;
261 }
262
263 int
264 sl_pp_process_ifndef(struct sl_pp_context *context,
265 const struct sl_pp_token_info *input,
266 unsigned int first,
267 unsigned int last)
268 {
269 unsigned int i;
270
271 if (!context->if_ptr) {
272 strcpy(context->error_msg, "`#if' nesting too deep");
273 return -1;
274 }
275
276 for (i = first; i < last; i++) {
277 switch (input[i].token) {
278 case SL_PP_IDENTIFIER:
279 context->if_ptr--;
280 context->if_stack[context->if_ptr].value = 0;
281 context->if_stack[context->if_ptr].u.condition = !_macro_is_defined(context, input[i].data.identifier);
282 context->if_value = _evaluate_if_stack(context);
283 return 0;
284
285 case SL_PP_WHITESPACE:
286 break;
287
288 default:
289 strcpy(context->error_msg, "expected an identifier");
290 return -1;
291 }
292 }
293
294 strcpy(context->error_msg, "expected an identifier");
295 return -1;
296 }
297
298 int
299 sl_pp_process_elif(struct sl_pp_context *context,
300 struct sl_pp_token_buffer *buffer)
301 {
302 if (_parse_else(context)) {
303 return -1;
304 }
305
306 if (context->if_stack[context->if_ptr].u.condition) {
307 context->if_ptr++;
308 if (_parse_if(context, buffer)) {
309 return -1;
310 }
311 }
312
313 /* We are still in the #if block. */
314 context->if_stack[context->if_ptr].u.went_thru_else = 0;
315
316 return 0;
317 }
318
319 int
320 sl_pp_process_else(struct sl_pp_context *context,
321 const struct sl_pp_token_info *input,
322 unsigned int first,
323 unsigned int last)
324 {
325 return _parse_else(context);
326 }
327
328 int
329 sl_pp_process_endif(struct sl_pp_context *context,
330 const struct sl_pp_token_info *input,
331 unsigned int first,
332 unsigned int last)
333 {
334 if (context->if_ptr == SL_PP_MAX_IF_NESTING) {
335 strcpy(context->error_msg, "no matching `#if'");
336 return -1;
337 }
338
339 context->if_ptr++;
340 context->if_value = _evaluate_if_stack(context);
341
342 return 0;
343 }