2 * Mesa 3-D graphics library
5 * Copyright (C) 2005-2006 Brian Paul All Rights Reserved.
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:
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
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.
26 * \file slang_assemble_typeinfo.c
32 #include "slang_typeinfo.h"
33 #include "slang_compile.h"
34 #include "slang_error.h"
35 #include "prog_instruction.h"
41 * Checks if a field selector is a general swizzle (an r-value swizzle
42 * with replicated components or an l-value swizzle mask) for a
43 * vector. Returns GL_TRUE if this is the case, <swz> is filled with
44 * swizzle information. Returns GL_FALSE otherwise.
47 _slang_is_swizzle(const char *field
, GLuint rows
, slang_swizzle
* swz
)
50 GLboolean xyzw
= GL_FALSE
, rgba
= GL_FALSE
, stpq
= GL_FALSE
;
53 * We rely on undefined/nil values to distinguish between
54 * regular swizzles and writemasks.
55 * For example, the swizzle ".xNNN" is the writemask ".x".
56 * That's different than the swizzle ".xxxx".
58 for (i
= 0; i
< 4; i
++)
59 swz
->swizzle
[i
] = SWIZZLE_NIL
;
61 /* the swizzle can be at most 4-component long */
62 swz
->num_components
= slang_string_length(field
);
63 if (swz
->num_components
> 4)
66 for (i
= 0; i
< swz
->num_components
; i
++) {
67 /* mark which swizzle group is used */
91 /* collect swizzle component */
115 /* check if the component is valid for given vector's row count */
116 if (rows
<= swz
->swizzle
[i
])
120 /* only one swizzle group can be used */
121 if ((xyzw
&& rgba
) || (xyzw
&& stpq
) || (rgba
&& stpq
))
130 * Checks if a general swizzle is an l-value swizzle - these swizzles
131 * do not have duplicated fields. Returns GL_TRUE if this is a
132 * swizzle mask. Returns GL_FALSE otherwise
135 _slang_is_swizzle_mask(const slang_swizzle
* swz
, GLuint rows
)
139 /* the swizzle may not be longer than the vector dim */
140 if (swz
->num_components
> rows
)
143 /* the swizzle components cannot be duplicated */
144 for (i
= 0; i
< swz
->num_components
; i
++) {
145 if ((c
& (1 << swz
->swizzle
[i
])) != 0)
147 c
|= 1 << swz
->swizzle
[i
];
155 slang_type_specifier_ctr(slang_type_specifier
* self
)
157 self
->type
= slang_spec_void
;
158 self
->_struct
= NULL
;
163 slang_type_specifier_dtr(slang_type_specifier
* self
)
165 if (self
->_struct
!= NULL
) {
166 slang_struct_destruct(self
->_struct
);
167 slang_alloc_free(self
->_struct
);
169 if (self
->_array
!= NULL
) {
170 slang_type_specifier_dtr(self
->_array
);
171 slang_alloc_free(self
->_array
);
176 slang_type_specifier_copy(slang_type_specifier
* x
,
177 const slang_type_specifier
* y
)
179 slang_type_specifier z
;
181 slang_type_specifier_ctr(&z
);
183 if (z
.type
== slang_spec_struct
) {
184 z
._struct
= (slang_struct
*) slang_alloc_malloc(sizeof(slang_struct
));
185 if (z
._struct
== NULL
) {
186 slang_type_specifier_dtr(&z
);
189 if (!slang_struct_construct(z
._struct
)) {
190 slang_alloc_free(z
._struct
);
191 slang_type_specifier_dtr(&z
);
194 if (!slang_struct_copy(z
._struct
, y
->_struct
)) {
195 slang_type_specifier_dtr(&z
);
199 else if (z
.type
== slang_spec_array
) {
201 (slang_type_specifier
*)
202 slang_alloc_malloc(sizeof(slang_type_specifier
));
203 if (z
._array
== NULL
) {
204 slang_type_specifier_dtr(&z
);
207 slang_type_specifier_ctr(z
._array
);
208 if (!slang_type_specifier_copy(z
._array
, y
->_array
)) {
209 slang_type_specifier_dtr(&z
);
213 slang_type_specifier_dtr(x
);
219 slang_type_specifier_equal(const slang_type_specifier
* x
,
220 const slang_type_specifier
* y
)
222 if (x
->type
!= y
->type
)
224 if (x
->type
== slang_spec_struct
)
225 return slang_struct_equal(x
->_struct
, y
->_struct
);
226 if (x
->type
== slang_spec_array
)
227 return slang_type_specifier_equal(x
->_array
, y
->_array
);
233 slang_typeinfo_construct(slang_typeinfo
* ti
)
235 slang_type_specifier_ctr(&ti
->spec
);
241 slang_typeinfo_destruct(slang_typeinfo
* ti
)
243 slang_type_specifier_dtr(&ti
->spec
);
248 * Determine the return type of a function.
249 * \param name name of the function
250 * \param params array of function parameters
251 * \param num_params number of parameters
252 * \param space namespace to use
253 * \param spec returns the function's type
254 * \param atoms atom pool
255 * \return GL_TRUE for success, GL_FALSE if failure
258 typeof_existing_function(const char *name
, const slang_operation
* params
,
260 const slang_name_space
* space
,
261 slang_type_specifier
* spec
,
262 slang_atom_pool
* atoms
)
267 atom
= slang_atom_pool_atom(atoms
, name
);
268 if (!_slang_typeof_function(atom
, params
, num_params
, space
, spec
,
275 _slang_typeof_operation(const slang_assemble_ctx
* A
,
276 const slang_operation
* op
,
279 return _slang_typeof_operation_(op
, &A
->space
, ti
, A
->atoms
);
284 * Determine the return type of an operation.
285 * \param op the operation node
286 * \param space the namespace to use
287 * \param ti the returned type
288 * \param atoms atom pool
289 * \return GL_TRUE for success, GL_FALSE if failure
292 _slang_typeof_operation_(const slang_operation
* op
,
293 const slang_name_space
* space
,
295 slang_atom_pool
* atoms
)
297 ti
->can_be_referenced
= GL_FALSE
;
298 ti
->is_swizzled
= GL_FALSE
;
301 case slang_oper_block_no_new_scope
:
302 case slang_oper_block_new_scope
:
303 case slang_oper_variable_decl
:
305 case slang_oper_break
:
306 case slang_oper_continue
:
307 case slang_oper_discard
:
308 case slang_oper_return
:
310 case slang_oper_while
:
313 case slang_oper_void
:
314 ti
->spec
.type
= slang_spec_void
;
316 case slang_oper_expression
:
317 case slang_oper_assign
:
318 case slang_oper_addassign
:
319 case slang_oper_subassign
:
320 case slang_oper_mulassign
:
321 case slang_oper_divassign
:
322 case slang_oper_preincrement
:
323 case slang_oper_predecrement
:
324 if (!_slang_typeof_operation_(op
->children
, space
, ti
, atoms
))
327 case slang_oper_literal_bool
:
328 case slang_oper_logicalor
:
329 case slang_oper_logicalxor
:
330 case slang_oper_logicaland
:
331 case slang_oper_equal
:
332 case slang_oper_notequal
:
333 case slang_oper_less
:
334 case slang_oper_greater
:
335 case slang_oper_lessequal
:
336 case slang_oper_greaterequal
:
338 ti
->spec
.type
= slang_spec_bool
;
340 case slang_oper_literal_int
:
341 ti
->spec
.type
= slang_spec_int
;
343 case slang_oper_literal_float
:
344 ti
->spec
.type
= slang_spec_float
;
346 case slang_oper_identifier
:
349 var
= _slang_locate_variable(op
->locals
, op
->a_id
, GL_TRUE
);
351 RETURN_ERROR2("undefined variable", (char *) op
->a_id
, 0);
352 if (!slang_type_specifier_copy(&ti
->spec
, &var
->type
.specifier
))
353 RETURN_OUT_OF_MEMORY();
354 ti
->can_be_referenced
= GL_TRUE
;
355 ti
->array_len
= var
->array_len
;
358 case slang_oper_sequence
:
359 /* TODO: check [0] and [1] if they match */
360 if (!_slang_typeof_operation_(&op
->children
[1], space
, ti
, atoms
))
362 ti
->can_be_referenced
= GL_FALSE
;
363 ti
->is_swizzled
= GL_FALSE
;
365 /*case slang_oper_modassign: */
366 /*case slang_oper_lshassign: */
367 /*case slang_oper_rshassign: */
368 /*case slang_oper_orassign: */
369 /*case slang_oper_xorassign: */
370 /*case slang_oper_andassign: */
371 case slang_oper_select
:
372 /* TODO: check [1] and [2] if they match */
373 if (!_slang_typeof_operation_(&op
->children
[1], space
, ti
, atoms
))
375 ti
->can_be_referenced
= GL_FALSE
;
376 ti
->is_swizzled
= GL_FALSE
;
378 /*case slang_oper_bitor: */
379 /*case slang_oper_bitxor: */
380 /*case slang_oper_bitand: */
381 /*case slang_oper_lshift: */
382 /*case slang_oper_rshift: */
384 if (!typeof_existing_function("+", op
->children
, 2, space
,
388 case slang_oper_subtract
:
389 if (!typeof_existing_function("-", op
->children
, 2, space
,
393 case slang_oper_multiply
:
394 if (!typeof_existing_function("*", op
->children
, 2, space
,
398 case slang_oper_divide
:
399 if (!typeof_existing_function("/", op
->children
, 2, space
,
403 /*case slang_oper_modulus: */
404 case slang_oper_plus
:
405 if (!_slang_typeof_operation_(op
->children
, space
, ti
, atoms
))
407 ti
->can_be_referenced
= GL_FALSE
;
408 ti
->is_swizzled
= GL_FALSE
;
410 case slang_oper_minus
:
411 if (!typeof_existing_function("-", op
->children
, 1, space
,
415 /*case slang_oper_complement: */
416 case slang_oper_subscript
:
420 if (!slang_typeinfo_construct(&_ti
))
422 if (!_slang_typeof_operation_(op
->children
, space
, &_ti
, atoms
)) {
423 slang_typeinfo_destruct(&_ti
);
426 ti
->can_be_referenced
= _ti
.can_be_referenced
;
427 if (_ti
.spec
.type
== slang_spec_array
) {
428 if (!slang_type_specifier_copy(&ti
->spec
, _ti
.spec
._array
)) {
429 slang_typeinfo_destruct(&_ti
);
434 if (!_slang_type_is_vector(_ti
.spec
.type
)
435 && !_slang_type_is_matrix(_ti
.spec
.type
)) {
436 slang_typeinfo_destruct(&_ti
);
437 RETURN_ERROR("cannot index a non-array type", 0);
439 ti
->spec
.type
= _slang_type_base(_ti
.spec
.type
);
441 slang_typeinfo_destruct(&_ti
);
444 case slang_oper_call
:
448 if (!_slang_typeof_function(op
->a_id
, op
->children
, op
->num_children
,
449 space
, &ti
->spec
, &exists
, atoms
))
453 slang_struct_scope_find(space
->structs
, op
->a_id
, GL_TRUE
);
455 ti
->spec
.type
= slang_spec_struct
;
457 (slang_struct
*) slang_alloc_malloc(sizeof(slang_struct
));
458 if (ti
->spec
._struct
== NULL
)
460 if (!slang_struct_construct(ti
->spec
._struct
)) {
461 slang_alloc_free(ti
->spec
._struct
);
462 ti
->spec
._struct
= NULL
;
465 if (!slang_struct_copy(ti
->spec
._struct
, s
))
470 slang_type_specifier_type type
;
472 name
= slang_atom_pool_id(atoms
, op
->a_id
);
473 type
= slang_type_specifier_type_from_string(name
);
474 if (type
== slang_spec_void
)
475 RETURN_ERROR2("function not found", name
, 0);
476 ti
->spec
.type
= type
;
481 case slang_oper_field
:
485 if (!slang_typeinfo_construct(&_ti
))
487 if (!_slang_typeof_operation_(op
->children
, space
, &_ti
, atoms
)) {
488 slang_typeinfo_destruct(&_ti
);
491 if (_ti
.spec
.type
== slang_spec_struct
) {
492 slang_variable
*field
;
494 field
= _slang_locate_variable(_ti
.spec
._struct
->fields
, op
->a_id
,
497 slang_typeinfo_destruct(&_ti
);
500 if (!slang_type_specifier_copy(&ti
->spec
, &field
->type
.specifier
)) {
501 slang_typeinfo_destruct(&_ti
);
504 ti
->can_be_referenced
= _ti
.can_be_referenced
;
509 slang_type_specifier_type base
;
511 /* determine the swizzle of the field expression */
513 if (!_slang_type_is_vector(_ti
.spec
.type
)) {
514 slang_typeinfo_destruct(&_ti
);
515 RETURN_ERROR("Can't swizzle scalar expression", 0);
518 rows
= _slang_type_dim(_ti
.spec
.type
);
519 swizzle
= slang_atom_pool_id(atoms
, op
->a_id
);
520 if (!_slang_is_swizzle(swizzle
, rows
, &ti
->swz
)) {
521 slang_typeinfo_destruct(&_ti
);
522 RETURN_ERROR("Bad swizzle", 0);
524 ti
->is_swizzled
= GL_TRUE
;
525 ti
->can_be_referenced
= _ti
.can_be_referenced
526 && _slang_is_swizzle_mask(&ti
->swz
, rows
);
527 if (_ti
.is_swizzled
) {
530 /* swizzle the swizzle */
531 _slang_multiply_swizzles(&swz
, &_ti
.swz
, &ti
->swz
);
534 base
= _slang_type_base(_ti
.spec
.type
);
535 switch (ti
->swz
.num_components
) {
537 ti
->spec
.type
= base
;
541 case slang_spec_float
:
542 ti
->spec
.type
= slang_spec_vec2
;
545 ti
->spec
.type
= slang_spec_ivec2
;
547 case slang_spec_bool
:
548 ti
->spec
.type
= slang_spec_bvec2
;
556 case slang_spec_float
:
557 ti
->spec
.type
= slang_spec_vec3
;
560 ti
->spec
.type
= slang_spec_ivec3
;
562 case slang_spec_bool
:
563 ti
->spec
.type
= slang_spec_bvec3
;
571 case slang_spec_float
:
572 ti
->spec
.type
= slang_spec_vec4
;
575 ti
->spec
.type
= slang_spec_ivec4
;
577 case slang_spec_bool
:
578 ti
->spec
.type
= slang_spec_bvec4
;
588 slang_typeinfo_destruct(&_ti
);
591 case slang_oper_postincrement
:
592 case slang_oper_postdecrement
:
593 if (!_slang_typeof_operation_(op
->children
, space
, ti
, atoms
))
595 ti
->can_be_referenced
= GL_FALSE
;
596 ti
->is_swizzled
= GL_FALSE
;
608 _slang_locate_function(const slang_function_scope
* funcs
, slang_atom a_name
,
609 const slang_operation
* args
, GLuint num_args
,
610 const slang_name_space
* space
,
611 slang_atom_pool
* atoms
)
615 for (i
= 0; i
< funcs
->num_functions
; i
++) {
616 slang_function
*f
= &funcs
->functions
[i
];
617 const GLuint haveRetValue
= _slang_function_has_return_value(f
);
620 if (a_name
!= f
->header
.a_name
)
622 if (f
->param_count
- haveRetValue
!= num_args
)
625 /* compare parameter / argument types */
626 for (j
= 0; j
< num_args
; j
++) {
629 if (!slang_typeinfo_construct(&ti
))
631 if (!_slang_typeof_operation_(&args
[j
], space
, &ti
, atoms
)) {
632 slang_typeinfo_destruct(&ti
);
635 if (!slang_type_specifier_equal(&ti
.spec
,
636 &f
->parameters
->variables
[j
/* + haveRetValue*/]->type
.specifier
)) {
637 slang_typeinfo_destruct(&ti
);
640 slang_typeinfo_destruct(&ti
);
642 /* "out" and "inout" formal parameter requires the actual parameter to be l-value */
643 if (!ti
.can_be_referenced
&&
644 (f
->parameters
->variables
[j
/* + haveRetValue*/]->type
.qualifier
== slang_qual_out
||
645 f
->parameters
->variables
[j
/* + haveRetValue*/]->type
.qualifier
== slang_qual_inout
))
651 if (funcs
->outer_scope
!= NULL
)
652 return _slang_locate_function(funcs
->outer_scope
, a_name
, args
,
653 num_args
, space
, atoms
);
660 * Determine the return type of a function.
661 * \param a_name the function name
662 * \param param function parameters (overloading)
663 * \param num_params number of parameters to function
664 * \param space namespace to search
665 * \param exists returns GL_TRUE or GL_FALSE to indicate existance of function
666 * \return GL_TRUE for success, GL_FALSE if failure (bad function name)
669 _slang_typeof_function(slang_atom a_name
, const slang_operation
* params
,
671 const slang_name_space
* space
,
672 slang_type_specifier
* spec
, GLboolean
* exists
,
673 slang_atom_pool
* atoms
)
675 slang_function
*fun
= _slang_locate_function(space
->funcs
, a_name
, params
,
676 num_params
, space
, atoms
);
677 *exists
= fun
!= NULL
;
679 return GL_TRUE
; /* yes, not false */
680 return slang_type_specifier_copy(spec
, &fun
->header
.type
.specifier
);
686 * Determine if a type is a matrix.
687 * \return GL_TRUE if is a matrix, GL_FALSE otherwise.
690 _slang_type_is_matrix(slang_type_specifier_type ty
)
693 case slang_spec_mat2
:
694 case slang_spec_mat3
:
695 case slang_spec_mat4
:
704 * Determine if a type is a vector.
705 * \return GL_TRUE if is a vector, GL_FALSE otherwise.
708 _slang_type_is_vector(slang_type_specifier_type ty
)
711 case slang_spec_vec2
:
712 case slang_spec_vec3
:
713 case slang_spec_vec4
:
714 case slang_spec_ivec2
:
715 case slang_spec_ivec3
:
716 case slang_spec_ivec4
:
717 case slang_spec_bvec2
:
718 case slang_spec_bvec3
:
719 case slang_spec_bvec4
:
728 * Given a vector type, return the type of the vector's elements
730 slang_type_specifier_type
731 _slang_type_base(slang_type_specifier_type ty
)
734 case slang_spec_float
:
735 case slang_spec_vec2
:
736 case slang_spec_vec3
:
737 case slang_spec_vec4
:
738 return slang_spec_float
;
740 case slang_spec_ivec2
:
741 case slang_spec_ivec3
:
742 case slang_spec_ivec4
:
743 return slang_spec_int
;
744 case slang_spec_bool
:
745 case slang_spec_bvec2
:
746 case slang_spec_bvec3
:
747 case slang_spec_bvec4
:
748 return slang_spec_bool
;
749 case slang_spec_mat2
:
750 return slang_spec_vec2
;
751 case slang_spec_mat3
:
752 return slang_spec_vec3
;
753 case slang_spec_mat4
:
754 return slang_spec_vec4
;
756 return slang_spec_void
;
762 * Return the dimensionality of a vector or matrix type.
765 _slang_type_dim(slang_type_specifier_type ty
)
768 case slang_spec_float
:
770 case slang_spec_bool
:
772 case slang_spec_vec2
:
773 case slang_spec_ivec2
:
774 case slang_spec_bvec2
:
775 case slang_spec_mat2
:
777 case slang_spec_vec3
:
778 case slang_spec_ivec3
:
779 case slang_spec_bvec3
:
780 case slang_spec_mat3
:
782 case slang_spec_vec4
:
783 case slang_spec_ivec4
:
784 case slang_spec_bvec4
:
785 case slang_spec_mat4
: