/* * Copyright 2001-2004 David Abrahams. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) */ #include "jam.h" #include "modules.h" #include "hash.h" #include "lists.h" #include "native.h" #include "object.h" #include "parse.h" #include "rules.h" #include "strings.h" #include "variable.h" #include #include static struct hash * module_hash = 0; static module_t root; module_t * bindmodule( OBJECT * name ) { if ( !name ) return &root; { PROFILE_ENTER( BINDMODULE ); module_t * m; int found; if ( !module_hash ) module_hash = hashinit( sizeof( module_t ), "modules" ); m = (module_t *)hash_insert( module_hash, name, &found ); if ( !found ) { m->name = object_copy( name ); m->variables = 0; m->variable_indices = 0; m->num_fixed_variables = 0; m->fixed_variables = 0; m->rules = 0; m->imported_modules = 0; m->class_module = 0; m->native_rules = 0; m->user_module = 0; } PROFILE_EXIT( BINDMODULE ); return m; } } /* * demand_rules() - Get the module's "rules" hash on demand. */ struct hash * demand_rules( module_t * m ) { if ( !m->rules ) m->rules = hashinit( sizeof( RULE ), "rules" ); return m->rules; } /* * delete_module() - wipe out the module's rules and variables. */ static void delete_rule_( void * xrule, void * data ) { rule_free( (RULE *)xrule ); } static void delete_native_rule( void * xrule, void * data ) { native_rule_t * rule = (native_rule_t *)xrule; object_free( rule->name ); if ( rule->procedure ) function_free( rule->procedure ); } static void delete_imported_modules( void * xmodule_name, void * data ) { object_free( *(OBJECT * *)xmodule_name ); } static void free_fixed_variable( void * xvar, void * data ); void delete_module( module_t * m ) { /* Clear out all the rules. */ if ( m->rules ) { hashenumerate( m->rules, delete_rule_, (void *)0 ); hash_free( m->rules ); m->rules = 0; } if ( m->native_rules ) { hashenumerate( m->native_rules, delete_native_rule, (void *)0 ); hash_free( m->native_rules ); m->native_rules = 0; } if ( m->variables ) { var_done( m ); m->variables = 0; } if ( m->fixed_variables ) { int i; for ( i = 0; i < m->num_fixed_variables; ++i ) { list_free( m->fixed_variables[ i ] ); } BJAM_FREE( m->fixed_variables ); m->fixed_variables = 0; } if ( m->variable_indices ) { hashenumerate( m->variable_indices, &free_fixed_variable, (void *)0 ); hash_free( m->variable_indices ); m->variable_indices = 0; } if ( m->imported_modules ) { hashenumerate( m->imported_modules, delete_imported_modules, (void *)0 ); hash_free( m->imported_modules ); m->imported_modules = 0; } } struct module_stats { OBJECT * module_name; struct hashstats rules_stats[ 1 ]; struct hashstats variables_stats[ 1 ]; struct hashstats variable_indices_stats[ 1 ]; struct hashstats imported_modules_stats[ 1 ]; }; static void module_stat( struct hash * hp, OBJECT * module, const char * name ) { if ( hp ) { struct hashstats stats[ 1 ]; string id[ 1 ]; hashstats_init( stats ); string_new( id ); string_append( id, object_str( module ) ); string_push_back( id, ' ' ); string_append( id, name ); hashstats_add( stats, hp ); hashstats_print( stats, id->value ); string_free( id ); } } static void class_module_stat( struct hashstats * stats, OBJECT * module, const char * name ) { if ( stats->item_size ) { string id[ 1 ]; string_new( id ); string_append( id, object_str( module ) ); string_append( id, " object " ); string_append( id, name ); hashstats_print( stats, id->value ); string_free( id ); } } static void stat_module( void * xmodule, void * data ) { module_t *m = (module_t *)xmodule; if ( DEBUG_MEM || DEBUG_PROFILE ) { struct hash * class_info = (struct hash *)data; if ( m->class_module ) { int found; struct module_stats * ms = (struct module_stats *)hash_insert( class_info, m->class_module->name, &found ); if ( !found ) { ms->module_name = m->class_module->name; hashstats_init( ms->rules_stats ); hashstats_init( ms->variables_stats ); hashstats_init( ms->variable_indices_stats ); hashstats_init( ms->imported_modules_stats ); } hashstats_add( ms->rules_stats, m->rules ); hashstats_add( ms->variables_stats, m->variables ); hashstats_add( ms->variable_indices_stats, m->variable_indices ); hashstats_add( ms->imported_modules_stats, m->imported_modules ); } else { module_stat( m->rules, m->name, "rules" ); module_stat( m->variables, m->name, "variables" ); module_stat( m->variable_indices, m->name, "fixed variables" ); module_stat( m->imported_modules, m->name, "imported modules" ); } } delete_module( m ); object_free( m->name ); } static void print_class_stats( void * xstats, void * data ) { struct module_stats * stats = (struct module_stats *)xstats; class_module_stat( stats->rules_stats, stats->module_name, "rules" ); class_module_stat( stats->variables_stats, stats->module_name, "variables" ); class_module_stat( stats->variable_indices_stats, stats->module_name, "fixed variables" ); class_module_stat( stats->imported_modules_stats, stats->module_name, "imported modules" ); } static void delete_module_( void * xmodule, void * data ) { module_t *m = (module_t *)xmodule; delete_module( m ); object_free( m->name ); } void modules_done() { if ( DEBUG_MEM || DEBUG_PROFILE ) { struct hash * class_hash = hashinit( sizeof( struct module_stats ), "object info" ); hashenumerate( module_hash, stat_module, (void *)class_hash ); hashenumerate( class_hash, print_class_stats, (void *)0 ); hash_free( class_hash ); } hashenumerate( module_hash, delete_module_, (void *)0 ); hashdone( module_hash ); module_hash = 0; delete_module( &root ); } module_t * root_module() { return &root; } void import_module( LIST * module_names, module_t * target_module ) { PROFILE_ENTER( IMPORT_MODULE ); struct hash * h; LISTITER iter; LISTITER end; if ( !target_module->imported_modules ) target_module->imported_modules = hashinit( sizeof( char * ), "imported" ); h = target_module->imported_modules; iter = list_begin( module_names ); end = list_end( module_names ); for ( ; iter != end; iter = list_next( iter ) ) { int found; OBJECT * const s = list_item( iter ); OBJECT * * const ss = (OBJECT * *)hash_insert( h, s, &found ); if ( !found ) *ss = object_copy( s ); } PROFILE_EXIT( IMPORT_MODULE ); } static void add_module_name( void * r_, void * result_ ) { OBJECT * * const r = (OBJECT * *)r_; LIST * * const result = (LIST * *)result_; *result = list_push_back( *result, object_copy( *r ) ); } LIST * imported_modules( module_t * module ) { LIST * result = L0; if ( module->imported_modules ) hashenumerate( module->imported_modules, add_module_name, &result ); return result; } FUNCTION * function_bind_variables( FUNCTION *, module_t *, int * counter ); FUNCTION * function_unbind_variables( FUNCTION * ); struct fixed_variable { OBJECT * key; int n; }; struct bind_vars_t { module_t * module; int counter; }; static void free_fixed_variable( void * xvar, void * data ) { object_free( ( (struct fixed_variable *)xvar )->key ); } static void bind_variables_for_rule( void * xrule, void * xdata ) { RULE * rule = (RULE *)xrule; struct bind_vars_t * data = (struct bind_vars_t *)xdata; if ( rule->procedure && rule->module == data->module ) rule->procedure = function_bind_variables( rule->procedure, data->module, &data->counter ); } void module_bind_variables( struct module_t * m ) { if ( m != root_module() && m->rules ) { struct bind_vars_t data; data.module = m; data.counter = m->num_fixed_variables; hashenumerate( m->rules, &bind_variables_for_rule, &data ); module_set_fixed_variables( m, data.counter ); } } int module_add_fixed_var( struct module_t * m, OBJECT * name, int * counter ) { struct fixed_variable * v; int found; assert( !m->class_module ); if ( !m->variable_indices ) m->variable_indices = hashinit( sizeof( struct fixed_variable ), "variable index table" ); v = (struct fixed_variable *)hash_insert( m->variable_indices, name, &found ); if ( !found ) { v->key = object_copy( name ); v->n = (*counter)++; } return v->n; } LIST * var_get_and_clear_raw( module_t * m, OBJECT * name ); static void load_fixed_variable( void * xvar, void * data ) { struct fixed_variable * var = (struct fixed_variable *)xvar; struct module_t * m = (struct module_t *)data; if ( var->n >= m->num_fixed_variables ) m->fixed_variables[ var->n ] = var_get_and_clear_raw( m, var->key ); } void module_set_fixed_variables( struct module_t * m, int n_variables ) { /* Reallocate */ struct hash * variable_indices; LIST * * fixed_variables = BJAM_MALLOC( n_variables * sizeof( LIST * ) ); if ( m->fixed_variables ) { memcpy( fixed_variables, m->fixed_variables, m->num_fixed_variables * sizeof( LIST * ) ); BJAM_FREE( m->fixed_variables ); } m->fixed_variables = fixed_variables; variable_indices = m->class_module ? m->class_module->variable_indices : m->variable_indices; if ( variable_indices ) hashenumerate( variable_indices, &load_fixed_variable, m ); m->num_fixed_variables = n_variables; } int module_get_fixed_var( struct module_t * m_, OBJECT * name ) { struct fixed_variable * v; struct module_t * m = m_; if ( m->class_module ) m = m->class_module; if ( !m->variable_indices ) return -1; v = (struct fixed_variable *)hash_find( m->variable_indices, name ); return v && v->n < m_->num_fixed_variables ? v->n : -1; }