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