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

com.google.javascript.rhino.jstype.JSTypeResolver Maven / Gradle / Ivy

Go to download

Closure Compiler is a JavaScript optimizing compiler. It parses your JavaScript, analyzes it, removes dead code and rewrites and minimizes what's left. It also checks syntax, variable references, and types, and warns about common JavaScript pitfalls. It is used in many of Google's JavaScript apps, including Gmail, Google Web Search, Google Maps, and Google Docs.

There is a newer version: v20240317
Show newest version
/*
 *
 * ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1/GPL 2.0
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is Rhino code, released
 * May 6, 1999.
 *
 * The Initial Developer of the Original Code is
 * Netscape Communications Corporation.
 * Portions created by the Initial Developer are Copyright (C) 1997-1999
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *   Bob Jervis
 *   Google Inc.
 *
 * Alternatively, the contents of this file may be used under the terms of
 * the GNU General Public License Version 2 or later (the "GPL"), in which
 * case the provisions of the GPL are applicable instead of those above. If
 * you wish to allow use of your version of this file only under the terms of
 * the GPL and not to allow others to use your version of this file under the
 * MPL, indicate your decision by deleting the provisions above and replacing
 * them with the notice and other provisions required by the GPL. If you do
 * not delete the provisions above, a recipient may use your version of this
 * file under either the MPL or the GPL.
 *
 * ***** END LICENSE BLOCK ***** */

package com.google.javascript.rhino.jstype;

import static com.google.common.base.Preconditions.checkState;
import static com.google.javascript.jscomp.base.JSCompObjects.identical;

import com.google.errorprone.annotations.MustBeClosed;
import java.util.ArrayDeque;

/**
 * A state machine for resolving all {@link JSType} instances.
 *
 * 

This object shares the lifecycle of a registry. Consider it as a narrow interface into the * registry for the purpose of resolving types. * *

Every time a new type is constructed it is (by cooperation of the {@link JSType} subclasses} * added to this resolver. Depending on the state of the resolver at the time of addition, the type * will either be eagerly resolved, or stored for later resolution. */ public final class JSTypeResolver { /** * A signal to resolve all types known to and close the owning resolver. * *

This is intended to be used in a try-with-resources statement. This approach was selected * over accepting a callback because it supports some level of compile-time enforcement while * allowing that enforcement to be suppressed in tests. */ public final class Closer implements AutoCloseable { private boolean hasRun = false; @Override public void close() { checkState(!this.hasRun); this.hasRun = true; JSTypeResolver.this.resolveAll(); } } private enum State { CLOSED, OPEN, CLOSING; } static JSTypeResolver create(JSTypeRegistry registry) { if (registry.getResolver() != null) { return registry.getResolver(); } return new JSTypeResolver(registry); } private final JSTypeRegistry registry; /** * The sequence of instantiated types. * *

This allows verification that every new type is captured by this resolver. In general this * stack should never be more than a handful of types. */ private final ArrayDeque captureStack = new ArrayDeque<>(); /** The sequence of types to resolve when the resolver is closed. */ private ArrayDeque resolutionQueue = new ArrayDeque<>(); private State state = State.CLOSED; private JSTypeResolver(JSTypeRegistry registry) { this.registry = registry; } /** * Record that a new type has been instantiated. * *

This should only be called in the {@code JSType} constructor, with the intention of * capturing all new types. */ void addUnresolved(JSType captured) { /** * This method exists to make it easier to debug the source of unresolved types in the future. * *

In theory we should be able to capture all types using `resolveIfClosed`, but this way we * get some guarantees against misuse. Separating capturing and resolving allows us to verify * our invariants. */ checkState(!captured.isResolved()); this.captureStack.addLast(captured); } /** * If {@code captured} is finished construction, and the resolver is closed, resolve it. * *

{@code caller} is used to cooperatively determine whether this call came from the final * constructor for {@code type}. * *

This should only be called at the end of {@link JSType} constructors which invoke super. It * should be called from all such constructors. Some constructors (e.g. {@code AllType}) may * choose to delegate that call through {@link JSType#eagerlyResolveToSelf}. */ void resolveIfClosed(JSType captured, JSTypeClass caller) { if (!caller.isTypeOf(captured)) { return; } JSType expected = this.captureStack.removeLast(); checkState(identical(captured, expected), "Captured %s; Expected %s", captured, expected); switch (this.state) { case CLOSED: case CLOSING: this.doResolve(captured); break; case OPEN: this.resolutionQueue.addLast(captured); break; } } /** * Allow new types to be created without eagerly resolving them. * *

This is required by, and only really useful for, type definition. Types being derived from * previously defined types should not contain reference cycles, and so should be eagerly * resolvable. */ @MustBeClosed public Closer openForDefinition() { checkState(this.state.equals(State.CLOSED)); checkState(this.captureStack.isEmpty()); this.state = State.OPEN; return new Closer(); } private void resolveAll() { checkState(this.state.equals(State.OPEN)); checkState(this.captureStack.isEmpty()); this.state = State.CLOSING; while (!this.resolutionQueue.isEmpty()) { this.doResolve(this.resolutionQueue.removeFirst()); } // resolutionQueue scales with the size of the application, so it needs to be GC'd. this.resolutionQueue = new ArrayDeque<>(); this.state = State.CLOSED; // TODO(sdh): Stop doing this here. It's obviously the wrong place. // By default, the global "this" type is just an anonymous object. // If the user has defined a Window type, make the Window the // implicit prototype of "this". PrototypeObjectType globalThis = (PrototypeObjectType) this.registry.getNativeType(JSTypeNative.GLOBAL_THIS); JSType windowType = this.registry.getGlobalType("Window"); if (globalThis.isUnknownType()) { ObjectType windowObjType = ObjectType.cast(windowType); if (windowObjType != null) { globalThis.setImplicitPrototype(windowObjType); } else { globalThis.setImplicitPrototype( this.registry.getNativeObjectType(JSTypeNative.OBJECT_TYPE)); } } } private void doResolve(JSType type) { type.resolve(this.registry.getErrorReporter()); } /** * Asserts that it's legal to call {@link JSType#resolve} * *

The intent is to enforce that while a type is being resolved, any new types synthesized will * be immediately resolved. */ void assertLegalToResolveTypes() { checkState( !this.state.equals(State.OPEN), "Types cannot be resolved while the registry is open"); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy