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

com.google.javascript.jscomp.CombinedCompilerPass 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
/*
 * Copyright 2007 The Closure Compiler Authors.
 *
 * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.javascript.jscomp;

import com.google.common.collect.ImmutableList;
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
import com.google.javascript.rhino.Node;
import java.util.List;
import org.jspecify.nullness.Nullable;

/**
 * A compiler pass combining multiple {@link Callback} and {@link ScopedCallback} objects. This pass
 * can be used to separate logically different verifications without incurring any additional
 * traversal and CFG generation costs.
 *
 * 

Due to this compiler pass' nature, none of the callbacks may mutate the parse tree. * *

TODO(user): This combined pass is currently limited in the type of callbacks it can * combine due to the difficulty of handling NodeTraversal's methods that initiate more recursion * (e.g., {@link NodeTraversal#traverse(Node)} and {@link NodeTraversal#traverseInnerNode(Node, * Node, Scope)}). The {@link NodeTraversal} object passed to the individual callbacks should be * instrumented to emulate the correct behavior. For instance, one could create a {@link * NodeTraversal} whose {@link NodeTraversal#traverseInnerNode(Node, Node, Scope)} ties back into * this compiler pass to give it context about what combined passes are doing. */ final class CombinedCompilerPass implements CompilerPass, ScopedCallback { /** The callbacks that this pass combines. */ private final CallbackWrapper[] callbacks; private final AbstractCompiler compiler; /** * Creates a combined compiler pass. * * @param compiler the compiler */ CombinedCompilerPass(AbstractCompiler compiler, NodeTraversal.Callback... callbacks) { this(compiler, ImmutableList.copyOf(callbacks)); } CombinedCompilerPass(AbstractCompiler compiler, List callbacks) { this.compiler = compiler; this.callbacks = new CallbackWrapper[callbacks.size()]; for (int i = 0; i < callbacks.size(); i++) { this.callbacks[i] = new CallbackWrapper(callbacks.get(i)); } } static void traverse( AbstractCompiler compiler, Node root, List callbacks) { if (callbacks.size() == 1) { NodeTraversal.traverse(compiler, root, callbacks.get(0)); } else { (new CombinedCompilerPass(compiler, callbacks)).process(null, root); } } /** * Maintains information about a callback in order to simulate it being the * exclusive client of the shared {@link NodeTraversal}. In particular, this * class simulates abbreviating the traversal when the wrapped callback * returns false for * {@link Callback#shouldTraverse(NodeTraversal, Node, Node)}. * The callback becomes inactive (i.e., traversal messages are not sent to it) * until the main traversal revisits the node during the post-order visit. */ private static class CallbackWrapper { /** The callback being wrapped. Never null. */ private final NodeTraversal.Callback callback; /** * if (callback instanceof ScopedCallback), then scopedCallback points to an instance of * ScopedCallback, otherwise scopedCallback points to null */ private final @Nullable ScopedCallback scopedCallback; /** * The node that {@link Callback#shouldTraverse(NodeTraversal, Node, Node)} returned false for. * The wrapped callback doesn't receive messages until after this node is revisited in the * post-order traversal. */ private @Nullable Node waiting = null; private CallbackWrapper(NodeTraversal.Callback callback) { this.callback = callback; if (callback instanceof ScopedCallback) { scopedCallback = (ScopedCallback) callback; } else { scopedCallback = null; } } /** * Visits the node unless the wrapped callback is inactive. Activates the * callback if appropriate. */ void visitOrMaybeActivate(NodeTraversal t, Node n, Node parent) { if (isActive()) { callback.visit(t, n, parent); } else if (waiting == n) { waiting = null; } } void shouldTraverseIfActive(NodeTraversal t, Node n, Node parent) { if (isActive() && !callback.shouldTraverse(t, n, parent)) { waiting = n; } } void enterScopeIfActive(NodeTraversal t) { if (isActive() && scopedCallback != null) { scopedCallback.enterScope(t); } } void exitScopeIfActive(NodeTraversal t) { if (isActive() && scopedCallback != null) { scopedCallback.exitScope(t); } } boolean isActive() { return waiting == null; } } @Override public final void process(@Nullable Node externs, Node root) { NodeTraversal.traverse(compiler, root, this); } @Override public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) { if (compiler.hasHaltingErrors()) { return false; } for (CallbackWrapper callback : callbacks) { callback.shouldTraverseIfActive(t, n, parent); } // Note that this method could return false if all callbacks are inactive. // This apparent optimization would make this method more expensive // in the typical case where not all nodes are inactive. It is // very unlikely that many all callbacks would be inactive at the same // time (indeed, there are several checking passes that never return false). return true; } @Override public void visit(NodeTraversal t, Node n, Node parent) { if (compiler.hasHaltingErrors()) { return; } for (CallbackWrapper callback : callbacks) { callback.visitOrMaybeActivate(t, n, parent); } } @Override public void enterScope(NodeTraversal t) { for (CallbackWrapper callback : callbacks) { callback.enterScopeIfActive(t); } } @Override public void exitScope(NodeTraversal t) { for (CallbackWrapper callback : callbacks) { callback.exitScopeIfActive(t); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy