/* * 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; /** * IDL scoped names * * @author Gerald Brose * */ import java.io.PrintWriter; import java.util.Hashtable; import java.util.Set; import java.util.Stack; import java.util.logging.Level; public class ScopedName extends SimpleTypeSpec implements SwitchTypeSpec { private static Hashtable<String, String> pseudoScopes = new Hashtable<String, String>(); private static Hashtable<String, String> enumMap = new Hashtable<String, String>(); private static Stack<String> recursionStack = new Stack<String>(); /** * Interfaces define a new scope, but since we can't do that * in Java, this kind of scope is called a 'pseudo scope' and * is just prepended to the interface name */ public static void definePseudoScope( String name ) { pseudoScopes.put( name, "" ); } public static boolean isPseudoScope( String name ) { return ( pseudoScopes.containsKey( name ) ); } /** * unPseudo transforms scoped names like * module.Interface1.Interface2.Type_name to * module.Interface1Package.Interface2Package.Type_name */ public static String unPseudoName( String name ) { String n = unPseudo( name ); if( n.endsWith( "PackagePackage" ) || !n.startsWith( "_" ) && n.endsWith( "Package" ) ) { n = n.substring( 0, n.lastIndexOf( "Package" ) ); } return n; } private static String unPseudo( String name ) { if (name.length() > 0 && name.charAt( 0 ) == '.' ) { name = name.substring( 1 ); } String head = name; String tail = null; int lastDot = name.lastIndexOf( '.' ); if( lastDot < 0 ) return name; while( !isPseudoScope( head ) ) { // search for longest tail in scope name which // does not contain a pseudo scope lastDot = head.lastIndexOf( '.' ); if( lastDot < 0 ) return name; head = name.substring( 0, lastDot ); tail = name.substring( lastDot + 1 ); } java.util.StringTokenizer strtok = new java.util.StringTokenizer( head, "." ); String scopes[] = new String[ strtok.countTokens() ]; for( int i = 0; strtok.hasMoreTokens(); scopes[ i++ ] = strtok.nextToken() ) ; StringBuffer newHead = new StringBuffer(); int j = 1; newHead.append( scopes[ 0 ] ); while( !isPseudoScope( newHead.toString() ) ) { if( j == scopes.length ) return ( name ); newHead.append( "." ); newHead.append( scopes[ j++ ] ); } StringBuffer copy = new StringBuffer( newHead.toString() ); // we have to remember this... newHead.append( "Package" ); while( j < scopes.length ) { newHead.append( "." + scopes[ j ] ); copy.append( "." + scopes[ j ] ); if( isPseudoScope( copy.toString() ) ) newHead.append( "Package" ); j++; } if( tail != null ) newHead.append( "." + tail ); return newHead.toString(); } /** * enumerations don't define new scopes in IDL, but their * mapping to Java introduces a new scope by generating * a new class for the enum's type. Thus, enumeration values * have to be additionally scoped in Java. */ public static void enumMap( String n, String m ) { enumMap.put( n, m ); } private static String unEnum( String _name ) { String n = enumMap.get( _name ); if( n != null ) return n; else return _name; } /* end of static part */ /* instance part */ private TypeSpec resolvedSpec = null; private String resolvedName = null; private boolean resolved = false; boolean set = false; public String typeName = null; public ScopedName( int num ) { super( num ); } public Object clone() { ScopedName sn = new ScopedName( new_num() ); sn.resolvedSpec = this.resolvedSpec; sn.resolvedName = this.resolvedName; sn.resolved = this.resolved; sn.typeName = this.typeName; sn.token = this.token; sn.set = this.set; /* superclass instance vars */ sn.pack_name = this.pack_name; sn.name = this.name; sn.is_pseudo = this.is_pseudo; sn.included = this.included; sn.inhibitionFlag = this.inhibitionFlag; return sn; } public void setId( String _id ) { if( parser.logger.isLoggable(Level.FINEST) ) parser.logger.log(Level.FINEST, "ScopedName.setId " + _id); typeName = _id; escapeName(); } /** */ public void escapeName() { if( !isEscaped(typeName) ) { // if the type name is not a simple name, then insert the escape // char after the last dot if( typeName.indexOf( '.' ) > -1 ) { if( lexer.strictJavaEscapeCheck( typeName.substring( typeName.lastIndexOf( '.' ) + 1 ))) { typeName = typeName.substring( 0, typeName.lastIndexOf( '.' ) + 1 ) + "_" + typeName.substring( typeName.lastIndexOf( '.' ) + 1 ); } } else { if( lexer.strictJavaEscapeCheck( typeName )) typeName = "_" + typeName; } } if( parser.logger.isLoggable(Level.FINEST) ) parser.logger.log(Level.FINEST, "ScopedName.escapeName " + typeName); } public void setEnclosingSymbol( IdlSymbol s ) { if( enclosing_symbol != null && enclosing_symbol != s ) throw new RuntimeException( "Compiler Error: trying to reassign container for " + name ); enclosing_symbol = s; } public void parse() { } public boolean resolved() { return resolved; } public boolean basic() { TypeSpec t = resolvedTypeSpec(); return t.basic(); } public boolean is_pseudo() { return NameTable.isDefined( resolvedName(), IDLTypes.PSEUDO_INTERFACE ); } public TypeSpec resolvedTypeSpec() { if( !resolved ) resolvedName = resolvedName(); if( resolvedSpec == null ) parser.fatal_error( "Not a type: " + resolvedName, token ); return resolvedSpec; } public boolean isEscaped(String name) { String last = null; if (name.indexOf('.') > -1) last = name.substring(name.lastIndexOf('.')+1); else last = name; return last.startsWith("_"); } public String resolvedName() { if( !resolved ) resolvedName = resolvedName( pack_name, typeName ); ConstDecl constDecl = ConstDecl.getDeclaration( resolvedName ); if( constDecl != null ) { if( !constDecl.contained() ) { resolvedName += ".value"; } } resolved = true; return resolvedName; } /** * This is the main name resolution algorithm. It resolves a qualified name * s by replacing it by a fully qualified one, (watch out for typedef'd * names!) * * @param name * the name that is to be resolved. This may be a simple name, * a partially qualified name, or even a fully qualifed name. * @param scopeOfOrigin * the scope from within which the resolution starts * @return a fully qualified IDL identifier */ private String resolvedName( String scopeOfOrigin, String name ) { if( parser.logger.isLoggable(Level.FINEST) ) parser.logger.log(Level.FINEST, "Resolve " + scopeOfOrigin + ":" + name); if( name == null ) throw new RuntimeException( "Parser Error: null string in ScopedName (pack_name: " + scopeOfOrigin + ") !" ); String result = null; // a fully qualified name starts with a '.' boolean global = false; if( name.charAt( 0 ) == '.' ) { // strip the dot name = name.substring( 1 ); global = true; } // strip any "[]" but remember them for later String bracketSuffix = ""; if( name.endsWith( "[]" ) ) { result = name.substring( 0, name.indexOf( "[" ) ); bracketSuffix = "[]"; } else result = name; // see if "scope.name" is a defined name. If so, return that // definition. First, try to form a combined name if( !global && NameTable.isDefined( scopeOfOrigin + "." + result )) { String unmappedResult = unMap( scopeOfOrigin + "." + result ); if( parser.logger.isLoggable(Level.FINEST) ) parser.logger.log(Level.FINEST, "resolve, " + scopeOfOrigin + "." + result + " was in name table, returning " + unmappedResult + " suffix: " + bracketSuffix); return unmappedResult + bracketSuffix; } // now, check if name is known by itself (either because it is global // or it is a qualified name) if( (global || result.indexOf('.') > -1 ) && NameTable.isDefined(result) ) { String unmappedResult = unMap( result ); if( parser.logger.isLoggable(Level.FINEST) ) parser.logger.log(Level.FINEST, "resolve, found " + result + " in name table, returning " + unmappedResult + " suffix: " + bracketSuffix); return unmappedResult + bracketSuffix; } // split up all scopes contained in the name java.util.StringTokenizer strtok = new java.util.StringTokenizer( name, "." ); String nameScopes[] = new String[ strtok.countTokens() ]; for( int i = 0; strtok.hasMoreTokens(); i++ ) { nameScopes[ i ] = strtok.nextToken(); } // if there are scopes in the name itself... if( nameScopes.length > 0 ) { // see if the compiler has registerd replacement names for // our scopes String replacedPackageName = parser.pack_replace( nameScopes[ 0 ] ); if( !replacedPackageName.equals( nameScopes[ 0 ] ) ) { // okay, it has, so rebuild the fully scoped name StringBuffer tmpString = new StringBuffer(); tmpString.append( replacedPackageName ); for( int i = 1; i < nameScopes.length; ++i ) { tmpString.append( "." ); tmpString.append( nameScopes[ i ] ); } // check if this is a defined name now result = tmpString.toString(); if( NameTable.isDefined( result ) ) { String unmappedResult = unMap( result ); if( parser.logger.isLoggable(Level.FINEST) ) parser.logger.log(Level.FINEST, "resolve b, " + result + " was in name table, returning " + unmappedResult + " suffix: " + bracketSuffix); return unmappedResult + bracketSuffix; } } } // split up the individual scopes in the scopeOfOrigin java.util.StringTokenizer p_strtok = new java.util.StringTokenizer( scopeOfOrigin, "." ); String packageScopes[] = new String[ p_strtok.countTokens() ]; for( int i = 0; p_strtok.hasMoreTokens(); i++ ) { packageScopes[ i ] = p_strtok.nextToken(); } // If the simple name was not known and we have no scopes at // all, try the global scope. if( nameScopes.length == 0 || packageScopes.length == 0 ) { if( NameTable.isDefined( result ) ) { return unMap( result ) + bracketSuffix; } // else: the name is not found, emit an error message parser.fatal_error( "Undefined name: " + name + " .", token ); } // if package name and the name which is to be resolved begin // with the same scoping qualifiers, strip these from name if( nameScopes[ 0 ].equals( packageScopes[ 0 ] ) ) { StringBuffer tmpString = new StringBuffer(); int minScopesLength = nameScopes.length < packageScopes.length ? nameScopes.length : packageScopes.length; if( minScopesLength > 1 ) { int i; for( i = 1; i < minScopesLength - 1; i++ ) { if( !( nameScopes[ i ].equals( packageScopes[ i ] ) ) ) break; } tmpString.append( nameScopes[ i ] ); for( int k = i + 1; k < nameScopes.length; k++ ) { tmpString.append( "." ); tmpString.append( nameScopes[ k ] ); } name = tmpString.toString(); } } String prefix = ""; int start_index = 0; if( parser.package_prefix != null ) { prefix = parser.package_prefix + "."; java.util.StringTokenizer prefix_strtok = new java.util.StringTokenizer( prefix, "." ); String prefix_scopes[] = new String[ prefix_strtok.countTokens() ]; for( int i = 0; prefix_strtok.hasMoreTokens(); i++ ) prefix_scopes[ i ] = prefix_strtok.nextToken(); while( start_index < prefix_scopes.length && prefix_scopes[ start_index ].equals( packageScopes[ start_index ] ) ) start_index++; } StringBuffer buf = new StringBuffer(); int k = packageScopes.length - start_index; if( k > 0 ) buf.append( packageScopes[ start_index ] + "." ); for( int j = start_index + 1; j < packageScopes.length; j++ ) { buf.append( packageScopes[ j ] ); buf.append( "." ); } buf.append( name ); int sub = start_index + 1; while( !NameTable.isDefined( prefix + buf.toString() ) ) { if( sub > packageScopes.length ) { parser.fatal_error( "Undefined name: " + scopeOfOrigin + "." + name, token ); return "/* unresolved name */"; } buf = new StringBuffer(); k = packageScopes.length - sub++; if( k > 0 ) { buf.append( packageScopes[ start_index ] + "." ); for( int j = start_index + 1; j < k + start_index; j++ ) { buf.append( packageScopes[ j ] ); buf.append( "." ); } } buf.append( name ); } String res = unMap( prefix + buf.toString() ) + bracketSuffix; if( parser.logger.isLoggable(Level.ALL) ) parser.logger.log(Level.ALL, "ScopedName.resolve (at end) returns: " + res); return res; } public TypeSpec typeSpec() { return this; } public void setPackage( String s ) { s = parser.pack_replace( s ); set = true; if( pack_name.length() > 0 ) pack_name = s + "." + pack_name; else pack_name = s; } /** * replace _name by the type name it stands for (through * as many levels of typedef's as necessary) As a side effect, * set resolvedSpec to point to type spec object if the name * resolved was defined as a type name */ private String unMap( String _name ) { if( parser.logger.isLoggable(Level.ALL) ) parser.logger.log(Level.ALL, "ScopedName.unmap: " + _name); TypeSpec y = TypeMap.map( _name ); if( parser.logger.isLoggable(Level.ALL) ) parser.logger.log(Level.ALL, "ScopedName.unmap: " + _name + ", Type.map( " + _name + " ) is : " + y); TypeSpec x = null; while( y != null && !( y instanceof ScopedName ) && !( y instanceof ConstrTypeSpec ) ) { x = y; y = y.typeSpec(); if( x.equals( y ) ) break; // necessary? } if( y == null ) { if( x != null ) { resolvedSpec = x; return x.typeName(); } resolvedSpec = y; return unEnum( _name ); } if( y instanceof ConstrTypeSpec ) { resolvedSpec = y; return y.typeName(); } if( y instanceof ScopedName && x != y ) { return unMap( y.typeName() ); } // If this is an alias of a sequence return the actual type. if (y instanceof AliasTypeSpec && ((AliasTypeSpec)y).originalType().typeSpec() instanceof SequenceType) { resolvedSpec = y; return y.typeName(); } resolvedSpec = y; return _name; } /** * @return the fully qualified and resolved name in an intermediate * format, i.e. with "Package" suffixes but without potential "omg.org" * scopes */ public String typeName() { String n = unPseudo( resolvedName( pack_name, typeName ) ); // !n.startsWith( "_" ) if( n.endsWith( "PackagePackage" ) || !isEscaped(n) && n.endsWith( "Package" ) ) n = n.substring( 0, n.lastIndexOf( "Package" ) ); return n; } public String holderName() { return resolvedTypeSpec().holderName(); } public String printReadExpression( String streamname ) { return resolvedTypeSpec().printReadExpression( streamname ); } public String printWriteStatement( String var_name, String streamname ) { return resolvedTypeSpec().printWriteStatement( var_name, streamname ); } public String printInsertExpression() { return resolvedTypeSpec().printInsertExpression(); } public String printExtractExpression() { return resolvedTypeSpec().printExtractExpression(); } /** * @return a string for an expression of type TypeCode that describes this type */ public String getTypeCodeExpression() { return resolvedTypeSpec().getTypeCodeExpression(); } public String getTypeCodeExpression(Set knownTypes) { return resolvedTypeSpec().getTypeCodeExpression(knownTypes); } public String id() { return resolvedTypeSpec().id(); } public String toString() { String n = typeName(); if( resolvedTypeSpec() != null && ( !n.startsWith( "org.omg" ) && !n.startsWith("java.lang")) ) { n = resolvedTypeSpec().omgPrefix() + n; } return n; } public void print( PrintWriter ps ) { } public String IDLName() { String n = toString(); StringBuffer sb = new StringBuffer(); int from = 0; while( n.substring( from ).indexOf( '.' ) > 0 ) { int to = from + n.substring( from ).indexOf( '.' ); sb.append( n.substring( from, to ) + "::" ); from = to + 1; } sb.append( n.substring( from ) ); return sb.toString(); } public static void addRecursionScope( String typeName ) { recursionStack.push( typeName ); } public static void removeRecursionScope( String typeName ) { String check = recursionStack.pop(); if( typeName != null && ( check == null || !check.equals( typeName ) ) ) { throw new RuntimeException( "RecursionScope Error, expected " + typeName + ", got " + check ); } } public static boolean isRecursionScope( String typeName ) { return ( recursionStack.search( typeName ) != -1 ); } public boolean isSwitchable() { TypeSpec t = resolvedTypeSpec(); return ( ( t instanceof SwitchTypeSpec ) && ( (SwitchTypeSpec)t ).isSwitchable() ); } }