glsl2: Conditionally allow optional extensions to be enabled
[mesa.git] / src / glsl / glsl_parser_extras.cpp
1 /*
2 * Copyright © 2008, 2009 Intel Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
22 */
23 #include <stdio.h>
24 #include <stdarg.h>
25 #include <string.h>
26 #include <assert.h>
27
28 extern "C" {
29 #include <talloc.h>
30 #include "main/mtypes.h"
31 }
32
33 #include "ast.h"
34 #include "glsl_parser_extras.h"
35 #include "glsl_parser.h"
36
37 const char *
38 _mesa_glsl_shader_target_name(enum _mesa_glsl_parser_targets target)
39 {
40 switch (target) {
41 case vertex_shader: return "vertex";
42 case fragment_shader: return "fragment";
43 case geometry_shader: return "geometry";
44 case ir_shader: break;
45 }
46
47 assert(!"Should not get here.");
48 }
49
50
51 void
52 _mesa_glsl_error(YYLTYPE *locp, _mesa_glsl_parse_state *state,
53 const char *fmt, ...)
54 {
55 va_list ap;
56
57 state->error = true;
58
59 assert(state->info_log != NULL);
60 state->info_log = talloc_asprintf_append(state->info_log,
61 "%u:%u(%u): error: ",
62 locp->source,
63 locp->first_line,
64 locp->first_column);
65 va_start(ap, fmt);
66 state->info_log = talloc_vasprintf_append(state->info_log, fmt, ap);
67 va_end(ap);
68 state->info_log = talloc_strdup_append(state->info_log, "\n");
69 }
70
71
72 void
73 _mesa_glsl_warning(const YYLTYPE *locp, _mesa_glsl_parse_state *state,
74 const char *fmt, ...)
75 {
76 va_list ap;
77
78 assert(state->info_log != NULL);
79 state->info_log = talloc_asprintf_append(state->info_log,
80 "%u:%u(%u): warning: ",
81 locp->source,
82 locp->first_line,
83 locp->first_column);
84 va_start(ap, fmt);
85 state->info_log = talloc_vasprintf_append(state->info_log, fmt, ap);
86 va_end(ap);
87 state->info_log = talloc_strdup_append(state->info_log, "\n");
88 }
89
90
91 bool
92 _mesa_glsl_process_extension(const char *name, YYLTYPE *name_locp,
93 const char *behavior, YYLTYPE *behavior_locp,
94 _mesa_glsl_parse_state *state)
95 {
96 enum {
97 extension_disable,
98 extension_enable,
99 extension_require,
100 extension_warn
101 } ext_mode;
102
103 if (strcmp(behavior, "warn") == 0) {
104 ext_mode = extension_warn;
105 } else if (strcmp(behavior, "require") == 0) {
106 ext_mode = extension_require;
107 } else if (strcmp(behavior, "enable") == 0) {
108 ext_mode = extension_enable;
109 } else if (strcmp(behavior, "disable") == 0) {
110 ext_mode = extension_disable;
111 } else {
112 _mesa_glsl_error(behavior_locp, state,
113 "Unknown extension behavior `%s'",
114 behavior);
115 return false;
116 }
117
118 bool unsupported = false;
119
120 if (strcmp(name, "all") == 0) {
121 if ((ext_mode == extension_enable) || (ext_mode == extension_require)) {
122 _mesa_glsl_error(name_locp, state, "Cannot %s all extensions",
123 (ext_mode == extension_enable)
124 ? "enable" : "require");
125 return false;
126 }
127 } else if (strcmp(name, "GL_ARB_draw_buffers") == 0) {
128 /* This extension is only supported in fragment shaders.
129 */
130 if (state->target != fragment_shader) {
131 unsupported = true;
132 } else {
133 state->ARB_draw_buffers_enable = (ext_mode != extension_disable);
134 state->ARB_draw_buffers_warn = (ext_mode == extension_warn);
135 }
136 } else if (strcmp(name, "GL_ARB_texture_rectangle") == 0) {
137 state->ARB_texture_rectangle_enable = (ext_mode != extension_disable);
138 state->ARB_texture_rectangle_warn = (ext_mode == extension_warn);
139 } else if (strcmp(name, "GL_EXT_texture_array") == 0) {
140 state->EXT_texture_array_enable = (ext_mode != extension_disable);
141 state->EXT_texture_array_warn = (ext_mode == extension_warn);
142
143 unsupported = !state->extensions->EXT_texture_array;
144 } else {
145 unsupported = true;
146 }
147
148 if (unsupported) {
149 static const char *const fmt = "extension `%s' unsupported in %s shader";
150
151 if (ext_mode == extension_require) {
152 _mesa_glsl_error(name_locp, state, fmt,
153 name, _mesa_glsl_shader_target_name(state->target));
154 return false;
155 } else {
156 _mesa_glsl_warning(name_locp, state, fmt,
157 name, _mesa_glsl_shader_target_name(state->target));
158 }
159 }
160
161 return true;
162 }
163
164 void
165 _mesa_ast_type_qualifier_print(const struct ast_type_qualifier *q)
166 {
167 if (q->constant)
168 printf("const ");
169
170 if (q->invariant)
171 printf("invariant ");
172
173 if (q->attribute)
174 printf("attribute ");
175
176 if (q->varying)
177 printf("varying ");
178
179 if (q->in && q->out)
180 printf("inout ");
181 else {
182 if (q->in)
183 printf("in ");
184
185 if (q->out)
186 printf("out ");
187 }
188
189 if (q->centroid)
190 printf("centroid ");
191 if (q->uniform)
192 printf("uniform ");
193 if (q->smooth)
194 printf("smooth ");
195 if (q->flat)
196 printf("flat ");
197 if (q->noperspective)
198 printf("noperspective ");
199 }
200
201
202 void
203 ast_node::print(void) const
204 {
205 printf("unhandled node ");
206 }
207
208
209 ast_node::ast_node(void)
210 {
211 /* empty */
212 }
213
214
215 static void
216 ast_opt_array_size_print(bool is_array, const ast_expression *array_size)
217 {
218 if (is_array) {
219 printf("[ ");
220
221 if (array_size)
222 array_size->print();
223
224 printf("] ");
225 }
226 }
227
228
229 void
230 ast_compound_statement::print(void) const
231 {
232 printf("{\n");
233
234 foreach_list_const(n, &this->statements) {
235 ast_node *ast = exec_node_data(ast_node, n, link);
236 ast->print();
237 }
238
239 printf("}\n");
240 }
241
242
243 ast_compound_statement::ast_compound_statement(int new_scope,
244 ast_node *statements)
245 {
246 this->new_scope = new_scope;
247
248 if (statements != NULL) {
249 this->statements.push_degenerate_list_at_head(&statements->link);
250 }
251 }
252
253
254 void
255 ast_expression::print(void) const
256 {
257 switch (oper) {
258 case ast_assign:
259 case ast_mul_assign:
260 case ast_div_assign:
261 case ast_mod_assign:
262 case ast_add_assign:
263 case ast_sub_assign:
264 case ast_ls_assign:
265 case ast_rs_assign:
266 case ast_and_assign:
267 case ast_xor_assign:
268 case ast_or_assign:
269 subexpressions[0]->print();
270 printf("%s ", operator_string(oper));
271 subexpressions[1]->print();
272 break;
273
274 case ast_field_selection:
275 subexpressions[0]->print();
276 printf(". %s ", primary_expression.identifier);
277 break;
278
279 case ast_plus:
280 case ast_neg:
281 case ast_bit_not:
282 case ast_logic_not:
283 case ast_pre_inc:
284 case ast_pre_dec:
285 printf("%s ", operator_string(oper));
286 subexpressions[0]->print();
287 break;
288
289 case ast_post_inc:
290 case ast_post_dec:
291 subexpressions[0]->print();
292 printf("%s ", operator_string(oper));
293 break;
294
295 case ast_conditional:
296 subexpressions[0]->print();
297 printf("? ");
298 subexpressions[1]->print();
299 printf(": ");
300 subexpressions[1]->print();
301 break;
302
303 case ast_array_index:
304 subexpressions[0]->print();
305 printf("[ ");
306 subexpressions[1]->print();
307 printf("] ");
308 break;
309
310 case ast_function_call: {
311 subexpressions[0]->print();
312 printf("( ");
313
314 foreach_list_const (n, &this->expressions) {
315 if (n != this->expressions.get_head())
316 printf(", ");
317
318 ast_node *ast = exec_node_data(ast_node, n, link);
319 ast->print();
320 }
321
322 printf(") ");
323 break;
324 }
325
326 case ast_identifier:
327 printf("%s ", primary_expression.identifier);
328 break;
329
330 case ast_int_constant:
331 printf("%d ", primary_expression.int_constant);
332 break;
333
334 case ast_uint_constant:
335 printf("%u ", primary_expression.uint_constant);
336 break;
337
338 case ast_float_constant:
339 printf("%f ", primary_expression.float_constant);
340 break;
341
342 case ast_bool_constant:
343 printf("%s ",
344 primary_expression.bool_constant
345 ? "true" : "false");
346 break;
347
348 case ast_sequence: {
349 printf("( ");
350 foreach_list_const(n, & this->expressions) {
351 if (n != this->expressions.get_head())
352 printf(", ");
353
354 ast_node *ast = exec_node_data(ast_node, n, link);
355 ast->print();
356 }
357 printf(") ");
358 break;
359 }
360
361 default:
362 assert(0);
363 break;
364 }
365 }
366
367 ast_expression::ast_expression(int oper,
368 ast_expression *ex0,
369 ast_expression *ex1,
370 ast_expression *ex2)
371 {
372 this->oper = ast_operators(oper);
373 this->subexpressions[0] = ex0;
374 this->subexpressions[1] = ex1;
375 this->subexpressions[2] = ex2;
376 }
377
378
379 void
380 ast_expression_statement::print(void) const
381 {
382 if (expression)
383 expression->print();
384
385 printf("; ");
386 }
387
388
389 ast_expression_statement::ast_expression_statement(ast_expression *ex) :
390 expression(ex)
391 {
392 /* empty */
393 }
394
395
396 void
397 ast_function::print(void) const
398 {
399 return_type->print();
400 printf(" %s (", identifier);
401
402 foreach_list_const(n, & this->parameters) {
403 ast_node *ast = exec_node_data(ast_node, n, link);
404 ast->print();
405 }
406
407 printf(")");
408 }
409
410
411 ast_function::ast_function(void)
412 : is_definition(false), signature(NULL)
413 {
414 /* empty */
415 }
416
417
418 void
419 ast_fully_specified_type::print(void) const
420 {
421 _mesa_ast_type_qualifier_print(& qualifier);
422 specifier->print();
423 }
424
425
426 void
427 ast_parameter_declarator::print(void) const
428 {
429 type->print();
430 if (identifier)
431 printf("%s ", identifier);
432 ast_opt_array_size_print(is_array, array_size);
433 }
434
435
436 void
437 ast_function_definition::print(void) const
438 {
439 prototype->print();
440 body->print();
441 }
442
443
444 void
445 ast_declaration::print(void) const
446 {
447 printf("%s ", identifier);
448 ast_opt_array_size_print(is_array, array_size);
449
450 if (initializer) {
451 printf("= ");
452 initializer->print();
453 }
454 }
455
456
457 ast_declaration::ast_declaration(char *identifier, int is_array,
458 ast_expression *array_size,
459 ast_expression *initializer)
460 {
461 this->identifier = identifier;
462 this->is_array = is_array;
463 this->array_size = array_size;
464 this->initializer = initializer;
465 }
466
467
468 void
469 ast_declarator_list::print(void) const
470 {
471 assert(type || invariant);
472
473 if (type)
474 type->print();
475 else
476 printf("invariant ");
477
478 foreach_list_const (ptr, & this->declarations) {
479 if (ptr != this->declarations.get_head())
480 printf(", ");
481
482 ast_node *ast = exec_node_data(ast_node, ptr, link);
483 ast->print();
484 }
485
486 printf("; ");
487 }
488
489
490 ast_declarator_list::ast_declarator_list(ast_fully_specified_type *type)
491 {
492 this->type = type;
493 this->invariant = false;
494 }
495
496 void
497 ast_jump_statement::print(void) const
498 {
499 switch (mode) {
500 case ast_continue:
501 printf("continue; ");
502 break;
503 case ast_break:
504 printf("break; ");
505 break;
506 case ast_return:
507 printf("return ");
508 if (opt_return_value)
509 opt_return_value->print();
510
511 printf("; ");
512 break;
513 case ast_discard:
514 printf("discard; ");
515 break;
516 }
517 }
518
519
520 ast_jump_statement::ast_jump_statement(int mode, ast_expression *return_value)
521 {
522 this->mode = ast_jump_modes(mode);
523
524 if (mode == ast_return)
525 opt_return_value = return_value;
526 }
527
528
529 void
530 ast_selection_statement::print(void) const
531 {
532 printf("if ( ");
533 condition->print();
534 printf(") ");
535
536 then_statement->print();
537
538 if (else_statement) {
539 printf("else ");
540 else_statement->print();
541 }
542
543 }
544
545
546 ast_selection_statement::ast_selection_statement(ast_expression *condition,
547 ast_node *then_statement,
548 ast_node *else_statement)
549 {
550 this->condition = condition;
551 this->then_statement = then_statement;
552 this->else_statement = else_statement;
553 }
554
555
556 void
557 ast_iteration_statement::print(void) const
558 {
559 switch (mode) {
560 case ast_for:
561 printf("for( ");
562 if (init_statement)
563 init_statement->print();
564 printf("; ");
565
566 if (condition)
567 condition->print();
568 printf("; ");
569
570 if (rest_expression)
571 rest_expression->print();
572 printf(") ");
573
574 body->print();
575 break;
576
577 case ast_while:
578 printf("while ( ");
579 if (condition)
580 condition->print();
581 printf(") ");
582 body->print();
583 break;
584
585 case ast_do_while:
586 printf("do ");
587 body->print();
588 printf("while ( ");
589 if (condition)
590 condition->print();
591 printf("); ");
592 break;
593 }
594 }
595
596
597 ast_iteration_statement::ast_iteration_statement(int mode,
598 ast_node *init,
599 ast_node *condition,
600 ast_expression *rest_expression,
601 ast_node *body)
602 {
603 this->mode = ast_iteration_modes(mode);
604 this->init_statement = init;
605 this->condition = condition;
606 this->rest_expression = rest_expression;
607 this->body = body;
608 }
609
610
611 void
612 ast_struct_specifier::print(void) const
613 {
614 printf("struct %s { ", name);
615 foreach_list_const(n, &this->declarations) {
616 ast_node *ast = exec_node_data(ast_node, n, link);
617 ast->print();
618 }
619 printf("} ");
620 }
621
622
623 ast_struct_specifier::ast_struct_specifier(char *identifier,
624 ast_node *declarator_list)
625 {
626 name = identifier;
627 this->declarations.push_degenerate_list_at_head(&declarator_list->link);
628 }