a052362035bec65a11b523de394c1c1f9824a84d
[mesa.git] / src / glsl / glsl_symbol_table.cpp
1 /* -*- c++ -*- */
2 /*
3 * Copyright © 2010 Intel Corporation
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
14 * Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 */
24
25 #include "glsl_symbol_table.h"
26
27 class symbol_table_entry {
28 public:
29 DECLARE_RALLOC_CXX_OPERATORS(symbol_table_entry);
30
31 bool add_interface(const glsl_type *i, enum ir_variable_mode mode)
32 {
33 const glsl_type **dest;
34
35 switch (mode) {
36 case ir_var_uniform:
37 dest = &ibu;
38 break;
39 case ir_var_shader_in:
40 dest = &ibi;
41 break;
42 case ir_var_shader_out:
43 dest = &ibo;
44 break;
45 default:
46 assert(!"Unsupported interface variable mode!");
47 return false;
48 }
49
50 if (*dest != NULL) {
51 return false;
52 } else {
53 *dest = i;
54 return true;
55 }
56 }
57
58 const glsl_type *get_interface(enum ir_variable_mode mode)
59 {
60 switch (mode) {
61 case ir_var_uniform:
62 return ibu;
63 case ir_var_shader_in:
64 return ibi;
65 case ir_var_shader_out:
66 return ibo;
67 default:
68 assert(!"Unsupported interface variable mode!");
69 return NULL;
70 }
71 }
72
73 symbol_table_entry(ir_variable *v) :
74 v(v), f(0), t(0), ibu(0), ibi(0), ibo(0), a(0) {}
75 symbol_table_entry(ir_function *f) :
76 v(0), f(f), t(0), ibu(0), ibi(0), ibo(0), a(0) {}
77 symbol_table_entry(const glsl_type *t) :
78 v(0), f(0), t(t), ibu(0), ibi(0), ibo(0), a(0) {}
79 symbol_table_entry(const glsl_type *t, enum ir_variable_mode mode) :
80 v(0), f(0), t(0), ibu(0), ibi(0), ibo(0), a(0)
81 {
82 assert(t->is_interface());
83 add_interface(t, mode);
84 }
85 symbol_table_entry(const class ast_type_specifier *a):
86 v(0), f(0), t(0), ibu(0), ibi(0), ibo(0), a(a) {}
87
88 ir_variable *v;
89 ir_function *f;
90 const glsl_type *t;
91 const glsl_type *ibu;
92 const glsl_type *ibi;
93 const glsl_type *ibo;
94 const class ast_type_specifier *a;
95 };
96
97 glsl_symbol_table::glsl_symbol_table()
98 {
99 this->separate_function_namespace = false;
100 this->table = _mesa_symbol_table_ctor();
101 this->mem_ctx = ralloc_context(NULL);
102 }
103
104 glsl_symbol_table::~glsl_symbol_table()
105 {
106 _mesa_symbol_table_dtor(table);
107 ralloc_free(mem_ctx);
108 }
109
110 void glsl_symbol_table::push_scope()
111 {
112 _mesa_symbol_table_push_scope(table);
113 }
114
115 void glsl_symbol_table::pop_scope()
116 {
117 _mesa_symbol_table_pop_scope(table);
118 }
119
120 bool glsl_symbol_table::name_declared_this_scope(const char *name)
121 {
122 return _mesa_symbol_table_symbol_scope(table, -1, name) == 0;
123 }
124
125 bool glsl_symbol_table::add_variable(ir_variable *v)
126 {
127 if (this->separate_function_namespace) {
128 /* In 1.10, functions and variables have separate namespaces. */
129 symbol_table_entry *existing = get_entry(v->name);
130 if (name_declared_this_scope(v->name)) {
131 /* If there's already an existing function (not a constructor!) in
132 * the current scope, just update the existing entry to include 'v'.
133 */
134 if (existing->v == NULL && existing->t == NULL) {
135 existing->v = v;
136 return true;
137 }
138 } else {
139 /* If not declared at this scope, add a new entry. But if an existing
140 * entry includes a function, propagate that to this block - otherwise
141 * the new variable declaration would shadow the function.
142 */
143 symbol_table_entry *entry = new(mem_ctx) symbol_table_entry(v);
144 if (existing != NULL)
145 entry->f = existing->f;
146 int added = _mesa_symbol_table_add_symbol(table, -1, v->name, entry);
147 assert(added == 0);
148 (void)added;
149 return true;
150 }
151 return false;
152 }
153
154 /* 1.20+ rules: */
155 symbol_table_entry *entry = new(mem_ctx) symbol_table_entry(v);
156 return _mesa_symbol_table_add_symbol(table, -1, v->name, entry) == 0;
157 }
158
159 bool glsl_symbol_table::add_type(const char *name, const glsl_type *t)
160 {
161 symbol_table_entry *entry = new(mem_ctx) symbol_table_entry(t);
162 return _mesa_symbol_table_add_symbol(table, -1, name, entry) == 0;
163 }
164
165 bool glsl_symbol_table::add_interface(const char *name, const glsl_type *i,
166 enum ir_variable_mode mode)
167 {
168 assert(i->is_interface());
169 symbol_table_entry *entry = get_entry(name);
170 if (entry == NULL) {
171 symbol_table_entry *entry =
172 new(mem_ctx) symbol_table_entry(i, mode);
173 bool add_interface_symbol_result =
174 _mesa_symbol_table_add_symbol(table, -1, name, entry) == 0;
175 assert(add_interface_symbol_result);
176 return add_interface_symbol_result;
177 } else {
178 return entry->add_interface(i, mode);
179 }
180 }
181
182 bool glsl_symbol_table::add_function(ir_function *f)
183 {
184 if (this->separate_function_namespace && name_declared_this_scope(f->name)) {
185 /* In 1.10, functions and variables have separate namespaces. */
186 symbol_table_entry *existing = get_entry(f->name);
187 if ((existing->f == NULL) && (existing->t == NULL)) {
188 existing->f = f;
189 return true;
190 }
191 }
192 symbol_table_entry *entry = new(mem_ctx) symbol_table_entry(f);
193 return _mesa_symbol_table_add_symbol(table, -1, f->name, entry) == 0;
194 }
195
196 void glsl_symbol_table::add_global_function(ir_function *f)
197 {
198 symbol_table_entry *entry = new(mem_ctx) symbol_table_entry(f);
199 int added = _mesa_symbol_table_add_global_symbol(table, -1, f->name, entry);
200 assert(added == 0);
201 (void)added;
202 }
203
204 ir_variable *glsl_symbol_table::get_variable(const char *name)
205 {
206 symbol_table_entry *entry = get_entry(name);
207 return entry != NULL ? entry->v : NULL;
208 }
209
210 const glsl_type *glsl_symbol_table::get_type(const char *name)
211 {
212 symbol_table_entry *entry = get_entry(name);
213 return entry != NULL ? entry->t : NULL;
214 }
215
216 const glsl_type *glsl_symbol_table::get_interface(const char *name,
217 enum ir_variable_mode mode)
218 {
219 symbol_table_entry *entry = get_entry(name);
220 return entry != NULL ? entry->get_interface(mode) : NULL;
221 }
222
223 ir_function *glsl_symbol_table::get_function(const char *name)
224 {
225 symbol_table_entry *entry = get_entry(name);
226 return entry != NULL ? entry->f : NULL;
227 }
228
229 symbol_table_entry *glsl_symbol_table::get_entry(const char *name)
230 {
231 return (symbol_table_entry *)
232 _mesa_symbol_table_find_symbol(table, -1, name);
233 }
234
235 void
236 glsl_symbol_table::disable_variable(const char *name)
237 {
238 /* Ideally we would remove the variable's entry from the symbol table, but
239 * that would be difficult. Fortunately, since this is only used for
240 * built-in variables, it won't be possible for the shader to re-introduce
241 * the variable later, so all we really need to do is to make sure that
242 * further attempts to access it using get_variable() will return NULL.
243 */
244 symbol_table_entry *entry = get_entry(name);
245 if (entry != NULL) {
246 entry->v = NULL;
247 }
248 }