compile.analyze.LastReached.java Source code

Java tutorial

Introduction

Here is the source code for compile.analyze.LastReached.java

Source

/**
 * ADOBE SYSTEMS INCORPORATED
 * Copyright 2009-2013 Adobe Systems Incorporated
 * All Rights Reserved.
 *
 * NOTICE: Adobe permits you to use, modify, and distribute
 * this file in accordance with the terms of the MIT license,
 * a copy of which can be found in the LICENSE.txt file or at
 * http://opensource.org/licenses/MIT.
 */
package compile.analyze;

import com.google.common.collect.Sets;
import compile.Loc;
import compile.Session;
import compile.module.Module;
import compile.module.Scope;
import compile.term.*;

import java.util.*;

/**
 * Calculates reachability data used by {@link RefChecker}.
 * For each let binding L in a module, the {@link #calc} method
 * picks the latest in-module let (i.e., the let whose definition
 * occurs last in the module's body) from the closure of lets reachable
 * from the RHS of L by reference (considering L as reachable in 0 steps).
 * Return a map from let bindings to these locations.
 *
 * @author Basil Hosmer
 */
public final class LastReached extends ModuleVisitor<Object> {
    private Loc lastLoc;

    private Map<LetBinding, Loc> lastReached;

    private final Set<RefTerm> visitedRefs;

    public LastReached(final Module module) {
        super(module);
        visitedRefs = Sets.newIdentityHashSet();
    }

    /**
     *
     */
    public Map<LetBinding, Loc> calc() {
        if (Session.isDebug())
            Session.debug(getModule().getLoc(), "Calculating last reached...");

        visitedRefs.clear();

        lastReached = new IdentityHashMap<LetBinding, Loc>();

        process();

        return lastReached;
    }

    // BindingVisitor

    /**
     * if let binding is non-intrinsic and hasn't already been
     * visited, traverse RHS and add resulting last-reached 
     * location to {@link #lastReached}.
     */
    @Override
    public Object visit(final LetBinding let) {
        if (let.getLoc() == Loc.INTRINSIC)
            return null;

        if (lastReached.containsKey(let))
            return null;

        final Loc prevLoc = lastLoc;

        lastLoc = let.getLoc();

        // let is current statement. this traversal will
        // leave an earliest valid location in map
        super.visit(let);

        if (Session.isDebug())
            Session.debug(let.getLoc(), "{0} : {1}", let.getName(), lastLoc.toString());

        lastReached.put(let, lastLoc);

        lastLoc = prevLoc;

        return null;
    }

    // TermVisitor

    /**
     * if we're traversing the RHS of a let, update in-progress
     * last-reached with the last-reached of our referent, if
     * it's later than current loc.
     */
    @Override
    public Object visit(final RefTerm ref) {
        // not spidering a let, no need to compute bound
        if (lastLoc == null)
            return null;

        final ValueBinding binding = ref.getBinding();

        // ref is not to a let
        if (!binding.isLet())
            return null;

        final LetBinding let = (LetBinding) binding;

        final Scope scope = let.getScope();

        // let is nonlocal
        if (scope.getModule() != getModule())
            return null;

        // already visited this ref
        if (visitedRefs.contains(ref))
            return null;

        visitedRefs.add(ref);

        // traverse to find find last-reached loc for this let
        visit(let);

        final Loc loc = lastReached.get(let);

        // if our earliest valid bound is later than current earliest, update
        if (lastLoc.isBefore(loc))
            lastLoc = loc;

        return null;
    }
}