1 /** 2 * Redistribution and use in source and binary forms, with or without 3 * modification, are permitted provided that the following conditions are 4 * met : 5 * 6 * . Redistributions of source code must retain the above copyright 7 * notice, this list of conditions and the following disclaimer. 8 * 9 * . Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * . The name of the author may not be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 20 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 24 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 25 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 package cppast; 30 31 import java.util.Hashtable; 32 33 /** 34 * Represents a scope. 35 * 36 * @author Mathieu Champlon 37 */ 38 public final class Scope 39 { 40 private final String name; 41 private final Hashtable<String, Scope> scopes = new Hashtable<String, Scope>(); 42 private Scope parent; 43 44 /** 45 * Creates a scope object with a given name. 46 * 47 * @param name the name of the scope 48 * @param parent the parent of the scope 49 */ 50 private Scope( final String name, final Scope parent ) 51 { 52 if( name == null ) 53 throw new IllegalArgumentException( "scope name is null" ); 54 if( parent == null ) 55 throw new IllegalArgumentException( "scope parent is null" ); 56 if( name.contains( "::" ) ) 57 throw new IllegalArgumentException( "scope name '" + name + "' contains '::'" ); 58 this.name = name; 59 this.parent = parent; 60 } 61 62 /** 63 * Creates an unnamed empty scope. 64 */ 65 public Scope() 66 { 67 this.name = ""; 68 this.parent = null; 69 } 70 71 /** 72 * Create a sub-scope to the scope. 73 * 74 * @param name the name of the sub-scope 75 * @return the new sub-scope 76 */ 77 public Scope createScope( final String name ) 78 { 79 final int index = name.indexOf( "::" ); 80 if( index != -1 ) 81 { 82 Scope scope = getScope( name.substring( 0, index ) ); 83 if( scope == null ) 84 { 85 scope = new Scope( name.substring( 0, index ), this ); 86 scopes.put( name, scope ); 87 } 88 return scope.createScope( name.substring( index + 2 ) ); 89 } 90 final Scope scope = new Scope( name, this ); 91 scopes.put( name, scope ); 92 return scope; 93 } 94 95 /** 96 * Extend the scope with another one. 97 * <p> 98 * Types from the given scope are added to the extended scope. 99 * 100 * @param scope the scope to merge into the current scope 101 */ 102 public void extend( final Scope scope ) 103 { 104 if( scope != null ) 105 scopes.putAll( scope.scopes ); 106 } 107 108 /** 109 * Retrieve the scope of a given name. 110 * 111 * @param name the name of the scope 112 * @return the matching scope 113 */ 114 public Scope getScope( final String name ) 115 { 116 final int index = name.indexOf( "::" ); 117 if( index != -1 ) 118 { 119 final Scope scope = getScope( name.substring( 0, index ) ); 120 if( scope != null ) 121 return scope.getScope( name.substring( index + 2 ) ); 122 return null; 123 } 124 if( scopes.containsKey( name ) ) 125 return scopes.get( name ); 126 if( parent != null ) 127 return parent.getScope( name ); 128 return null; 129 } 130 131 /** 132 * Close the scope. 133 * 134 * @return the parent scope 135 */ 136 public Scope close() 137 { 138 if( parent == null ) 139 return this; 140 return parent; 141 } 142 143 /** 144 * Resolve a name into the scope. 145 * 146 * @param name the name 147 * @return the fully scoped name 148 */ 149 public String resolve( final String name ) 150 { 151 final int index = name.lastIndexOf( "::" ); 152 if( index == -1 ) 153 return toString() + name; 154 final Scope scope = getScope( name.substring( 0, index ) ); 155 if( scope == null ) 156 return toString() + name; 157 return scope.resolve( name.substring( index + 2 ) ); 158 } 159 160 /** 161 * {@inheritDoc} 162 */ 163 public String toString() 164 { 165 if( parent == null ) 166 return ""; 167 return parent.toString() + name + "::"; 168 } 169 }