module Sbuilder class SymbolTable # ------------------------------------------------------------------ # Attributes # @attr [Hash] types of :name -> :desc mappingssymbol names to add # @option types [String] :name of symbol to define # @option types [String] :desc description of symbol to define attr_reader :types alias_method :metatypes, :types # @attr [Hash] table of symbols # @option table [String] key is type name # @option table [Hash] spec-namesvalue spec names of 'type' # @option spec-names [String] key spec name of symbol entry # @option spec-names [String] value app name of symbol entry attr_reader :table # ------------------------------------------------------------------ # Logger PROGNAME = nil # progname for logger default class name include Sbuilder::Utils::MyLogger # mix logger # ------------------------------------------------------------------ # @!group Construct & configure def initialize( options = {} ) @logger = getLogger( PROGNAME, options ) @logger.info( "#{__method__} initialized" ) @types = {} @table = {} end # @!endgroup # ------------------------------------------------------------------ # @!group Build symbol table # Add type names to symbol table so that we can issue a warning if # unknon symbol types are entered # # @param [Hash] symbol name to add # @option symbol [String] :name of symbol to define # @option symbol [String] :desc description of symbol to define # # def defineMetaType( symbol ) @logger.info "#{__method__}: #{symbol}" # symbol[:name ] = symbol[:name ] symbol[:prefix] = symbol[:prefix] || generatePrefix() types[symbol[:name]] = symbol # Initialize empty hash to store appName->specName mappings table[symbol[:name]] = table[symbol[:name]] || {} end # Create unique prefix entry. # # Implementation iteraterates '@types' in symbol table, for # entries with :prefix symbol starting with fixed characted 'x'. # # Take max of # # private def generatePrefix current_prefix=0 @types.each do |k,v| if !v[:prefix].nil? && v[:prefix].start_with?( 'x' ) then result,tmp_prefix = /x(\d+)/.match( v[:prefix]).to_a.flatten current_prefix = tmp_prefix.to_i > current_prefix ? tmp_prefix.to_i : current_prefix end end "x#{current_prefix+1}" end # Add 'spec' symbol of 'type' for 'app'. Issue a warning if 'type' # is undefined, or if 'type', 'spec' is redefined. # # @param [String] metatype of previsously defined metatype # # # @param [String] spec name in specifcation domain # # @param [String] app name in application domain where 'spec' name # is associated def addSymbol( metatype, app, spec ) # ------------------------------------------------------------------ # Unknown metatype if types[metatype].nil? then typeDesc = "Unknown metatype '#{metatype}' encountered when mapping #{app} -> #{spec}" msg= <<-EOS #{typeDesc} use #{self.class.name}#defineMetaType(symbol) -method to define metatypes before adding symbols using #{self.class.name}#addSymbol -method. EOS # warn msg @logger.error "#{__method__}: #{msg}" raise SymbolTableException.new msg end # Init hash to map appName -> specName table[metatype] = table[metatype] || {} # ------------------------------------------------------------------ # Check for alias definition for specName # turn table outsize in: specName -> [metatype,appName] specName2metatype_appName = table.inject( {} ) {|memo,(m,ah)| ah.each { |a,s| memo[s] = [m,a] } memo } # ------------------------------------------------------------------ # error on aliased definition # if specName2metatype_appName[spec] && specName2metatype_appName[spec] != [metatype,app] # msg = specNameAliasedMessage( metatype, app, *specName2metatype_appName[spec], spec ) # @logger.error "#{__method__} #{msg}" # raise SymbolTableException.new msg # end # ------------------------------------------------------------------ # Warn on duplicate definition if table[metatype][app] && table[metatype][app] != spec msg = specNameRerefined( metatype, app, table[metatype][app], spec ) @logger.error "#{__method__}: #{msg}" raise SymbolTableException.new msg end # ------------------------------------------------------------------ # Warn on duplicate definition if ! table[metatype][app].nil? msg = "Duplicate symbol definition #{metatype}:#{spec}" warn msg @logger.warn "#{__method__}: #{msg}" end # ------------------------------------------------------------------ # Here normal add @logger.info "#{__method__} added metatype '#{metatype}', name in spec-domain: '#{spec}', name in app domain: '#{app}'" table[metatype][app] = spec end # @!endgroup # ------------------------------------------------------------------ # @!group Use symbol table # @return [String] definition of metatype def getMetaTypeDescription( metatype ) getMetaTypeDefinition( metatype )[:desc] end # @return [String] definition of metatype, nil if not found def getMetaTypeDefinition( metatype ) ret = types[metatype] if ret.nil? msg= <<-EOS Metatype definition for metatype '#{metatype}' not found. Known metatypes are: #{types.keys.join( ', ')} EOS # warn msg @logger.error "#{__method__}: #{msg}" raise SymbolTableException.new msg end ret end # # @return [Hash] application-names for 'type' # def []( type ) # table[type] # end # Return 'spec' -name identified by 'app'/'type' combination # # @param [String] app name in application domain where 'spec' name # is associated # # @param [String] type of previsously defined type # def lookupSymbol( appName, metatype ) # Find specname (raise exceptio if metatype not found ) specName = getMetaTypeHash( metatype, appName )[appName] # Valid spec-name found if specName.nil? then msg=<<-EOS Unknown name '#{appName}' in metatype '#{metatype}' Valid app-names in meta-type '#{metatype}' are: #{table[metatype].keys.join(', ')} EOS @logger.error msg raise SymbolTableException.new msg end specName end # @!endgroup # @return [Hash] symbol map for 'metatype' private def getMetaTypeHash( metatype, appName ) # Valid 'metatype' if table[metatype].nil? then msg=<<-EOS Unknown meta-type '#{metatype}', when looking up for specification name for appName #{appName} Valid meta-types are: #{table.keys.join(', ')} EOS @logger.error msg raise SymbolTableException.new msg end # return hash for metape table[metatype] end # # @return [Hash] unknown metatype hash # private def unknownMetatype( metatype ) # { # :name => metatype, # :desc => "Unknown metatype '#{metatype}'", # } # end # @return [String] error message for aliasins specName private def specNameAliasedMessage( metatype1, appName1, metatype2, appName2, specName ) <<-EOS Name '#{specName}' in specification code domain is defined twice Application name '#{appName1}' in metatype '#{metatype1}' is defined as '#{specName}' Application name '#{appName2}' in metatype '#{metatype2}' is defined as '#{specName}' EOS end # @return [String] error message for redfining metatype/appName private def specNameRerefined( metatype, appName, specName1, specName2 ) <<-EOS Application name '#{appName}' in metatype '#{metatype}' refined specName1 = #{specName1} specName2 = #{specName1} EOS end end # class SymboTable end # module