remove stray tab
[mesa.git] / src / mesa / shader / slang / slang_assemble_typeinfo.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 6.5
4 *
5 * Copyright (C) 2005-2006 Brian Paul All Rights Reserved.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25 /**
26 * \file slang_assemble_typeinfo.c
27 * slang type info
28 * \author Michal Krol
29 */
30
31 #include "imports.h"
32 #include "slang_assemble.h"
33 #include "slang_compile.h"
34 #include "slang_error.h"
35
36
37 GLvoid
38 slang_type_specifier_ctr(slang_type_specifier * self)
39 {
40 self->type = slang_spec_void;
41 self->_struct = NULL;
42 self->_array = NULL;
43 }
44
45 GLvoid
46 slang_type_specifier_dtr(slang_type_specifier * self)
47 {
48 if (self->_struct != NULL) {
49 slang_struct_destruct(self->_struct);
50 slang_alloc_free(self->_struct);
51 }
52 if (self->_array != NULL) {
53 slang_type_specifier_dtr(self->_array);
54 slang_alloc_free(self->_array);
55 }
56 }
57
58 GLboolean
59 slang_type_specifier_copy(slang_type_specifier * x,
60 const slang_type_specifier * y)
61 {
62 slang_type_specifier z;
63
64 slang_type_specifier_ctr(&z);
65 z.type = y->type;
66 if (z.type == slang_spec_struct) {
67 z._struct = (slang_struct *) slang_alloc_malloc(sizeof(slang_struct));
68 if (z._struct == NULL) {
69 slang_type_specifier_dtr(&z);
70 return GL_FALSE;
71 }
72 if (!slang_struct_construct(z._struct)) {
73 slang_alloc_free(z._struct);
74 slang_type_specifier_dtr(&z);
75 return GL_FALSE;
76 }
77 if (!slang_struct_copy(z._struct, y->_struct)) {
78 slang_type_specifier_dtr(&z);
79 return GL_FALSE;
80 }
81 }
82 else if (z.type == slang_spec_array) {
83 z._array =
84 (slang_type_specifier *)
85 slang_alloc_malloc(sizeof(slang_type_specifier));
86 if (z._array == NULL) {
87 slang_type_specifier_dtr(&z);
88 return GL_FALSE;
89 }
90 slang_type_specifier_ctr(z._array);
91 if (!slang_type_specifier_copy(z._array, y->_array)) {
92 slang_type_specifier_dtr(&z);
93 return GL_FALSE;
94 }
95 }
96 slang_type_specifier_dtr(x);
97 *x = z;
98 return GL_TRUE;
99 }
100
101 GLboolean
102 slang_type_specifier_equal(const slang_type_specifier * x,
103 const slang_type_specifier * y)
104 {
105 if (x->type != y->type)
106 return 0;
107 if (x->type == slang_spec_struct)
108 return slang_struct_equal(x->_struct, y->_struct);
109 if (x->type == slang_spec_array)
110 return slang_type_specifier_equal(x->_array, y->_array);
111 return 1;
112 }
113
114
115 GLboolean
116 slang_assembly_typeinfo_construct(slang_assembly_typeinfo * ti)
117 {
118 slang_type_specifier_ctr(&ti->spec);
119 ti->array_len = 0;
120 return GL_TRUE;
121 }
122
123 GLvoid
124 slang_assembly_typeinfo_destruct(slang_assembly_typeinfo * ti)
125 {
126 slang_type_specifier_dtr(&ti->spec);
127 }
128
129
130 /**
131 * Determine the return type of a function.
132 * \param name name of the function
133 * \param params array of function parameters
134 * \param num_params number of parameters
135 * \param space namespace to use
136 * \param spec returns the function's type
137 * \param atoms atom pool
138 * \return GL_TRUE for success, GL_FALSE if failure
139 */
140 static GLboolean
141 typeof_existing_function(const char *name, const slang_operation * params,
142 GLuint num_params,
143 const slang_assembly_name_space * space,
144 slang_type_specifier * spec,
145 slang_atom_pool * atoms)
146 {
147 slang_atom atom;
148 GLboolean exists;
149
150 atom = slang_atom_pool_atom(atoms, name);
151 if (!_slang_typeof_function(atom, params, num_params, space, spec,
152 &exists, atoms))
153 return GL_FALSE;
154 return exists;
155 }
156
157 GLboolean
158 _slang_typeof_operation(const slang_assemble_ctx * A,
159 const slang_operation * op,
160 slang_assembly_typeinfo * ti)
161 {
162 return _slang_typeof_operation_(op, &A->space, ti, A->atoms);
163 }
164
165
166 /**
167 * Determine the return type of an operation.
168 * \param op the operation node
169 * \param space the namespace to use
170 * \param ti the returned type
171 * \param atoms atom pool
172 * \return GL_TRUE for success, GL_FALSE if failure
173 */
174 GLboolean
175 _slang_typeof_operation_(const slang_operation * op,
176 const slang_assembly_name_space * space,
177 slang_assembly_typeinfo * ti,
178 slang_atom_pool * atoms)
179 {
180 ti->can_be_referenced = GL_FALSE;
181 ti->is_swizzled = GL_FALSE;
182
183 switch (op->type) {
184 case slang_oper_block_no_new_scope:
185 case slang_oper_block_new_scope:
186 case slang_oper_variable_decl:
187 case slang_oper_asm:
188 case slang_oper_break:
189 case slang_oper_continue:
190 case slang_oper_discard:
191 case slang_oper_return:
192 case slang_oper_if:
193 case slang_oper_while:
194 case slang_oper_do:
195 case slang_oper_for:
196 case slang_oper_void:
197 ti->spec.type = slang_spec_void;
198 break;
199 case slang_oper_expression:
200 case slang_oper_assign:
201 case slang_oper_addassign:
202 case slang_oper_subassign:
203 case slang_oper_mulassign:
204 case slang_oper_divassign:
205 case slang_oper_preincrement:
206 case slang_oper_predecrement:
207 if (!_slang_typeof_operation_(op->children, space, ti, atoms))
208 return GL_FALSE;
209 break;
210 case slang_oper_literal_bool:
211 case slang_oper_logicalor:
212 case slang_oper_logicalxor:
213 case slang_oper_logicaland:
214 case slang_oper_equal:
215 case slang_oper_notequal:
216 case slang_oper_less:
217 case slang_oper_greater:
218 case slang_oper_lessequal:
219 case slang_oper_greaterequal:
220 case slang_oper_not:
221 ti->spec.type = slang_spec_bool;
222 break;
223 case slang_oper_literal_int:
224 ti->spec.type = slang_spec_int;
225 break;
226 case slang_oper_literal_float:
227 ti->spec.type = slang_spec_float;
228 break;
229 case slang_oper_identifier:
230 {
231 slang_variable *var;
232 var = _slang_locate_variable(op->locals, op->a_id, GL_TRUE);
233 if (var == NULL)
234 RETURN_ERROR2("undefined variable", (char *) op->a_id, 0);
235 if (!slang_type_specifier_copy(&ti->spec, &var->type.specifier))
236 RETURN_OUT_OF_MEMORY();
237 ti->can_be_referenced = GL_TRUE;
238 ti->array_len = var->array_len;
239 }
240 break;
241 case slang_oper_sequence:
242 /* TODO: check [0] and [1] if they match */
243 if (!_slang_typeof_operation_(&op->children[1], space, ti, atoms))
244 RETURN_NIL();
245 ti->can_be_referenced = GL_FALSE;
246 ti->is_swizzled = GL_FALSE;
247 break;
248 /*case slang_oper_modassign: */
249 /*case slang_oper_lshassign: */
250 /*case slang_oper_rshassign: */
251 /*case slang_oper_orassign: */
252 /*case slang_oper_xorassign: */
253 /*case slang_oper_andassign: */
254 case slang_oper_select:
255 /* TODO: check [1] and [2] if they match */
256 if (!_slang_typeof_operation_(&op->children[1], space, ti, atoms))
257 RETURN_NIL();
258 ti->can_be_referenced = GL_FALSE;
259 ti->is_swizzled = GL_FALSE;
260 break;
261 /*case slang_oper_bitor: */
262 /*case slang_oper_bitxor: */
263 /*case slang_oper_bitand: */
264 /*case slang_oper_lshift: */
265 /*case slang_oper_rshift: */
266 case slang_oper_add:
267 if (!typeof_existing_function("+", op->children, 2, space,
268 &ti->spec, atoms))
269 RETURN_NIL();
270 break;
271 case slang_oper_subtract:
272 if (!typeof_existing_function("-", op->children, 2, space,
273 &ti->spec, atoms))
274 RETURN_NIL();
275 break;
276 case slang_oper_multiply:
277 if (!typeof_existing_function("*", op->children, 2, space,
278 &ti->spec, atoms))
279 RETURN_NIL();
280 break;
281 case slang_oper_divide:
282 if (!typeof_existing_function("/", op->children, 2, space,
283 &ti->spec, atoms))
284 RETURN_NIL();
285 break;
286 /*case slang_oper_modulus: */
287 case slang_oper_plus:
288 if (!_slang_typeof_operation_(op->children, space, ti, atoms))
289 RETURN_NIL();
290 ti->can_be_referenced = GL_FALSE;
291 ti->is_swizzled = GL_FALSE;
292 break;
293 case slang_oper_minus:
294 if (!typeof_existing_function("-", op->children, 1, space,
295 &ti->spec, atoms))
296 RETURN_NIL();
297 break;
298 /*case slang_oper_complement: */
299 case slang_oper_subscript:
300 {
301 slang_assembly_typeinfo _ti;
302
303 if (!slang_assembly_typeinfo_construct(&_ti))
304 RETURN_NIL();
305 if (!_slang_typeof_operation_(op->children, space, &_ti, atoms)) {
306 slang_assembly_typeinfo_destruct(&_ti);
307 RETURN_NIL();
308 }
309 ti->can_be_referenced = _ti.can_be_referenced;
310 if (_ti.spec.type == slang_spec_array) {
311 if (!slang_type_specifier_copy(&ti->spec, _ti.spec._array)) {
312 slang_assembly_typeinfo_destruct(&_ti);
313 RETURN_NIL();
314 }
315 }
316 else {
317 if (!_slang_type_is_vector(_ti.spec.type)
318 && !_slang_type_is_matrix(_ti.spec.type)) {
319 slang_assembly_typeinfo_destruct(&_ti);
320 RETURN_ERROR("cannot index a non-array type", 0);
321 }
322 ti->spec.type = _slang_type_base(_ti.spec.type);
323 }
324 slang_assembly_typeinfo_destruct(&_ti);
325 }
326 break;
327 case slang_oper_call:
328 {
329 GLboolean exists;
330
331 if (!_slang_typeof_function(op->a_id, op->children, op->num_children,
332 space, &ti->spec, &exists, atoms))
333 RETURN_NIL();
334 if (!exists) {
335 slang_struct *s =
336 slang_struct_scope_find(space->structs, op->a_id, GL_TRUE);
337 if (s != NULL) {
338 ti->spec.type = slang_spec_struct;
339 ti->spec._struct =
340 (slang_struct *) slang_alloc_malloc(sizeof(slang_struct));
341 if (ti->spec._struct == NULL)
342 RETURN_NIL();
343 if (!slang_struct_construct(ti->spec._struct)) {
344 slang_alloc_free(ti->spec._struct);
345 ti->spec._struct = NULL;
346 RETURN_NIL();
347 }
348 if (!slang_struct_copy(ti->spec._struct, s))
349 RETURN_NIL();
350 }
351 else {
352 const char *name;
353 slang_type_specifier_type type;
354
355 name = slang_atom_pool_id(atoms, op->a_id);
356 type = slang_type_specifier_type_from_string(name);
357 if (type == slang_spec_void)
358 RETURN_ERROR2("function not found", name, 0);
359 ti->spec.type = type;
360 }
361 }
362 }
363 break;
364 case slang_oper_field:
365 {
366 slang_assembly_typeinfo _ti;
367
368 if (!slang_assembly_typeinfo_construct(&_ti))
369 RETURN_NIL();
370 if (!_slang_typeof_operation_(op->children, space, &_ti, atoms)) {
371 slang_assembly_typeinfo_destruct(&_ti);
372 RETURN_NIL();
373 }
374 if (_ti.spec.type == slang_spec_struct) {
375 slang_variable *field;
376
377 field = _slang_locate_variable(_ti.spec._struct->fields, op->a_id,
378 GL_FALSE);
379 if (field == NULL) {
380 slang_assembly_typeinfo_destruct(&_ti);
381 RETURN_NIL();
382 }
383 if (!slang_type_specifier_copy(&ti->spec, &field->type.specifier)) {
384 slang_assembly_typeinfo_destruct(&_ti);
385 RETURN_NIL();
386 }
387 ti->can_be_referenced = _ti.can_be_referenced;
388 }
389 else {
390 GLuint rows;
391 const char *swizzle;
392 slang_type_specifier_type base;
393
394 /* determine the swizzle of the field expression */
395 #if 000
396 if (!_slang_type_is_vector(_ti.spec.type)) {
397 slang_assembly_typeinfo_destruct(&_ti);
398 RETURN_ERROR("Can't swizzle scalar expression", 0);
399 }
400 #endif
401 rows = _slang_type_dim(_ti.spec.type);
402 swizzle = slang_atom_pool_id(atoms, op->a_id);
403 if (!_slang_is_swizzle(swizzle, rows, &ti->swz)) {
404 slang_assembly_typeinfo_destruct(&_ti);
405 RETURN_ERROR("Bad swizzle", 0);
406 }
407 ti->is_swizzled = GL_TRUE;
408 ti->can_be_referenced = _ti.can_be_referenced
409 && _slang_is_swizzle_mask(&ti->swz, rows);
410 if (_ti.is_swizzled) {
411 slang_swizzle swz;
412
413 /* swizzle the swizzle */
414 _slang_multiply_swizzles(&swz, &_ti.swz, &ti->swz);
415 ti->swz = swz;
416 }
417 base = _slang_type_base(_ti.spec.type);
418 switch (ti->swz.num_components) {
419 case 1:
420 ti->spec.type = base;
421 break;
422 case 2:
423 switch (base) {
424 case slang_spec_float:
425 ti->spec.type = slang_spec_vec2;
426 break;
427 case slang_spec_int:
428 ti->spec.type = slang_spec_ivec2;
429 break;
430 case slang_spec_bool:
431 ti->spec.type = slang_spec_bvec2;
432 break;
433 default:
434 break;
435 }
436 break;
437 case 3:
438 switch (base) {
439 case slang_spec_float:
440 ti->spec.type = slang_spec_vec3;
441 break;
442 case slang_spec_int:
443 ti->spec.type = slang_spec_ivec3;
444 break;
445 case slang_spec_bool:
446 ti->spec.type = slang_spec_bvec3;
447 break;
448 default:
449 break;
450 }
451 break;
452 case 4:
453 switch (base) {
454 case slang_spec_float:
455 ti->spec.type = slang_spec_vec4;
456 break;
457 case slang_spec_int:
458 ti->spec.type = slang_spec_ivec4;
459 break;
460 case slang_spec_bool:
461 ti->spec.type = slang_spec_bvec4;
462 break;
463 default:
464 break;
465 }
466 break;
467 default:
468 break;
469 }
470 }
471 slang_assembly_typeinfo_destruct(&_ti);
472 }
473 break;
474 case slang_oper_postincrement:
475 case slang_oper_postdecrement:
476 if (!_slang_typeof_operation_(op->children, space, ti, atoms))
477 RETURN_NIL();
478 ti->can_be_referenced = GL_FALSE;
479 ti->is_swizzled = GL_FALSE;
480 break;
481 default:
482 RETURN_NIL();
483 }
484
485 return GL_TRUE;
486 }
487
488
489
490 /**
491 * Determine the return type of a function.
492 * \param a_name the function name
493 * \param param function parameters (overloading)
494 * \param num_params number of parameters to function
495 * \param space namespace to search
496 * \param exists returns GL_TRUE or GL_FALSE to indicate existance of function
497 * \return GL_TRUE for success, GL_FALSE if failure (bad function name)
498 */
499 GLboolean
500 _slang_typeof_function(slang_atom a_name, const slang_operation * params,
501 GLuint num_params,
502 const slang_assembly_name_space * space,
503 slang_type_specifier * spec, GLboolean * exists,
504 slang_atom_pool * atoms)
505 {
506 slang_function *fun = _slang_locate_function(space->funcs, a_name, params,
507 num_params, space, atoms);
508 *exists = fun != NULL;
509 if (!fun)
510 return GL_TRUE; /* yes, not false */
511 return slang_type_specifier_copy(spec, &fun->header.type.specifier);
512 }
513
514
515
516 /**
517 * Determine if a type is a matrix.
518 * \return GL_TRUE if is a matrix, GL_FALSE otherwise.
519 */
520 GLboolean
521 _slang_type_is_matrix(slang_type_specifier_type ty)
522 {
523 switch (ty) {
524 case slang_spec_mat2:
525 case slang_spec_mat3:
526 case slang_spec_mat4:
527 return GL_TRUE;
528 default:
529 return GL_FALSE;
530 }
531 }
532
533
534 /**
535 * Determine if a type is a vector.
536 * \return GL_TRUE if is a vector, GL_FALSE otherwise.
537 */
538 GLboolean
539 _slang_type_is_vector(slang_type_specifier_type ty)
540 {
541 switch (ty) {
542 case slang_spec_vec2:
543 case slang_spec_vec3:
544 case slang_spec_vec4:
545 case slang_spec_ivec2:
546 case slang_spec_ivec3:
547 case slang_spec_ivec4:
548 case slang_spec_bvec2:
549 case slang_spec_bvec3:
550 case slang_spec_bvec4:
551 return GL_TRUE;
552 default:
553 return GL_FALSE;
554 }
555 }
556
557
558 /**
559 * Given a vector type, return the type of the vector's elements
560 */
561 slang_type_specifier_type
562 _slang_type_base(slang_type_specifier_type ty)
563 {
564 switch (ty) {
565 case slang_spec_float:
566 case slang_spec_vec2:
567 case slang_spec_vec3:
568 case slang_spec_vec4:
569 return slang_spec_float;
570 case slang_spec_int:
571 case slang_spec_ivec2:
572 case slang_spec_ivec3:
573 case slang_spec_ivec4:
574 return slang_spec_int;
575 case slang_spec_bool:
576 case slang_spec_bvec2:
577 case slang_spec_bvec3:
578 case slang_spec_bvec4:
579 return slang_spec_bool;
580 case slang_spec_mat2:
581 return slang_spec_vec2;
582 case slang_spec_mat3:
583 return slang_spec_vec3;
584 case slang_spec_mat4:
585 return slang_spec_vec4;
586 default:
587 return slang_spec_void;
588 }
589 }
590
591
592 /**
593 * Return the dimensionality of a vector or matrix type.
594 */
595 GLuint
596 _slang_type_dim(slang_type_specifier_type ty)
597 {
598 switch (ty) {
599 case slang_spec_float:
600 case slang_spec_int:
601 case slang_spec_bool:
602 return 1;
603 case slang_spec_vec2:
604 case slang_spec_ivec2:
605 case slang_spec_bvec2:
606 case slang_spec_mat2:
607 return 2;
608 case slang_spec_vec3:
609 case slang_spec_ivec3:
610 case slang_spec_bvec3:
611 case slang_spec_mat3:
612 return 3;
613 case slang_spec_vec4:
614 case slang_spec_ivec4:
615 case slang_spec_bvec4:
616 case slang_spec_mat4:
617 return 4;
618 default:
619 return 0;
620 }
621 }