/* * JacORB - a free Java ORB * * Copyright (C) 1997-2014 Gerald Brose / The JacORB Team. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ package org.jacorb.idl; /** * A table of defined names * * @author Gerald Brose */ import java.util.Enumeration; import java.util.Hashtable; import java.util.Map; import java.util.StringTokenizer; import java.util.logging.Level; public class NameTable { private static final Hashtable/*<String, IDLTypes>*/ names = new Hashtable/*<String, IDLTypes>*/( 10000 ); private static final Map shadows = new Hashtable(); private static final Map ancestors = new Hashtable(); /** key: operation name, value: interface this operation was originally defined in necessary to track legal diamond inheritance of operations */ private static final Map operationSources = new Hashtable(); public static final Map parsed_interfaces = new Hashtable(); public static void init() { names.clear(); operationSources.clear(); shadows.clear(); ancestors.clear(); operationSources.clear(); parsed_interfaces.clear(); names.put( "char", IDLTypes.TYPE ); names.put( "boolean", IDLTypes.TYPE ); names.put( "long", IDLTypes.TYPE ); names.put( "long", IDLTypes.TYPE ); names.put( "short", IDLTypes.TYPE ); names.put( "int", IDLTypes.TYPE ); names.put( "float", IDLTypes.TYPE ); names.put( "double", IDLTypes.TYPE ); names.put( "byte", IDLTypes.TYPE ); names.put( "void", IDLTypes.TYPE ); names.put( "org.omg.CORBA.Any", IDLTypes.TYPE ); names.put( "org.omg.CORBA.Object", IDLTypes.INTERFACE ); } /** * check IDL scoping rules * @throws NameAlreadyDefined or the derived IllegalRedefinition */ private static void checkScopingRules( String name, IDLTypes kind ) throws NameAlreadyDefined { if( parser.logger.isLoggable(Level.ALL) ) { parser.logger.log(Level.ALL, "NameTable.checkScopingRules: " + name + " kind: " + kind.name()); } if( kind == IDLTypes.ARGUMENT ) { return; // no checks in outer scopes ??? } StringTokenizer strtok = new StringTokenizer( name.toUpperCase(), "." ); String scopes[] = new String[ strtok.countTokens() ]; for( int i = 0; strtok.hasMoreTokens(); i++ ) { scopes[ i ] = strtok.nextToken(); } if( parser.logger.isLoggable(Level.ALL) ) { parser.logger.log(Level.ALL, "NameTable.checkScopingRules2: " + name + " kind: " + kind.name()); } if( scopes.length > 1 && scopes[ scopes.length - 2 ].equals( scopes[ scopes.length - 1 ] ) ) { throw new IllegalRedefinition( name ); } } /** * define a name. If it has already been defined in this scope, * an exception is thrown * * @param name The name to be defined * @param kind the type of name, e.g. "type" * @throws NameAlreadyDefined if the name is already defined */ public static void define( String name, IDLTypes kind ) throws NameAlreadyDefined { define(null, name, kind); } /** * define a name. If it has already been defined in this scope, * an exception is thrown * * @param originalName The unreplaced name (i2jPackage) * @param name The name to be defined * @param kind the type of name, e.g. "type" * @throws NameAlreadyDefined if the name is already defined */ public static void define( String originalName, String name, IDLTypes kind ) throws NameAlreadyDefined { if( parser.logger.isLoggable(Level.FINEST) ) { parser.logger.log(Level.FINEST, "putting " + name + " kind " + kind.name() + " hash: " + name.hashCode()); } /* check also for the all uppercase version of this name, (which is also reserved to block identifiers that only differ in case) */ if( names.containsKey( name ) || names.containsKey( name.toUpperCase() ) ) { // if this name has been inherited, it is "shadowed" // in this case, it is redefined if it is not an operation // or interface name. If it has been // explicitly defined in this scope, we have an error if( kind == IDLTypes.MODULE ) { // modules may be "reopened", no further checks or table entries return; } // This check ensures that we can't redefine a name with a // different type. // We also need to ignore any pending forward declarations. else if (parser.strict_identifiers && org.jacorb.idl.parser.strict_names && names.containsKey (name) && ! names.get(name).equals (kind) && parser.get_pending (name) == null) { throw new IllegalRedefinition( name ); } else if( !shadows.containsKey( name ) || kind == IDLTypes.OPERATION || kind == IDLTypes.INTERFACE ) { throw new NameAlreadyDefined( name ); } else { // redefine if( parser.logger.isLoggable(Level.FINEST) ) { parser.logger.log(Level.FINEST, "NameTable.define2: redefining " + name); } shadows.remove( name ); names.remove( name ); if( IDLTypes.isTypeKind(kind) ) { // remove the inherited type definition, a new one will be // added soon under this name! Addition of this line fixes // bug #345 TypeMap.removeDefinition( name ); } } } if( org.jacorb.idl.parser.strict_names ) { if (originalName != null) { checkScopingRules(originalName, kind); } else { checkScopingRules( name, kind ); } } /* block identifiers that only differ in case * * JAC#584: when the name already in uppercase * at first add dummy name then override it * if necessary */ if( org.jacorb.idl.parser.strict_names ) { names.put( name.toUpperCase(), IDLTypes.DUMMY ); } names.put( name, kind ); if( kind == IDLTypes.OPERATION ) { operationSources.put( name, name.substring( 0, name.lastIndexOf( "." ) ) ); } } private static void defineInheritedOperation( String name, String inheritedFrom ) throws NameAlreadyDefined { if( names.containsKey( name ) ) { String source = null; String opName = ( name.indexOf( "." ) < 0 ? name : name.substring( name.lastIndexOf( "." ) + 1 ) ); String presentOpName = name; while( ( source = (String)operationSources.get( presentOpName ) ) != null ) { if( presentOpName.equals( source + "." + opName ) ) { break; } presentOpName = source + "." + opName; } if( parser.logger.isLoggable(Level.FINEST) ) { parser.logger.log(Level.FINEST, "NameTable source of " + name + " is " + presentOpName); } String otherOpName = inheritedFrom + "." + opName; while( ( source = (String)operationSources.get( otherOpName ) ) != null ) { if( otherOpName.equals( source + "." + opName ) ) { break; } otherOpName = source + "." + opName; } if( parser.logger.isLoggable(Level.FINEST) ) { parser.logger.log(Level.FINEST, "NameTable other source of " + name + " is " + otherOpName); } if( otherOpName.equals( presentOpName ) ) { // found an operation that is inherited from // the same ultimate base via different paths // do nothing, as it is already defined for this // interface return; } // illegal multiple inheritance of a the same op name throw new NameAlreadyDefined( name ); } names.put( name, IDLTypes.OPERATION ); operationSources.put( name, inheritedFrom ); } /** * define a shadowed name, i.e. an inherited name * @throws NameAlreadyDefined if a name is already defined */ private static void defineShadows( Hashtable/*<String, IDLTypes>*/ shadowEntries ) throws NameAlreadyDefined { String firstViolation = null; for( Enumeration e = shadowEntries.keys(); e.hasMoreElements(); ) { String name = (String)e.nextElement(); IDLTypes kind = (IDLTypes)shadowEntries.get( name ); if( names.containsKey( name ) ) { firstViolation = name; } else { names.put( name, kind ); if( parser.logger.isLoggable(Level.ALL) ) { parser.logger.log(Level.ALL, "Put shadow " + name); } shadows.put( name, "" ); if( kind == IDLTypes.OPERATION ) { operationSources.put( name, name.substring( 0, name.lastIndexOf( "." ) ) ); } } } if( firstViolation != null ) { throw new NameAlreadyDefined( firstViolation ); } } /** * copy names declared in an ancestor interface to the local scope * @throws NameAlreadyDefined */ public static synchronized void inheritFrom( String name, SymbolList ancestors ) throws NameAlreadyDefined { Hashtable/*<String, IDLTypes>*/ shadowNames = new Hashtable/*<String, IDLTypes>*/(); for( Enumeration e = names.keys(); e.hasMoreElements(); ) { String key = (String)e.nextElement(); String s = null; if( key.indexOf( '.' ) > 0 ) { s = key.substring( 0, key.lastIndexOf( '.' ) ); } else { continue; } for( Enumeration i = ancestors.v.elements(); i.hasMoreElements(); ) { String anc = ( (ScopedName)( i.nextElement() ) ).resolvedName(); if( s.equals( anc ) ) { IDLTypes kind = (IDLTypes)names.get( key ); if( parser.logger.isLoggable(Level.ALL) ) { parser.logger.log(Level.ALL, "NameTable.inheritFrom ancestor " + anc + " : key " + key + " kind " + kind); } String shadowKey = name + key.substring( key.lastIndexOf( '.' ) ); shadowNames.put( shadowKey, kind ); // if the name we inherit is a typedef'd name, we need // to typedef the inherited name as well if( IDLTypes.isTypeKind(kind) ) { if( parser.logger.isLoggable(Level.ALL) ) parser.logger.log(Level.ALL, "- NameTable.inherit type from: " + key); TypeSpec t = TypeMap.map( anc + key.substring( key.lastIndexOf( '.' ) ) ); // t can be null for some cases where we had to put // Java type names (e.g. for sequence s) into the // name table. These need not be typedef'd again here if( t != null ) { TypeMap.typedef( name + key.substring( key.lastIndexOf( '.' ) ), t ); } shadowNames.put( name + key.substring( key.lastIndexOf( '.' ) ), kind ); } else if( kind == IDLTypes.OPERATION ) { if( parser.logger.isLoggable(Level.ALL) ) parser.logger.log(Level.ALL, "- NameTable.inherit operation from: " + key); NameTable.defineInheritedOperation( name + key.substring( key.lastIndexOf( '.' ) ), anc ); } else { if( parser.logger.isLoggable(Level.ALL) ) { parser.logger.log(Level.ALL, "- NameTable.inherit " + kind.name() + " from: " + key); } } if( !isDefined( key ) ) { throw new RuntimeException( "CompilerError!" ); } } } } /* update the hashtable */ try { defineShadows( shadowNames ); } catch( NameAlreadyDefined nad ) { if( parser.logger.isLoggable(Level.ALL) ) parser.logger.log(Level.ALL, "Exception ", nad); } } /** * check whether name is already defined */ public static boolean isDefined( String name ) { return ( names.containsKey( name ) ); } public static boolean isDefined( String name, IDLTypes kind ) { if( !names.containsKey( name ) ) { return false; } return names.get( name ) == kind; } static boolean baseType( String _s ) { return ( _s.equals( "int" ) || _s.equals( "short" ) || _s.equals( "long" ) || _s.equals( "float" ) || _s.equals( "boolean" ) || _s.equals( "double" ) || _s.equals( "byte" ) || _s.equals( "char" ) || _s.equals( "void" ) || _s.equals( "org.omg.CORBA.Object" ) || _s.equals( "org.omg.CORBA.Any" ) || _s.equals( "<anon>" ) ); } }