org.napile.compiler.lang.cfg.PseudocodeTraverser.java Source code

Java tutorial

Introduction

Here is the source code for org.napile.compiler.lang.cfg.PseudocodeTraverser.java

Source

/*
 * Copyright 2010-2012 JetBrains s.r.o.
 *
 * 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 org.napile.compiler.lang.cfg;

import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.napile.compiler.lang.cfg.pseudocode.Instruction;
import org.napile.compiler.lang.cfg.pseudocode.LocalDeclarationInstruction;
import org.napile.compiler.lang.cfg.pseudocode.Pseudocode;
import org.napile.compiler.lang.cfg.pseudocode.SubroutineEnterInstruction;
import org.napile.compiler.lang.cfg.pseudocode.SubroutineSinkInstruction;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;

/**
 * @author svtk
 */
public class PseudocodeTraverser {
    @NotNull
    private static Instruction getStartInstruction(@NotNull Pseudocode pseudocode, boolean directOrder) {
        return directOrder ? pseudocode.getEnterInstruction() : pseudocode.getSinkInstruction();
    }

    public static <D> Map<Instruction, Edges<D>> collectData(@NotNull Pseudocode pseudocode, boolean directOrder,
            boolean lookInside, @NotNull D initialDataValue, @NotNull D initialDataValueForEnterInstruction,
            @NotNull InstructionDataMergeStrategy<D> instructionDataMergeStrategy) {

        Map<Instruction, Edges<D>> edgesMap = Maps.newLinkedHashMap();
        initializeEdgesMap(pseudocode, lookInside, edgesMap, initialDataValue);
        edgesMap.put(getStartInstruction(pseudocode, directOrder),
                Edges.create(initialDataValueForEnterInstruction, initialDataValueForEnterInstruction));

        boolean[] changed = new boolean[1];
        changed[0] = true;
        while (changed[0]) {
            changed[0] = false;
            collectDataFromSubgraph(pseudocode, directOrder, lookInside, edgesMap, instructionDataMergeStrategy,
                    Collections.<Instruction>emptyList(), changed, false);
        }
        return edgesMap;
    }

    private static <D> void initializeEdgesMap(@NotNull Pseudocode pseudocode, boolean lookInside,
            @NotNull Map<Instruction, Edges<D>> edgesMap, @NotNull D initialDataValue) {
        List<Instruction> instructions = pseudocode.getInstructions();
        Edges<D> initialEdge = Edges.create(initialDataValue, initialDataValue);
        for (Instruction instruction : instructions) {
            edgesMap.put(instruction, initialEdge);
            if (lookInside && instruction instanceof LocalDeclarationInstruction) {
                initializeEdgesMap(((LocalDeclarationInstruction) instruction).getBody(), lookInside, edgesMap,
                        initialDataValue);
            }
        }
    }

    private static <D> void collectDataFromSubgraph(@NotNull Pseudocode pseudocode, boolean directOrder,
            boolean lookInside, @NotNull Map<Instruction, Edges<D>> edgesMap,
            @NotNull InstructionDataMergeStrategy<D> instructionDataMergeStrategy,
            @NotNull Collection<Instruction> previousSubGraphInstructions, boolean[] changed, boolean isLocal) {

        List<Instruction> instructions = directOrder ? pseudocode.getInstructions()
                : pseudocode.getReversedInstructions();
        Instruction startInstruction = getStartInstruction(pseudocode, directOrder);

        for (Instruction instruction : instructions) {
            boolean isStart = directOrder ? instruction instanceof SubroutineEnterInstruction
                    : instruction instanceof SubroutineSinkInstruction;
            if (!isLocal && isStart)
                continue;

            Collection<Instruction> allPreviousInstructions;
            Collection<Instruction> previousInstructions = directOrder ? instruction.getPreviousInstructions()
                    : instruction.getNextInstructions();

            if (instruction == startInstruction && !previousSubGraphInstructions.isEmpty()) {
                allPreviousInstructions = Lists.newArrayList(previousInstructions);
                allPreviousInstructions.addAll(previousSubGraphInstructions);
            } else {
                allPreviousInstructions = previousInstructions;
            }

            if (lookInside && instruction instanceof LocalDeclarationInstruction) {
                Pseudocode subroutinePseudocode = ((LocalDeclarationInstruction) instruction).getBody();
                collectDataFromSubgraph(subroutinePseudocode, directOrder, lookInside, edgesMap,
                        instructionDataMergeStrategy, previousInstructions, changed, true);
                Instruction lastInstruction = directOrder ? subroutinePseudocode.getSinkInstruction()
                        : subroutinePseudocode.getEnterInstruction();
                Edges<D> previousValue = edgesMap.get(instruction);
                Edges<D> newValue = edgesMap.get(lastInstruction);
                if (!previousValue.equals(newValue)) {
                    changed[0] = true;
                    edgesMap.put(instruction, newValue);
                }
                continue;
            }
            Edges<D> previousDataValue = edgesMap.get(instruction);

            Collection<D> incomingEdgesData = Sets.newHashSet();

            for (Instruction previousInstruction : allPreviousInstructions) {
                Edges<D> previousData = edgesMap.get(previousInstruction);
                if (previousData != null) {
                    incomingEdgesData.add(previousData.out);
                }
            }
            Edges<D> mergedData = instructionDataMergeStrategy.execute(instruction, incomingEdgesData);
            if (!mergedData.equals(previousDataValue)) {
                changed[0] = true;
                edgesMap.put(instruction, mergedData);
            }
        }
    }

    public static void traverse(@NotNull Pseudocode pseudocode, boolean directOrder,
            InstructionAnalyzeStrategy instructionAnalyzeStrategy) {

        List<Instruction> instructions = directOrder ? pseudocode.getInstructions()
                : pseudocode.getReversedInstructions();
        for (Instruction instruction : instructions) {
            if (instruction instanceof LocalDeclarationInstruction) {
                traverse(((LocalDeclarationInstruction) instruction).getBody(), directOrder,
                        instructionAnalyzeStrategy);
            }
            instructionAnalyzeStrategy.execute(instruction);
        }
    }

    public static <D> void traverse(@NotNull Pseudocode pseudocode, boolean directOrder, boolean lookInside,
            @NotNull Map<Instruction, Edges<D>> edgesMap,
            @NotNull InstructionDataAnalyzeStrategy<D> instructionDataAnalyzeStrategy) {

        List<Instruction> instructions = directOrder ? pseudocode.getInstructions()
                : pseudocode.getReversedInstructions();
        for (Instruction instruction : instructions) {
            if (lookInside && instruction instanceof LocalDeclarationInstruction) {
                traverse(((LocalDeclarationInstruction) instruction).getBody(), directOrder, lookInside, edgesMap,
                        instructionDataAnalyzeStrategy);
            }
            Edges<D> edges = edgesMap.get(instruction);
            instructionDataAnalyzeStrategy.execute(instruction, edges != null ? edges.in : null,
                    edges != null ? edges.out : null);
        }
    }

    public interface InstructionDataMergeStrategy<D> {
        Edges<D> execute(@NotNull Instruction instruction, @NotNull Collection<D> incomingEdgesData);
    }

    public interface InstructionDataAnalyzeStrategy<D> {
        void execute(@NotNull Instruction instruction, @Nullable D enterData, @Nullable D exitData);
    }

    public interface InstructionAnalyzeStrategy {
        void execute(@NotNull Instruction instruction);
    }

    public static class Edges<T> {
        public final T in;
        public final T out;

        Edges(@NotNull T in, @NotNull T out) {
            this.in = in;
            this.out = out;
        }

        public static <T> Edges<T> create(@NotNull T in, @NotNull T out) {
            return new Edges<T>(in, out);
        }

        @Override
        public boolean equals(Object o) {
            if (this == o)
                return true;
            if (!(o instanceof Edges))
                return false;

            Edges edges = (Edges) o;

            if (in != null ? !in.equals(edges.in) : edges.in != null)
                return false;
            if (out != null ? !out.equals(edges.out) : edges.out != null)
                return false;

            return true;
        }

        @Override
        public int hashCode() {
            int result = in != null ? in.hashCode() : 0;
            result = 31 * result + (out != null ? out.hashCode() : 0);
            return result;
        }
    }
}