All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.dart.compiler.backend.js.ast.JsScope Maven / Gradle / Ivy

There is a newer version: 2.0.0
Show newest version
// Copyright (c) 2011, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

package com.google.dart.compiler.backend.js.ast;

import com.google.dart.compiler.util.Maps;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.Collections;
import java.util.Map;

/**
 * A scope is a factory for creating and allocating
 * {@link JsName}s. A JavaScript AST is
 * built in terms of abstract name objects without worrying about obfuscation,
 * keyword/identifier blacklisting, and so on.
 * 

*

*

* Scopes are associated with * {@link JsFunction}s, but the two are * not equivalent. Functions have scopes, but a scope does not * necessarily have an associated Function. Examples of this include the * {@link JsRootScope} and synthetic * scopes that might be created by a client. *

*

*

* Scopes can have parents to provide constraints when allocating actual * identifiers for names. Specifically, names in child scopes are chosen such * that they do not conflict with names in their parent scopes. The ultimate * parent is usually the global scope (see * {@link JsProgram#getRootScope()}), * but parentless scopes are useful for managing names that are always accessed * with a qualifier and could therefore never be confused with the global scope * hierarchy. */ public class JsScope { @Nullable private final String description; private Map names = Collections.emptyMap(); private final JsScope parent; protected int tempIndex = 0; private final String scopeId; public JsScope(JsScope parent, @Nullable String description) { this(parent, description, null); } public JsScope(JsScope parent) { this(parent, null); } public JsScope(JsScope parent, @Nullable String description, @Nullable String scopeId) { assert (parent != null); this.scopeId = scopeId; this.description = description; this.parent = parent; } @NotNull public JsScope innerScope(@Nullable String scopeName) { return new JsScope(this, scopeName); } protected JsScope(@Nullable String description) { this.description = description; parent = null; scopeId = null; } /** * Gets a name object associated with the specified identifier in this scope, * creating it if necessary.
* If the JsName does not exist yet, a new JsName is created. The identifier, * short name, and original name of the newly created JsName are equal to * the given identifier. * * @param identifier An identifier that is unique within this scope. */ public JsName declareName(String identifier) { JsName name = findOwnName(identifier); return name != null ? name : doCreateName(identifier); } /** * Creates a new variable with an unique ident in this scope. * The generated JsName is guaranteed to have an identifier that does not clash with any existing variables in the scope. * Future declarations of variables might however clash with the temporary * (unless they use this function). */ @NotNull public JsName declareFreshName(String suggestedName) { String name = suggestedName; int counter = 0; while (hasOwnName(name)) { name = suggestedName + '_' + counter++; } return doCreateName(name); } private String getNextTempName() { // introduced by the compiler return "tmp$" + (scopeId != null ? scopeId + "$" : "") + tempIndex++; } /** * Creates a temporary variable with an unique name in this scope. * The generated temporary is guaranteed to have an identifier (but not short * name) that does not clash with any existing variables in the scope. * Future declarations of variables might however clash with the temporary. */ public JsName declareTemporary() { return declareFreshName(getNextTempName()); } /** * Attempts to find the name object for the specified ident, searching in this * scope, and if not found, in the parent scopes. * * @return null if the identifier has no associated name */ @Nullable public final JsName findName(String ident) { JsName name = findOwnName(ident); if (name == null && parent != null) { return parent.findName(ident); } return name; } protected boolean hasOwnName(@NotNull String name) { return names.containsKey(name); } /** * Returns the parent scope of this scope, or null if this is the * root scope. */ public final JsScope getParent() { return parent; } public JsProgram getProgram() { assert (parent != null) : "Subclasses must override getProgram() if they do not set a parent"; return parent.getProgram(); } @Override public final String toString() { if (parent != null) { return description + "->" + parent; } else { return description; } } protected JsName doCreateName(String ident) { JsName name = new JsName(this, ident); names = Maps.put(names, ident, name); return name; } /** * Attempts to find the name object for the specified ident, searching in this * scope only. * * @return null if the identifier has no associated name */ protected JsName findOwnName(String ident) { return names.get(ident); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy