1848b8605Smrg/*
2848b8605Smrg * Copyright © 2008 Intel Corporation
3848b8605Smrg *
4848b8605Smrg * Permission is hereby granted, free of charge, to any person obtaining a
5848b8605Smrg * copy of this software and associated documentation files (the "Software"),
6848b8605Smrg * to deal in the Software without restriction, including without limitation
7848b8605Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8848b8605Smrg * and/or sell copies of the Software, and to permit persons to whom the
9848b8605Smrg * Software is furnished to do so, subject to the following conditions:
10848b8605Smrg *
11848b8605Smrg * The above copyright notice and this permission notice (including the next
12848b8605Smrg * paragraph) shall be included in all copies or substantial portions of the
13848b8605Smrg * Software.
14848b8605Smrg *
15848b8605Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16848b8605Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17848b8605Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18848b8605Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19848b8605Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20848b8605Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21848b8605Smrg * DEALINGS IN THE SOFTWARE.
22848b8605Smrg */
23848b8605Smrg
24848b8605Smrg#include "main/imports.h"
25b8e80941Smrg#include "main/errors.h"
26848b8605Smrg#include "symbol_table.h"
27b8e80941Smrg#include "../../util/hash_table.h"
28b8e80941Smrg#include "util/u_string.h"
29848b8605Smrg
30848b8605Smrgstruct symbol {
31b8e80941Smrg   /** Symbol name. */
32b8e80941Smrg   char *name;
33b8e80941Smrg
34848b8605Smrg    /**
35848b8605Smrg     * Link to the next symbol in the table with the same name
36848b8605Smrg     *
37848b8605Smrg     * The linked list of symbols with the same name is ordered by scope
38848b8605Smrg     * from inner-most to outer-most.
39848b8605Smrg     */
40848b8605Smrg    struct symbol *next_with_same_name;
41848b8605Smrg
42848b8605Smrg    /**
43848b8605Smrg     * Link to the next symbol in the table with the same scope
44848b8605Smrg     *
45848b8605Smrg     * The linked list of symbols with the same scope is unordered.  Symbols
46848b8605Smrg     * in this list my have unique names.
47848b8605Smrg     */
48848b8605Smrg    struct symbol *next_with_same_scope;
49848b8605Smrg
50848b8605Smrg    /** Scope depth where this symbol was defined. */
51848b8605Smrg    unsigned depth;
52848b8605Smrg
53848b8605Smrg    /**
54848b8605Smrg     * Arbitrary user supplied data.
55848b8605Smrg     */
56848b8605Smrg    void *data;
57848b8605Smrg};
58848b8605Smrg
59848b8605Smrg
60848b8605Smrg/**
61848b8605Smrg * Element of the scope stack.
62848b8605Smrg */
63848b8605Smrgstruct scope_level {
64848b8605Smrg    /** Link to next (inner) scope level. */
65848b8605Smrg    struct scope_level *next;
66848b8605Smrg
67848b8605Smrg    /** Linked list of symbols with the same scope. */
68848b8605Smrg    struct symbol *symbols;
69848b8605Smrg};
70848b8605Smrg
71848b8605Smrg
72848b8605Smrg/**
73848b8605Smrg *
74848b8605Smrg */
75848b8605Smrgstruct _mesa_symbol_table {
76848b8605Smrg    /** Hash table containing all symbols in the symbol table. */
77848b8605Smrg    struct hash_table *ht;
78848b8605Smrg
79848b8605Smrg    /** Top of scope stack. */
80848b8605Smrg    struct scope_level *current_scope;
81848b8605Smrg
82848b8605Smrg    /** Current scope depth. */
83848b8605Smrg    unsigned depth;
84848b8605Smrg};
85848b8605Smrg
86848b8605Smrgvoid
87848b8605Smrg_mesa_symbol_table_pop_scope(struct _mesa_symbol_table *table)
88848b8605Smrg{
89848b8605Smrg    struct scope_level *const scope = table->current_scope;
90848b8605Smrg    struct symbol *sym = scope->symbols;
91848b8605Smrg
92848b8605Smrg    table->current_scope = scope->next;
93848b8605Smrg    table->depth--;
94848b8605Smrg
95848b8605Smrg    free(scope);
96848b8605Smrg
97848b8605Smrg    while (sym != NULL) {
98848b8605Smrg        struct symbol *const next = sym->next_with_same_scope;
99b8e80941Smrg        struct hash_entry *hte = _mesa_hash_table_search(table->ht,
100b8e80941Smrg                                                         sym->name);
101b8e80941Smrg        if (sym->next_with_same_name) {
102b8e80941Smrg           /* If there is a symbol with this name in an outer scope update
103b8e80941Smrg            * the hash table to point to it.
104b8e80941Smrg            */
105b8e80941Smrg           hte->key = sym->next_with_same_name->name;
106b8e80941Smrg           hte->data = sym->next_with_same_name;
107b8e80941Smrg        } else {
108b8e80941Smrg           _mesa_hash_table_remove(table->ht, hte);
109b8e80941Smrg           free(sym->name);
110b8e80941Smrg        }
111848b8605Smrg
112848b8605Smrg        free(sym);
113848b8605Smrg        sym = next;
114848b8605Smrg    }
115848b8605Smrg}
116848b8605Smrg
117848b8605Smrg
118848b8605Smrgvoid
119848b8605Smrg_mesa_symbol_table_push_scope(struct _mesa_symbol_table *table)
120848b8605Smrg{
121848b8605Smrg    struct scope_level *const scope = calloc(1, sizeof(*scope));
122b8e80941Smrg    if (scope == NULL) {
123b8e80941Smrg       _mesa_error_no_memory(__func__);
124b8e80941Smrg       return;
125b8e80941Smrg    }
126b8e80941Smrg
127848b8605Smrg    scope->next = table->current_scope;
128848b8605Smrg    table->current_scope = scope;
129848b8605Smrg    table->depth++;
130848b8605Smrg}
131848b8605Smrg
132848b8605Smrg
133b8e80941Smrgstatic struct symbol *
134848b8605Smrgfind_symbol(struct _mesa_symbol_table *table, const char *name)
135848b8605Smrg{
136b8e80941Smrg   struct hash_entry *entry = _mesa_hash_table_search(table->ht, name);
137b8e80941Smrg   return entry ? (struct symbol *) entry->data : NULL;
138848b8605Smrg}
139848b8605Smrg
140848b8605Smrg
141848b8605Smrg/**
142848b8605Smrg * Determine the scope "distance" of a symbol from the current scope
143848b8605Smrg *
144848b8605Smrg * \return
145848b8605Smrg * A non-negative number for the number of scopes between the current scope
146848b8605Smrg * and the scope where a symbol was defined.  A value of zero means the current
147848b8605Smrg * scope.  A negative number if the symbol does not exist.
148848b8605Smrg */
149848b8605Smrgint
150848b8605Smrg_mesa_symbol_table_symbol_scope(struct _mesa_symbol_table *table,
151b8e80941Smrg                                const char *name)
152848b8605Smrg{
153b8e80941Smrg   struct symbol *const sym = find_symbol(table, name);
154b8e80941Smrg
155b8e80941Smrg   if (sym) {
156b8e80941Smrg      assert(sym->depth <= table->depth);
157b8e80941Smrg      return sym->depth - table->depth;
158b8e80941Smrg   }
159848b8605Smrg
160b8e80941Smrg   return -1;
161848b8605Smrg}
162848b8605Smrg
163848b8605Smrg
164848b8605Smrgvoid *
165848b8605Smrg_mesa_symbol_table_find_symbol(struct _mesa_symbol_table *table,
166b8e80941Smrg                               const char *name)
167848b8605Smrg{
168b8e80941Smrg   struct symbol *const sym = find_symbol(table, name);
169b8e80941Smrg   if (sym)
170b8e80941Smrg      return sym->data;
171848b8605Smrg
172b8e80941Smrg   return NULL;
173848b8605Smrg}
174848b8605Smrg
175848b8605Smrg
176848b8605Smrgint
177848b8605Smrg_mesa_symbol_table_add_symbol(struct _mesa_symbol_table *table,
178b8e80941Smrg                              const char *name, void *declaration)
179848b8605Smrg{
180b8e80941Smrg   struct symbol *new_sym;
181b8e80941Smrg   struct symbol *sym = find_symbol(table, name);
182848b8605Smrg
183b8e80941Smrg   if (sym && sym->depth == table->depth)
184b8e80941Smrg      return -1;
185848b8605Smrg
186b8e80941Smrg   new_sym = calloc(1, sizeof(*sym));
187b8e80941Smrg   if (new_sym == NULL) {
188b8e80941Smrg      _mesa_error_no_memory(__func__);
189b8e80941Smrg      return -1;
190b8e80941Smrg   }
191848b8605Smrg
192b8e80941Smrg   if (sym) {
193b8e80941Smrg      /* Store link to symbol in outer scope with the same name */
194b8e80941Smrg      new_sym->next_with_same_name = sym;
195b8e80941Smrg      new_sym->name = sym->name;
196b8e80941Smrg   } else {
197b8e80941Smrg      new_sym->name = util_strdup(name);
198b8e80941Smrg      if (new_sym->name == NULL) {
199b8e80941Smrg         free(new_sym);
200b8e80941Smrg         _mesa_error_no_memory(__func__);
201b8e80941Smrg         return -1;
202b8e80941Smrg      }
203b8e80941Smrg   }
204848b8605Smrg
205b8e80941Smrg   new_sym->next_with_same_scope = table->current_scope->symbols;
206b8e80941Smrg   new_sym->data = declaration;
207b8e80941Smrg   new_sym->depth = table->depth;
208848b8605Smrg
209b8e80941Smrg   table->current_scope->symbols = new_sym;
210848b8605Smrg
211b8e80941Smrg   _mesa_hash_table_insert(table->ht, new_sym->name, new_sym);
212848b8605Smrg
213b8e80941Smrg   return 0;
214b8e80941Smrg}
215848b8605Smrg
216b8e80941Smrgint
217b8e80941Smrg_mesa_symbol_table_replace_symbol(struct _mesa_symbol_table *table,
218b8e80941Smrg                                  const char *name,
219b8e80941Smrg                                  void *declaration)
220b8e80941Smrg{
221b8e80941Smrg    struct symbol *sym = find_symbol(table, name);
222b8e80941Smrg
223b8e80941Smrg    /* If the symbol doesn't exist, it cannot be replaced. */
224b8e80941Smrg    if (sym == NULL)
225848b8605Smrg       return -1;
226848b8605Smrg
227848b8605Smrg    sym->data = declaration;
228848b8605Smrg    return 0;
229848b8605Smrg}
230848b8605Smrg
231848b8605Smrgint
232848b8605Smrg_mesa_symbol_table_add_global_symbol(struct _mesa_symbol_table *table,
233b8e80941Smrg                                     const char *name, void *declaration)
234848b8605Smrg{
235b8e80941Smrg   struct scope_level *top_scope;
236b8e80941Smrg   struct symbol *inner_sym = NULL;
237b8e80941Smrg   struct symbol *sym = find_symbol(table, name);
238848b8605Smrg
239b8e80941Smrg   while (sym) {
240b8e80941Smrg      if (sym->depth == 0)
241b8e80941Smrg         return -1;
242848b8605Smrg
243b8e80941Smrg      inner_sym = sym;
244848b8605Smrg
245b8e80941Smrg      /* Get symbol from the outer scope with the same name */
246b8e80941Smrg      sym = sym->next_with_same_name;
247b8e80941Smrg   }
248848b8605Smrg
249b8e80941Smrg   /* Find the top-level scope */
250b8e80941Smrg   for (top_scope = table->current_scope; top_scope->next != NULL;
251b8e80941Smrg        top_scope = top_scope->next) {
252b8e80941Smrg      /* empty */
253b8e80941Smrg   }
254848b8605Smrg
255b8e80941Smrg   sym = calloc(1, sizeof(*sym));
256b8e80941Smrg   if (sym == NULL) {
257b8e80941Smrg      _mesa_error_no_memory(__func__);
258b8e80941Smrg      return -1;
259b8e80941Smrg   }
260848b8605Smrg
261b8e80941Smrg   if (inner_sym) {
262b8e80941Smrg      /* In case we add the global out of order store a link to the global
263b8e80941Smrg       * symbol in global.
264b8e80941Smrg       */
265b8e80941Smrg      inner_sym->next_with_same_name = sym;
266b8e80941Smrg
267b8e80941Smrg      sym->name = inner_sym->name;
268b8e80941Smrg   } else {
269b8e80941Smrg      sym->name = util_strdup(name);
270b8e80941Smrg      if (sym->name == NULL) {
271b8e80941Smrg         free(sym);
272b8e80941Smrg         _mesa_error_no_memory(__func__);
273b8e80941Smrg         return -1;
274b8e80941Smrg      }
275b8e80941Smrg   }
276848b8605Smrg
277b8e80941Smrg   sym->next_with_same_scope = top_scope->symbols;
278b8e80941Smrg   sym->data = declaration;
279848b8605Smrg
280b8e80941Smrg   top_scope->symbols = sym;
281848b8605Smrg
282b8e80941Smrg   _mesa_hash_table_insert(table->ht, sym->name, sym);
283848b8605Smrg
284b8e80941Smrg   return 0;
285848b8605Smrg}
286848b8605Smrg
287848b8605Smrg
288848b8605Smrg
289848b8605Smrgstruct _mesa_symbol_table *
290848b8605Smrg_mesa_symbol_table_ctor(void)
291848b8605Smrg{
292848b8605Smrg    struct _mesa_symbol_table *table = calloc(1, sizeof(*table));
293848b8605Smrg
294848b8605Smrg    if (table != NULL) {
295b8e80941Smrg       table->ht = _mesa_hash_table_create(NULL, _mesa_key_hash_string,
296b8e80941Smrg                                           _mesa_key_string_equal);
297848b8605Smrg
298848b8605Smrg       _mesa_symbol_table_push_scope(table);
299848b8605Smrg    }
300848b8605Smrg
301848b8605Smrg    return table;
302848b8605Smrg}
303848b8605Smrg
304848b8605Smrg
305848b8605Smrgvoid
306848b8605Smrg_mesa_symbol_table_dtor(struct _mesa_symbol_table *table)
307848b8605Smrg{
308848b8605Smrg   while (table->current_scope != NULL) {
309848b8605Smrg      _mesa_symbol_table_pop_scope(table);
310848b8605Smrg   }
311848b8605Smrg
312b8e80941Smrg   _mesa_hash_table_destroy(table->ht, NULL);
313848b8605Smrg   free(table);
314848b8605Smrg}
315