1 /*******************************************************************************
2 * Copyright (c) 2011, 2015 Ericsson, Ecole Polytechnique de Montreal and others
4 * All rights reserved. This program and the accompanying materials are made
5 * available under the terms of the Eclipse Public License v1.0 which
6 * accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
9 * Contributors: Matthew Khouzam - Initial Design and Grammar
10 * Contributors: Simon Marchi - Initial API and implementation
11 *******************************************************************************/
13 package org
.eclipse
.tracecompass
.ctf
.core
.event
.metadata
;
15 import java
.util
.Arrays
;
16 import java
.util
.HashMap
;
20 import org
.eclipse
.jdt
.annotation
.NonNull
;
21 import org
.eclipse
.jdt
.annotation
.Nullable
;
22 import org
.eclipse
.tracecompass
.ctf
.core
.event
.types
.EnumDeclaration
;
23 import org
.eclipse
.tracecompass
.ctf
.core
.event
.types
.IDeclaration
;
24 import org
.eclipse
.tracecompass
.ctf
.core
.event
.types
.StructDeclaration
;
25 import org
.eclipse
.tracecompass
.ctf
.core
.event
.types
.VariantDeclaration
;
26 import org
.eclipse
.tracecompass
.internal
.ctf
.core
.event
.metadata
.ParseException
;
29 * <b><u>DeclarationScope</u></b>
31 * A DeclarationScope keeps track of the various CTF declarations for a given
34 * TODO: The notion of "symbols" and the notion of "scope" are misused in this
35 * parser, which leads to inefficient tree management. It should be cleaned up.
37 * @author Matthew Khouzam
38 * @author Simon Marchi
42 public class DeclarationScope
{
44 // ------------------------------------------------------------------------
46 // ------------------------------------------------------------------------
48 private DeclarationScope fParentScope
;
49 private @NonNull Map
<String
, DeclarationScope
> fChildren
= new HashMap
<>();
51 private final Map
<String
, StructDeclaration
> fStructs
= new HashMap
<>();
52 private final Map
<String
, EnumDeclaration
> fEnums
= new HashMap
<>();
53 private final Map
<String
, VariantDeclaration
> fVariants
= new HashMap
<>();
54 private final Map
<String
, IDeclaration
> fTypes
= new HashMap
<>();
55 private final Map
<String
, IDeclaration
> fIdentifiers
= new HashMap
<>();
58 // ------------------------------------------------------------------------
60 // ------------------------------------------------------------------------
63 * Creates a declaration scope with no parent.
65 public DeclarationScope() {
69 * Creates a declaration scope with the specified parent.
72 * The parent of the newly created scope.
76 public DeclarationScope(DeclarationScope parentScope
, String name
) {
77 fParentScope
= parentScope
;
79 if (parentScope
!= null) {
80 parentScope
.registerChild(name
, this);
84 private void registerChild(String name
, DeclarationScope declarationScope
) {
85 fChildren
.put(name
, declarationScope
);
88 // ------------------------------------------------------------------------
89 // Getters/Setters/Predicates
90 // ------------------------------------------------------------------------
93 * Returns the parent of the current scope.
95 * @return The parent scope.
97 public DeclarationScope
getParentScope() {
102 * Sets the name of the scope
107 public void setName(String name
) {
109 fParentScope
.fChildren
.remove(fName
);
110 fParentScope
.fChildren
.put(name
, this);
115 // ------------------------------------------------------------------------
116 // Registration operations
117 // ------------------------------------------------------------------------
120 * Registers a type declaration.
123 * The name of the type.
125 * The type declaration.
126 * @throws ParseException
127 * if a type with the same name has already been defined.
129 public void registerType(String name
, IDeclaration declaration
)
130 throws ParseException
{
131 /* Check if the type has been defined in the current scope */
132 if (fTypes
.containsKey(name
)) {
133 throw new ParseException("Type has already been defined:" + name
); //$NON-NLS-1$
136 /* Add it to the register. */
137 fTypes
.put(name
, declaration
);
141 * Registers an identifier declaration.
144 * name of the identifier
146 * the identfier's declaration
147 * @throws ParseException
148 * if an identifier with the same name has already been defined.
150 public void registerIdentifier(String name
, IDeclaration declaration
) throws ParseException
{
151 /* Check if the type has been defined in the current scope */
152 if (fIdentifiers
.containsKey(name
)) {
153 throw new ParseException("Identifier has already been defined:" + name
); //$NON-NLS-1$
156 /* Add it to the register. */
157 fIdentifiers
.put(name
, declaration
);
161 * Registers a struct declaration.
164 * The name of the struct.
166 * The declaration of the struct.
167 * @throws ParseException
168 * if a struct with the same name has already been registered.
170 public void registerStruct(String name
, StructDeclaration declaration
)
171 throws ParseException
{
172 /* Check if the struct has been defined in the current scope. */
173 if (fStructs
.containsKey(name
)) {
174 throw new ParseException("Struct has already been defined:" + name
); //$NON-NLS-1$
177 /* Add it to the register. */
178 fStructs
.put(name
, declaration
);
180 /* It also defined a new type, so add it to the type declarations. */
181 String structPrefix
= "struct "; //$NON-NLS-1$
182 registerType(structPrefix
+ name
, declaration
);
186 * Registers an enum declaration.
189 * The name of the enum.
191 * The declaration of the enum.
192 * @throws ParseException
193 * if an enum with the same name has already been registered.
195 public void registerEnum(String name
, EnumDeclaration declaration
)
196 throws ParseException
{
197 /* Check if the enum has been defined in the current scope. */
198 if (lookupEnum(name
) != null) {
199 throw new ParseException("Enum has already been defined:" + name
); //$NON-NLS-1$
202 /* Add it to the register. */
203 fEnums
.put(name
, declaration
);
205 /* It also defined a new type, so add it to the type declarations. */
206 String enumPrefix
= "enum "; //$NON-NLS-1$
207 registerType(enumPrefix
+ name
, declaration
);
211 * Registers a variant declaration.
214 * The name of the variant.
216 * The declaration of the variant.
217 * @throws ParseException
218 * if a variant with the same name has already been registered.
220 public void registerVariant(String name
, VariantDeclaration declaration
)
221 throws ParseException
{
222 /* Check if the variant has been defined in the current scope. */
223 final VariantDeclaration lookupVariant
= lookupVariant(name
);
224 if (declaration
.equals(lookupVariant
)) {
227 if (lookupVariant
!= null) {
228 throw new ParseException("Variant has already been defined:" + name
); //$NON-NLS-1$
231 /* Add it to the register. */
232 fVariants
.put(name
, declaration
);
234 /* It also defined a new type, so add it to the type declarations. */
235 String variantPrefix
= "variant "; //$NON-NLS-1$
236 registerType(variantPrefix
+ name
, declaration
);
239 // ------------------------------------------------------------------------
241 // ------------------------------------------------------------------------
244 * Lookup the children scopes of this scope
247 * the child to lookup
248 * @return the scope or null
250 public @Nullable DeclarationScope
lookupChild(String name
) {
251 return fChildren
.get(name
);
255 * Lookup the children scopes of this scope and this scope's parents
258 * the child to lookup
259 * @return the scope or null
261 public @Nullable DeclarationScope
lookupChildRecursive(String name
) {
262 final DeclarationScope declarationScope
= fChildren
.get(name
);
263 if (declarationScope
== null && hasParent()) {
264 return fParentScope
.lookupChildRecursive(name
);
266 return declarationScope
;
270 * Looks up a type declaration in the current scope.
273 * The name of the type to search for.
274 * @return The type declaration, or null if no type with that name has been
277 public IDeclaration
lookupType(String name
) {
278 return fTypes
.get(name
);
282 * Looks up a type declaration in the current scope and recursively in the
286 * The name of the type to search for.
287 * @return The type declaration, or null if no type with that name has been
290 public IDeclaration
lookupTypeRecursive(String name
) {
291 IDeclaration declaration
= lookupType(name
);
292 if (declaration
!= null) {
294 } else if (hasParent()) {
295 return fParentScope
.lookupTypeRecursive(name
);
302 * Looks up a struct declaration.
305 * The name of the struct to search for.
306 * @return The struct declaration, or null if no struct with that name has
309 public StructDeclaration
lookupStruct(String name
) {
310 return fStructs
.get(name
);
314 * Looks up a struct declaration in the current scope and recursively in the
318 * The name of the struct to search for.
319 * @return The struct declaration, or null if no struct with that name has
322 public StructDeclaration
lookupStructRecursive(String name
) {
323 StructDeclaration declaration
= lookupStruct(name
);
324 if (declaration
!= null) {
326 } else if (hasParent()) {
327 return fParentScope
.lookupStructRecursive(name
);
334 * Looks up an enum declaration.
337 * The name of the enum to search for.
338 * @return The enum declaration, or null if no enum with that name has been
341 public EnumDeclaration
lookupEnum(String name
) {
342 return fEnums
.get(name
);
346 * Looks up an enum declaration in the current scope and recursively in the
350 * The name of the enum to search for.
351 * @return The enum declaration, or null if no enum with that name has been
354 public EnumDeclaration
lookupEnumRecursive(String name
) {
355 EnumDeclaration declaration
= lookupEnum(name
);
356 if (declaration
!= null) {
358 } else if (hasParent()) {
359 return fParentScope
.lookupEnumRecursive(name
);
366 * Looks up a variant declaration.
369 * The name of the variant to search for.
370 * @return The variant declaration, or null if no variant with that name has
373 public VariantDeclaration
lookupVariant(String name
) {
374 return fVariants
.get(name
);
378 * Looks up a variant declaration in the current scope and recursively in
382 * The name of the variant to search for.
383 * @return The variant declaration, or null if no variant with that name has
386 public VariantDeclaration
lookupVariantRecursive(String name
) {
387 VariantDeclaration declaration
= lookupVariant(name
);
388 if (declaration
!= null) {
390 } else if (hasParent()) {
391 return fParentScope
.lookupVariantRecursive(name
);
397 private boolean hasParent() {
398 return fParentScope
!= null;
402 * Lookup query for an identifier in this scope.
405 * the name of the identifier to search for. In the case of int
407 * @return the declaration of the type associated to that identifier
409 public IDeclaration
lookupIdentifier(String identifier
) {
410 return fIdentifiers
.get(identifier
);
414 * Lookup query for an identifier through this scope and its ancestors. An
415 * ancestor scope is a scope in which this scope is nested.
418 * the name of the identifier to search for. In the case of int
420 * @return the declaration of the type associated to that identifier
422 public IDeclaration
lookupIdentifierRecursive(String identifier
) {
423 if (identifier
.contains(".")) { //$NON-NLS-1$
424 String
[] scopes
= identifier
.split("\\."); //$NON-NLS-1$
425 return lookupIdentifierRecursive(scopes
);
427 IDeclaration declaration
= lookupIdentifier(identifier
);
428 if (declaration
!= null) {
430 } else if (hasParent()) {
431 return fParentScope
.lookupIdentifierRecursive(identifier
);
436 private IDeclaration
lookupIdentifierRecursive(String
[] scopes
) {
437 if (scopes
.length
< 1) {
440 // find first element
441 DeclarationScope scope
= this;
442 scope
= lookupRoot(scopes
, scope
);
446 for (int i
= 1; i
< scopes
.length
; i
++) {
447 final String scopeName
= scopes
[i
];
451 IDeclaration declaration
= lookupIdentifierElement(scope
, scopeName
, Arrays
.copyOfRange(scopes
, i
, scopes
.length
));
452 if (declaration
!= null) {
455 scope
= scope
.fChildren
.get(scopeName
);
460 private static DeclarationScope
lookupRoot(String
[] scopes
, DeclarationScope originScope
) {
461 DeclarationScope scope
= originScope
;
462 final String rootElement
= scopes
[0];
463 while (!rootElement
.equals(scope
.fName
)) {
464 if (!scope
.hasParent()) {
465 return scope
.fChildren
.get(rootElement
);
467 scope
= scope
.getParentScope();
472 private IDeclaration
lookupIdentifierElement(DeclarationScope scope
, String scopeName
, String
[] scopes
) {
473 if (scope
.fStructs
.containsKey(scopeName
)) {
474 return lookupStructScope(scope
, scopeName
, scopes
);
475 } else if (scope
.fTypes
.containsKey(scopeName
)) {
476 return scope
.fTypes
.get(scopeName
);
477 } else if (scope
.fEnums
.containsKey(scopeName
)) {
478 return scope
.fEnums
.get(scopeName
);
479 } else if (scope
.fIdentifiers
.containsKey(scopeName
)) {
480 return scope
.fIdentifiers
.get(scopeName
);
485 private IDeclaration
lookupStructScope(DeclarationScope scope
, String scopeName
, String
[] scopes
) {
486 final IDeclaration structDeclaration
= scope
.fStructs
.get(scopeName
);
487 if (scopes
.length
<= 1) {
488 return structDeclaration
;
490 return lookupIdentifierStructElement((StructDeclaration
) structDeclaration
, scopes
[1], Arrays
.copyOfRange(scopes
, 2, scopes
.length
));
493 private IDeclaration
lookupIdentifierStructElement(StructDeclaration structDeclaration
, String string
, String
[] children
) {
494 IDeclaration field
= structDeclaration
.getField(string
);
495 if (children
== null || children
.length
<= 0) {
498 if (field
instanceof StructDeclaration
) {
499 StructDeclaration fieldStructDeclaration
= (StructDeclaration
) field
;
500 return lookupIdentifierStructElement(fieldStructDeclaration
, children
[0], Arrays
.copyOfRange(children
, 1, children
.length
));
506 * Get all the type names of this scope.
508 * @return The type names
510 public Set
<String
> getTypeNames() {
511 return fTypes
.keySet();
515 * Replace a type with a new one.
518 * The name of the type
521 * @throws ParseException
522 * If the type does not exist.
524 public void replaceType(String name
, IDeclaration newType
) throws ParseException
{
525 if (fTypes
.containsKey(name
)) {
526 fTypes
.put(name
, newType
);
528 throw new ParseException("Trace does not contain type:" + name
); //$NON-NLS-1$
538 public void addChild(DeclarationScope scope
) {
539 final DeclarationScope oldParent
= scope
.getParentScope();
540 if (oldParent
!= null) {
541 oldParent
.fChildren
.remove(scope
.fName
);
543 fChildren
.put(scope
.fName
, scope
);
544 scope
.fParentScope
= this;
548 public String
toString() {
549 return "Scope : " + fName
+ " children: " + fChildren
.size() + (fParentScope
== null ?
"" : (" parent " + fParentScope
.fName
)); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$