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 * Combines (multiplies) two swizzles to form single swizzle.
156 * Example: "vec.wzyx.yx" --> "vec.zw".
159 _slang_multiply_swizzles(slang_swizzle
* dst
, const slang_swizzle
* left
,
160 const slang_swizzle
* right
)
164 dst
->num_components
= right
->num_components
;
165 for (i
= 0; i
< right
->num_components
; i
++)
166 dst
->swizzle
[i
] = left
->swizzle
[right
->swizzle
[i
]];
171 slang_type_specifier_ctr(slang_type_specifier
* self
)
173 self
->type
= slang_spec_void
;
174 self
->_struct
= NULL
;
179 slang_type_specifier_dtr(slang_type_specifier
* self
)
181 if (self
->_struct
!= NULL
) {
182 slang_struct_destruct(self
->_struct
);
183 slang_alloc_free(self
->_struct
);
185 if (self
->_array
!= NULL
) {
186 slang_type_specifier_dtr(self
->_array
);
187 slang_alloc_free(self
->_array
);
192 slang_type_specifier_copy(slang_type_specifier
* x
,
193 const slang_type_specifier
* y
)
195 slang_type_specifier z
;
197 slang_type_specifier_ctr(&z
);
199 if (z
.type
== slang_spec_struct
) {
200 z
._struct
= (slang_struct
*) slang_alloc_malloc(sizeof(slang_struct
));
201 if (z
._struct
== NULL
) {
202 slang_type_specifier_dtr(&z
);
205 if (!slang_struct_construct(z
._struct
)) {
206 slang_alloc_free(z
._struct
);
207 slang_type_specifier_dtr(&z
);
210 if (!slang_struct_copy(z
._struct
, y
->_struct
)) {
211 slang_type_specifier_dtr(&z
);
215 else if (z
.type
== slang_spec_array
) {
217 (slang_type_specifier
*)
218 slang_alloc_malloc(sizeof(slang_type_specifier
));
219 if (z
._array
== NULL
) {
220 slang_type_specifier_dtr(&z
);
223 slang_type_specifier_ctr(z
._array
);
224 if (!slang_type_specifier_copy(z
._array
, y
->_array
)) {
225 slang_type_specifier_dtr(&z
);
229 slang_type_specifier_dtr(x
);
235 slang_type_specifier_equal(const slang_type_specifier
* x
,
236 const slang_type_specifier
* y
)
238 if (x
->type
!= y
->type
)
240 if (x
->type
== slang_spec_struct
)
241 return slang_struct_equal(x
->_struct
, y
->_struct
);
242 if (x
->type
== slang_spec_array
)
243 return slang_type_specifier_equal(x
->_array
, y
->_array
);
249 slang_typeinfo_construct(slang_typeinfo
* ti
)
251 slang_type_specifier_ctr(&ti
->spec
);
257 slang_typeinfo_destruct(slang_typeinfo
* ti
)
259 slang_type_specifier_dtr(&ti
->spec
);
264 * Determine the return type of a function.
265 * \param name name of the function
266 * \param params array of function parameters
267 * \param num_params number of parameters
268 * \param space namespace to use
269 * \param spec returns the function's type
270 * \param atoms atom pool
271 * \return GL_TRUE for success, GL_FALSE if failure
274 typeof_existing_function(const char *name
, const slang_operation
* params
,
276 const slang_name_space
* space
,
277 slang_type_specifier
* spec
,
278 slang_atom_pool
* atoms
)
283 atom
= slang_atom_pool_atom(atoms
, name
);
284 if (!_slang_typeof_function(atom
, params
, num_params
, space
, spec
,
291 _slang_typeof_operation(const slang_assemble_ctx
* A
,
292 const slang_operation
* op
,
295 return _slang_typeof_operation_(op
, &A
->space
, ti
, A
->atoms
);
300 * Determine the return type of an operation.
301 * \param op the operation node
302 * \param space the namespace to use
303 * \param ti the returned type
304 * \param atoms atom pool
305 * \return GL_TRUE for success, GL_FALSE if failure
308 _slang_typeof_operation_(const slang_operation
* op
,
309 const slang_name_space
* space
,
311 slang_atom_pool
* atoms
)
313 ti
->can_be_referenced
= GL_FALSE
;
314 ti
->is_swizzled
= GL_FALSE
;
317 case slang_oper_block_no_new_scope
:
318 case slang_oper_block_new_scope
:
319 case slang_oper_variable_decl
:
321 case slang_oper_break
:
322 case slang_oper_continue
:
323 case slang_oper_discard
:
324 case slang_oper_return
:
326 case slang_oper_while
:
329 case slang_oper_void
:
330 ti
->spec
.type
= slang_spec_void
;
332 case slang_oper_expression
:
333 case slang_oper_assign
:
334 case slang_oper_addassign
:
335 case slang_oper_subassign
:
336 case slang_oper_mulassign
:
337 case slang_oper_divassign
:
338 case slang_oper_preincrement
:
339 case slang_oper_predecrement
:
340 if (!_slang_typeof_operation_(op
->children
, space
, ti
, atoms
))
343 case slang_oper_literal_bool
:
344 case slang_oper_logicalor
:
345 case slang_oper_logicalxor
:
346 case slang_oper_logicaland
:
347 case slang_oper_equal
:
348 case slang_oper_notequal
:
349 case slang_oper_less
:
350 case slang_oper_greater
:
351 case slang_oper_lessequal
:
352 case slang_oper_greaterequal
:
354 ti
->spec
.type
= slang_spec_bool
;
356 case slang_oper_literal_int
:
357 ti
->spec
.type
= slang_spec_int
;
359 case slang_oper_literal_float
:
360 ti
->spec
.type
= slang_spec_float
;
362 case slang_oper_identifier
:
365 var
= _slang_locate_variable(op
->locals
, op
->a_id
, GL_TRUE
);
367 RETURN_ERROR2("undefined variable", (char *) op
->a_id
, 0);
368 if (!slang_type_specifier_copy(&ti
->spec
, &var
->type
.specifier
))
369 RETURN_OUT_OF_MEMORY();
370 ti
->can_be_referenced
= GL_TRUE
;
371 ti
->array_len
= var
->array_len
;
374 case slang_oper_sequence
:
375 /* TODO: check [0] and [1] if they match */
376 if (!_slang_typeof_operation_(&op
->children
[1], space
, ti
, atoms
))
378 ti
->can_be_referenced
= GL_FALSE
;
379 ti
->is_swizzled
= GL_FALSE
;
381 /*case slang_oper_modassign: */
382 /*case slang_oper_lshassign: */
383 /*case slang_oper_rshassign: */
384 /*case slang_oper_orassign: */
385 /*case slang_oper_xorassign: */
386 /*case slang_oper_andassign: */
387 case slang_oper_select
:
388 /* TODO: check [1] and [2] if they match */
389 if (!_slang_typeof_operation_(&op
->children
[1], space
, ti
, atoms
))
391 ti
->can_be_referenced
= GL_FALSE
;
392 ti
->is_swizzled
= GL_FALSE
;
394 /*case slang_oper_bitor: */
395 /*case slang_oper_bitxor: */
396 /*case slang_oper_bitand: */
397 /*case slang_oper_lshift: */
398 /*case slang_oper_rshift: */
400 if (!typeof_existing_function("+", op
->children
, 2, space
,
404 case slang_oper_subtract
:
405 if (!typeof_existing_function("-", op
->children
, 2, space
,
409 case slang_oper_multiply
:
410 if (!typeof_existing_function("*", op
->children
, 2, space
,
414 case slang_oper_divide
:
415 if (!typeof_existing_function("/", op
->children
, 2, space
,
419 /*case slang_oper_modulus: */
420 case slang_oper_plus
:
421 if (!_slang_typeof_operation_(op
->children
, space
, ti
, atoms
))
423 ti
->can_be_referenced
= GL_FALSE
;
424 ti
->is_swizzled
= GL_FALSE
;
426 case slang_oper_minus
:
427 if (!typeof_existing_function("-", op
->children
, 1, space
,
431 /*case slang_oper_complement: */
432 case slang_oper_subscript
:
436 if (!slang_typeinfo_construct(&_ti
))
438 if (!_slang_typeof_operation_(op
->children
, space
, &_ti
, atoms
)) {
439 slang_typeinfo_destruct(&_ti
);
442 ti
->can_be_referenced
= _ti
.can_be_referenced
;
443 if (_ti
.spec
.type
== slang_spec_array
) {
444 if (!slang_type_specifier_copy(&ti
->spec
, _ti
.spec
._array
)) {
445 slang_typeinfo_destruct(&_ti
);
450 if (!_slang_type_is_vector(_ti
.spec
.type
)
451 && !_slang_type_is_matrix(_ti
.spec
.type
)) {
452 slang_typeinfo_destruct(&_ti
);
453 RETURN_ERROR("cannot index a non-array type", 0);
455 ti
->spec
.type
= _slang_type_base(_ti
.spec
.type
);
457 slang_typeinfo_destruct(&_ti
);
460 case slang_oper_call
:
464 if (!_slang_typeof_function(op
->a_id
, op
->children
, op
->num_children
,
465 space
, &ti
->spec
, &exists
, atoms
))
469 slang_struct_scope_find(space
->structs
, op
->a_id
, GL_TRUE
);
471 ti
->spec
.type
= slang_spec_struct
;
473 (slang_struct
*) slang_alloc_malloc(sizeof(slang_struct
));
474 if (ti
->spec
._struct
== NULL
)
476 if (!slang_struct_construct(ti
->spec
._struct
)) {
477 slang_alloc_free(ti
->spec
._struct
);
478 ti
->spec
._struct
= NULL
;
481 if (!slang_struct_copy(ti
->spec
._struct
, s
))
486 slang_type_specifier_type type
;
488 name
= slang_atom_pool_id(atoms
, op
->a_id
);
489 type
= slang_type_specifier_type_from_string(name
);
490 if (type
== slang_spec_void
)
491 RETURN_ERROR2("function not found", name
, 0);
492 ti
->spec
.type
= type
;
497 case slang_oper_field
:
501 if (!slang_typeinfo_construct(&_ti
))
503 if (!_slang_typeof_operation_(op
->children
, space
, &_ti
, atoms
)) {
504 slang_typeinfo_destruct(&_ti
);
507 if (_ti
.spec
.type
== slang_spec_struct
) {
508 slang_variable
*field
;
510 field
= _slang_locate_variable(_ti
.spec
._struct
->fields
, op
->a_id
,
513 slang_typeinfo_destruct(&_ti
);
516 if (!slang_type_specifier_copy(&ti
->spec
, &field
->type
.specifier
)) {
517 slang_typeinfo_destruct(&_ti
);
520 ti
->can_be_referenced
= _ti
.can_be_referenced
;
525 slang_type_specifier_type base
;
527 /* determine the swizzle of the field expression */
529 if (!_slang_type_is_vector(_ti
.spec
.type
)) {
530 slang_typeinfo_destruct(&_ti
);
531 RETURN_ERROR("Can't swizzle scalar expression", 0);
534 rows
= _slang_type_dim(_ti
.spec
.type
);
535 swizzle
= slang_atom_pool_id(atoms
, op
->a_id
);
536 if (!_slang_is_swizzle(swizzle
, rows
, &ti
->swz
)) {
537 slang_typeinfo_destruct(&_ti
);
538 RETURN_ERROR("Bad swizzle", 0);
540 ti
->is_swizzled
= GL_TRUE
;
541 ti
->can_be_referenced
= _ti
.can_be_referenced
542 && _slang_is_swizzle_mask(&ti
->swz
, rows
);
543 if (_ti
.is_swizzled
) {
546 /* swizzle the swizzle */
547 _slang_multiply_swizzles(&swz
, &_ti
.swz
, &ti
->swz
);
550 base
= _slang_type_base(_ti
.spec
.type
);
551 switch (ti
->swz
.num_components
) {
553 ti
->spec
.type
= base
;
557 case slang_spec_float
:
558 ti
->spec
.type
= slang_spec_vec2
;
561 ti
->spec
.type
= slang_spec_ivec2
;
563 case slang_spec_bool
:
564 ti
->spec
.type
= slang_spec_bvec2
;
572 case slang_spec_float
:
573 ti
->spec
.type
= slang_spec_vec3
;
576 ti
->spec
.type
= slang_spec_ivec3
;
578 case slang_spec_bool
:
579 ti
->spec
.type
= slang_spec_bvec3
;
587 case slang_spec_float
:
588 ti
->spec
.type
= slang_spec_vec4
;
591 ti
->spec
.type
= slang_spec_ivec4
;
593 case slang_spec_bool
:
594 ti
->spec
.type
= slang_spec_bvec4
;
604 slang_typeinfo_destruct(&_ti
);
607 case slang_oper_postincrement
:
608 case slang_oper_postdecrement
:
609 if (!_slang_typeof_operation_(op
->children
, space
, ti
, atoms
))
611 ti
->can_be_referenced
= GL_FALSE
;
612 ti
->is_swizzled
= GL_FALSE
;
624 _slang_locate_function(const slang_function_scope
* funcs
, slang_atom a_name
,
625 const slang_operation
* args
, GLuint num_args
,
626 const slang_name_space
* space
,
627 slang_atom_pool
* atoms
)
631 for (i
= 0; i
< funcs
->num_functions
; i
++) {
632 slang_function
*f
= &funcs
->functions
[i
];
633 const GLuint haveRetValue
= _slang_function_has_return_value(f
);
636 if (a_name
!= f
->header
.a_name
)
638 if (f
->param_count
- haveRetValue
!= num_args
)
641 /* compare parameter / argument types */
642 for (j
= 0; j
< num_args
; j
++) {
645 if (!slang_typeinfo_construct(&ti
))
647 if (!_slang_typeof_operation_(&args
[j
], space
, &ti
, atoms
)) {
648 slang_typeinfo_destruct(&ti
);
651 if (!slang_type_specifier_equal(&ti
.spec
,
652 &f
->parameters
->variables
[j
/* + haveRetValue*/]->type
.specifier
)) {
653 slang_typeinfo_destruct(&ti
);
656 slang_typeinfo_destruct(&ti
);
658 /* "out" and "inout" formal parameter requires the actual parameter to be l-value */
659 if (!ti
.can_be_referenced
&&
660 (f
->parameters
->variables
[j
/* + haveRetValue*/]->type
.qualifier
== slang_qual_out
||
661 f
->parameters
->variables
[j
/* + haveRetValue*/]->type
.qualifier
== slang_qual_inout
))
667 if (funcs
->outer_scope
!= NULL
)
668 return _slang_locate_function(funcs
->outer_scope
, a_name
, args
,
669 num_args
, space
, atoms
);
676 * Determine the return type of a function.
677 * \param a_name the function name
678 * \param param function parameters (overloading)
679 * \param num_params number of parameters to function
680 * \param space namespace to search
681 * \param exists returns GL_TRUE or GL_FALSE to indicate existance of function
682 * \return GL_TRUE for success, GL_FALSE if failure (bad function name)
685 _slang_typeof_function(slang_atom a_name
, const slang_operation
* params
,
687 const slang_name_space
* space
,
688 slang_type_specifier
* spec
, GLboolean
* exists
,
689 slang_atom_pool
* atoms
)
691 slang_function
*fun
= _slang_locate_function(space
->funcs
, a_name
, params
,
692 num_params
, space
, atoms
);
693 *exists
= fun
!= NULL
;
695 return GL_TRUE
; /* yes, not false */
696 return slang_type_specifier_copy(spec
, &fun
->header
.type
.specifier
);
702 * Determine if a type is a matrix.
703 * \return GL_TRUE if is a matrix, GL_FALSE otherwise.
706 _slang_type_is_matrix(slang_type_specifier_type ty
)
709 case slang_spec_mat2
:
710 case slang_spec_mat3
:
711 case slang_spec_mat4
:
720 * Determine if a type is a vector.
721 * \return GL_TRUE if is a vector, GL_FALSE otherwise.
724 _slang_type_is_vector(slang_type_specifier_type ty
)
727 case slang_spec_vec2
:
728 case slang_spec_vec3
:
729 case slang_spec_vec4
:
730 case slang_spec_ivec2
:
731 case slang_spec_ivec3
:
732 case slang_spec_ivec4
:
733 case slang_spec_bvec2
:
734 case slang_spec_bvec3
:
735 case slang_spec_bvec4
:
744 * Given a vector type, return the type of the vector's elements
746 slang_type_specifier_type
747 _slang_type_base(slang_type_specifier_type ty
)
750 case slang_spec_float
:
751 case slang_spec_vec2
:
752 case slang_spec_vec3
:
753 case slang_spec_vec4
:
754 return slang_spec_float
;
756 case slang_spec_ivec2
:
757 case slang_spec_ivec3
:
758 case slang_spec_ivec4
:
759 return slang_spec_int
;
760 case slang_spec_bool
:
761 case slang_spec_bvec2
:
762 case slang_spec_bvec3
:
763 case slang_spec_bvec4
:
764 return slang_spec_bool
;
765 case slang_spec_mat2
:
766 return slang_spec_vec2
;
767 case slang_spec_mat3
:
768 return slang_spec_vec3
;
769 case slang_spec_mat4
:
770 return slang_spec_vec4
;
772 return slang_spec_void
;
778 * Return the dimensionality of a vector or matrix type.
781 _slang_type_dim(slang_type_specifier_type ty
)
784 case slang_spec_float
:
786 case slang_spec_bool
:
788 case slang_spec_vec2
:
789 case slang_spec_ivec2
:
790 case slang_spec_bvec2
:
791 case slang_spec_mat2
:
793 case slang_spec_vec3
:
794 case slang_spec_ivec3
:
795 case slang_spec_bvec3
:
796 case slang_spec_mat3
:
798 case slang_spec_vec4
:
799 case slang_spec_ivec4
:
800 case slang_spec_bvec4
:
801 case slang_spec_mat4
: