1 /*
2  * Copyright 2001-2004 David Abrahams.
3  * Distributed under the Boost Software License, Version 1.0.
4  * (See accompanying file LICENSE_1_0.txt or copy at
5  * http://www.boost.org/LICENSE_1_0.txt)
6  */
7 
8 #include "jam.h"
9 #include "modules.h"
10 
11 #include "hash.h"
12 #include "lists.h"
13 #include "native.h"
14 #include "object.h"
15 #include "parse.h"
16 #include "rules.h"
17 #include "jam_strings.h"
18 #include "variable.h"
19 
20 #include <assert.h>
21 #include <string.h>
22 
23 static struct hash * module_hash = 0;
24 static module_t root;
25 
26 
bindmodule(OBJECT * name)27 module_t * bindmodule( OBJECT * name )
28 {
29     if ( !name )
30         return &root;
31 
32     {
33         PROFILE_ENTER( BINDMODULE );
34 
35         module_t * m;
36         int found;
37 
38         if ( !module_hash )
39             module_hash = hashinit( sizeof( module_t ), "modules" );
40 
41         m = (module_t *)hash_insert( module_hash, name, &found );
42         if ( !found )
43         {
44             m->name = object_copy( name );
45             m->variables = 0;
46             m->variable_indices = 0;
47             m->num_fixed_variables = 0;
48             m->fixed_variables = 0;
49             m->rules = 0;
50             m->imported_modules = 0;
51             m->class_module = 0;
52             m->native_rules = 0;
53             m->user_module = 0;
54         }
55 
56         PROFILE_EXIT( BINDMODULE );
57 
58         return m;
59     }
60 }
61 
62 
63 /*
64  * demand_rules() - Get the module's "rules" hash on demand.
65  */
demand_rules(module_t * m)66 struct hash * demand_rules( module_t * m )
67 {
68     if ( !m->rules )
69         m->rules = hashinit( sizeof( RULE ), "rules" );
70     return m->rules;
71 }
72 
73 
74 /*
75  * delete_module() - wipe out the module's rules and variables.
76  */
77 
delete_rule_(void * xrule,void * data)78 static void delete_rule_( void * xrule, void * data )
79 {
80     rule_free( (RULE *)xrule );
81 }
82 
83 
delete_native_rule(void * xrule,void * data)84 static void delete_native_rule( void * xrule, void * data )
85 {
86     native_rule_t * rule = (native_rule_t *)xrule;
87     object_free( rule->name );
88     if ( rule->procedure )
89         function_free( rule->procedure );
90 }
91 
92 
delete_imported_modules(void * xmodule_name,void * data)93 static void delete_imported_modules( void * xmodule_name, void * data )
94 {
95     object_free( *(OBJECT * *)xmodule_name );
96 }
97 
98 
99 static void free_fixed_variable( void * xvar, void * data );
100 
delete_module(module_t * m)101 void delete_module( module_t * m )
102 {
103     /* Clear out all the rules. */
104     if ( m->rules )
105     {
106         hashenumerate( m->rules, delete_rule_, (void *)0 );
107         hash_free( m->rules );
108         m->rules = 0;
109     }
110 
111     if ( m->native_rules )
112     {
113         hashenumerate( m->native_rules, delete_native_rule, (void *)0 );
114         hash_free( m->native_rules );
115         m->native_rules = 0;
116     }
117 
118     if ( m->variables )
119     {
120         var_done( m );
121         m->variables = 0;
122     }
123 
124     if ( m->fixed_variables )
125     {
126         int i;
127         for ( i = 0; i < m->num_fixed_variables; ++i )
128         {
129             list_free( m->fixed_variables[ i ] );
130         }
131         BJAM_FREE( m->fixed_variables );
132         m->fixed_variables = 0;
133     }
134 
135     if ( m->variable_indices )
136     {
137         hashenumerate( m->variable_indices, &free_fixed_variable, (void *)0 );
138         hash_free( m->variable_indices );
139         m->variable_indices = 0;
140     }
141 
142     if ( m->imported_modules )
143     {
144         hashenumerate( m->imported_modules, delete_imported_modules, (void *)0 );
145         hash_free( m->imported_modules );
146         m->imported_modules = 0;
147     }
148 }
149 
150 
151 struct module_stats
152 {
153     OBJECT * module_name;
154     struct hashstats rules_stats[ 1 ];
155     struct hashstats variables_stats[ 1 ];
156     struct hashstats variable_indices_stats[ 1 ];
157     struct hashstats imported_modules_stats[ 1 ];
158 };
159 
160 
module_stat(struct hash * hp,OBJECT * module,const char * name)161 static void module_stat( struct hash * hp, OBJECT * module, const char * name )
162 {
163     if ( hp )
164     {
165         struct hashstats stats[ 1 ];
166         string id[ 1 ];
167         hashstats_init( stats );
168         string_new( id );
169         string_append( id, object_str( module ) );
170         string_push_back( id, ' ' );
171         string_append( id, name );
172 
173         hashstats_add( stats, hp );
174         hashstats_print( stats, id->value );
175 
176         string_free( id );
177     }
178 }
179 
180 
class_module_stat(struct hashstats * stats,OBJECT * module,const char * name)181 static void class_module_stat( struct hashstats * stats, OBJECT * module, const char * name )
182 {
183     if ( stats->item_size )
184     {
185         string id[ 1 ];
186         string_new( id );
187         string_append( id, object_str( module ) );
188         string_append( id, " object " );
189         string_append( id, name );
190 
191         hashstats_print( stats, id->value );
192 
193         string_free( id );
194     }
195 }
196 
197 
stat_module(void * xmodule,void * data)198 static void stat_module( void * xmodule, void * data )
199 {
200     module_t *m = (module_t *)xmodule;
201 
202     if ( DEBUG_MEM || DEBUG_PROFILE )
203     {
204         struct hash * class_info = (struct hash *)data;
205         if ( m->class_module )
206         {
207             int found;
208             struct module_stats * ms = (struct module_stats *)hash_insert( class_info, m->class_module->name, &found );
209             if ( !found )
210             {
211                 ms->module_name = m->class_module->name;
212                 hashstats_init( ms->rules_stats );
213                 hashstats_init( ms->variables_stats );
214                 hashstats_init( ms->variable_indices_stats );
215                 hashstats_init( ms->imported_modules_stats );
216             }
217 
218             hashstats_add( ms->rules_stats, m->rules );
219             hashstats_add( ms->variables_stats, m->variables );
220             hashstats_add( ms->variable_indices_stats, m->variable_indices );
221             hashstats_add( ms->imported_modules_stats, m->imported_modules );
222         }
223         else
224         {
225             module_stat( m->rules, m->name, "rules" );
226             module_stat( m->variables, m->name, "variables" );
227             module_stat( m->variable_indices, m->name, "fixed variables" );
228             module_stat( m->imported_modules, m->name, "imported modules" );
229         }
230     }
231 
232     delete_module( m );
233     object_free( m->name );
234 }
235 
print_class_stats(void * xstats,void * data)236 static void print_class_stats( void * xstats, void * data )
237 {
238     struct module_stats * stats = (struct module_stats *)xstats;
239     class_module_stat( stats->rules_stats, stats->module_name, "rules" );
240     class_module_stat( stats->variables_stats, stats->module_name, "variables" );
241     class_module_stat( stats->variable_indices_stats, stats->module_name, "fixed variables" );
242     class_module_stat( stats->imported_modules_stats, stats->module_name, "imported modules" );
243 }
244 
245 
delete_module_(void * xmodule,void * data)246 static void delete_module_( void * xmodule, void * data )
247 {
248     module_t *m = (module_t *)xmodule;
249 
250     delete_module( m );
251     object_free( m->name );
252 }
253 
254 
modules_done()255 void modules_done()
256 {
257     if ( DEBUG_MEM || DEBUG_PROFILE )
258     {
259         struct hash * class_hash = hashinit( sizeof( struct module_stats ), "object info" );
260         hashenumerate( module_hash, stat_module, (void *)class_hash );
261         hashenumerate( class_hash, print_class_stats, (void *)0 );
262         hash_free( class_hash );
263     }
264     hashenumerate( module_hash, delete_module_, (void *)0 );
265     hashdone( module_hash );
266     module_hash = 0;
267     delete_module( &root );
268 }
269 
root_module()270 module_t * root_module()
271 {
272     return &root;
273 }
274 
275 
import_module(LIST * module_names,module_t * target_module)276 void import_module( LIST * module_names, module_t * target_module )
277 {
278     PROFILE_ENTER( IMPORT_MODULE );
279 
280     struct hash * h;
281     LISTITER iter;
282     LISTITER end;
283 
284     if ( !target_module->imported_modules )
285         target_module->imported_modules = hashinit( sizeof( char * ), "imported"
286             );
287     h = target_module->imported_modules;
288 
289     iter = list_begin( module_names );
290     end = list_end( module_names );
291     for ( ; iter != end; iter = list_next( iter ) )
292     {
293         int found;
294         OBJECT * const s = list_item( iter );
295         OBJECT * * const ss = (OBJECT * *)hash_insert( h, s, &found );
296         if ( !found )
297             *ss = object_copy( s );
298     }
299 
300     PROFILE_EXIT( IMPORT_MODULE );
301 }
302 
303 
add_module_name(void * r_,void * result_)304 static void add_module_name( void * r_, void * result_ )
305 {
306     OBJECT * * const r = (OBJECT * *)r_;
307     LIST * * const result = (LIST * *)result_;
308     *result = list_push_back( *result, object_copy( *r ) );
309 }
310 
311 
imported_modules(module_t * module)312 LIST * imported_modules( module_t * module )
313 {
314     LIST * result = L0;
315     if ( module->imported_modules )
316         hashenumerate( module->imported_modules, add_module_name, &result );
317     return result;
318 }
319 
320 
321 FUNCTION * function_bind_variables( FUNCTION *, module_t *, int * counter );
322 FUNCTION * function_unbind_variables( FUNCTION * );
323 
324 struct fixed_variable
325 {
326     OBJECT * key;
327     int n;
328 };
329 
330 struct bind_vars_t
331 {
332     module_t * module;
333     int counter;
334 };
335 
336 
free_fixed_variable(void * xvar,void * data)337 static void free_fixed_variable( void * xvar, void * data )
338 {
339     object_free( ( (struct fixed_variable *)xvar )->key );
340 }
341 
342 
bind_variables_for_rule(void * xrule,void * xdata)343 static void bind_variables_for_rule( void * xrule, void * xdata )
344 {
345     RULE * rule = (RULE *)xrule;
346     struct bind_vars_t * data = (struct bind_vars_t *)xdata;
347     if ( rule->procedure && rule->module == data->module )
348         rule->procedure = function_bind_variables( rule->procedure,
349             data->module, &data->counter );
350 }
351 
352 
module_bind_variables(struct module_t * m)353 void module_bind_variables( struct module_t * m )
354 {
355     if ( m != root_module() && m->rules )
356     {
357         struct bind_vars_t data;
358         data.module = m;
359         data.counter = m->num_fixed_variables;
360         hashenumerate( m->rules, &bind_variables_for_rule, &data );
361         module_set_fixed_variables( m, data.counter );
362     }
363 }
364 
365 
module_add_fixed_var(struct module_t * m,OBJECT * name,int * counter)366 int module_add_fixed_var( struct module_t * m, OBJECT * name, int * counter )
367 {
368     struct fixed_variable * v;
369     int found;
370 
371     assert( !m->class_module );
372 
373     if ( !m->variable_indices )
374         m->variable_indices = hashinit( sizeof( struct fixed_variable ), "variable index table" );
375 
376     v = (struct fixed_variable *)hash_insert( m->variable_indices, name, &found );
377     if ( !found )
378     {
379         v->key = object_copy( name );
380         v->n = (*counter)++;
381     }
382 
383     return v->n;
384 }
385 
386 
387 LIST * var_get_and_clear_raw( module_t * m, OBJECT * name );
388 
load_fixed_variable(void * xvar,void * data)389 static void load_fixed_variable( void * xvar, void * data )
390 {
391     struct fixed_variable * var = (struct fixed_variable *)xvar;
392     struct module_t * m = (struct module_t *)data;
393     if ( var->n >= m->num_fixed_variables )
394         m->fixed_variables[ var->n ] = var_get_and_clear_raw( m, var->key );
395 }
396 
397 
module_set_fixed_variables(struct module_t * m,int n_variables)398 void module_set_fixed_variables( struct module_t * m, int n_variables )
399 {
400     /* Reallocate */
401     struct hash * variable_indices;
402     LIST * * fixed_variables = (LIST * *)BJAM_MALLOC( n_variables * sizeof( LIST * ) );
403     if ( m->fixed_variables )
404     {
405         memcpy( fixed_variables, m->fixed_variables, m->num_fixed_variables * sizeof( LIST * ) );
406         BJAM_FREE( m->fixed_variables );
407     }
408     m->fixed_variables = fixed_variables;
409     variable_indices = m->class_module
410         ? m->class_module->variable_indices
411         : m->variable_indices;
412     if ( variable_indices )
413         hashenumerate( variable_indices, &load_fixed_variable, m );
414     m->num_fixed_variables = n_variables;
415 }
416 
417 
module_get_fixed_var(struct module_t * m_,OBJECT * name)418 int module_get_fixed_var( struct module_t * m_, OBJECT * name )
419 {
420     struct fixed_variable * v;
421     struct module_t * m = m_;
422 
423     if ( m->class_module )
424         m = m->class_module;
425 
426     if ( !m->variable_indices )
427         return -1;
428 
429     v = (struct fixed_variable *)hash_find( m->variable_indices, name );
430     return v && v->n < m_->num_fixed_variables ? v->n : -1;
431 }
432