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 }