Commit 4cce3a1b authored by Javier Costa's avatar Javier Costa
Browse files

Reinvented scopes

parent 035df101
Loading
Loading
Loading
Loading
+4 −2
Original line number Diff line number Diff line
@@ -7,6 +7,7 @@ import tfm.graphs.CFGGraph;
import tfm.graphs.Graph;
import tfm.graphs.PDGGraph;
import tfm.nodes.PDGNode;
import tfm.scopes.ScopeHolder;
import tfm.utils.Logger;
import tfm.visitors.CFGVisitor;
import tfm.visitors.PDGVisitor;
@@ -68,9 +69,10 @@ public class Main {
            }
        };

        VoidVisitor<PDGNode> voidVisitor = new PDGVisitor(pdgGraph);
        ScopeHolder<PDGNode> scopeHolder = new ScopeHolder<>(pdgGraph.getRootNode());
        PDGVisitor visitor = new PDGVisitor(pdgGraph, scopeHolder);

        cu.accept(voidVisitor, pdgGraph.getRootNode());
        cu.accept(visitor, scopeHolder);

        return pdgGraph;
    }
+28 −0
Original line number Diff line number Diff line
package tfm.scopes;

import tfm.nodes.Node;
import tfm.variables.actions.VariableDefinition;

import java.util.List;
import java.util.stream.Collectors;

public class BranchedScope<N extends Node> extends ScopeHolder<N> {

    public BranchedScope(N node) {
        super(node);
    }

    @Override
    public List<VariableDefinition<N>> getLastDefinitions(String variable) {
        return getSubscopes().stream()
                .flatMap(scope -> scope.getLastDefinitions(variable).stream())
                .collect(Collectors.toList());
    }

    @Override
    public List<VariableDefinition<N>> getLastDefinitionsBeforeNode(String variable, N node) {
        return getSubscopes().stream()
                .flatMap(scope -> scope.getLastDefinitionsBeforeNode(variable, node).stream())
                .collect(Collectors.toList());
    }
}
+42 −0
Original line number Diff line number Diff line
package tfm.scopes;

import tfm.nodes.Node;
import tfm.variables.actions.VariableDeclaration;
import tfm.variables.actions.VariableDefinition;
import tfm.variables.actions.VariableUse;

import java.util.List;
import java.util.Set;

public abstract class Scope<N extends Node> {

    protected N root;

    protected Scope(N root) {
        this.root = root;
    }

    public N getRoot() {
        return root;
    }

    public abstract void addVariableDeclaration(String variable, N context);
    public abstract void addVariableDefinition(String variable, N context);
    public abstract void addVariableUse(String variable, N context);

    public abstract boolean isVariableDeclared(String variable);
    public abstract boolean isVariableDefined(String variable);
    public abstract boolean isVariableUsed(String variable);

    public abstract List<VariableDeclaration<N>> getVariableDeclarations(String variable);
    public abstract List<VariableDefinition<N>> getVariableDefinitions(String variable);
    public abstract List<VariableUse<N>> getVariableUses(String variable);

    public abstract Set<String> getDeclaredVariables();
    public abstract Set<String> getDefinedVariables();
    public abstract Set<String> getUsedVariables();

    public abstract List<VariableDefinition<N>> getLastDefinitions(String variable);
    public abstract List<VariableDefinition<N>> getLastDefinitionsBeforeNode(String variable, N node);
}
+166 −0
Original line number Diff line number Diff line
package tfm.scopes;

import tfm.nodes.Node;
import tfm.variables.actions.VariableDeclaration;
import tfm.variables.actions.VariableDefinition;
import tfm.variables.actions.VariableUse;

import java.util.*;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class ScopeHolder<N extends Node> extends Scope<N> {

    private Queue<Scope<N>> subscopes;

    public ScopeHolder(N root) {
        super(root);

        subscopes = Collections.asLifoQueue(new ArrayDeque<>());
    }

    private Optional<Scope<N>> getLastScope() {
        if (subscopes.isEmpty())
            return Optional.empty();

        return Optional.of(subscopes.peek());
    }

    @Override
    public void addVariableDeclaration(String variable, N context) {
        Optional<Scope<N>> optionalScope = getLastScope();

        boolean newScope = !optionalScope.isPresent();

        Scope<N> scope = optionalScope.orElse(new VariableScope<>(context));

        scope.addVariableDeclaration(variable, context);

        if (newScope) {
            addSubscope(scope);
        }
    }

    @Override
    public void addVariableDefinition(String variable, N context) {
        Optional<Scope<N>> optionalScope = getLastScope();

        boolean newScope = !optionalScope.isPresent();

        Scope<N> scope = optionalScope.orElse(new VariableScope<>(context));

        scope.addVariableDefinition(variable, context);

        if (newScope) {
            addSubscope(scope);
        }
    }

    @Override
    public void addVariableUse(String variable, N context) {
        Optional<Scope<N>> optionalScope = getLastScope();

        boolean newScope = !optionalScope.isPresent();

        Scope<N> scope = optionalScope.orElse(new VariableScope<>(context));

        scope.addVariableUse(variable, context);

        if (newScope) {
            addSubscope(scope);
        }
    }

    public Queue<Scope<N>> getSubscopes() {
        return subscopes;
    }

    public void addSubscope(Scope<N> subscope) {
        subscopes.add(subscope);
    }

    @Override
    public boolean isVariableDeclared(String variable) {
        return subscopes.stream().anyMatch(subscope -> subscope.isVariableDeclared(variable));
    }

    @Override
    public boolean isVariableDefined(String variable) {
        return subscopes.stream().anyMatch(subscope -> subscope.isVariableDefined(variable));
    }

    @Override
    public boolean isVariableUsed(String variable) {
        return subscopes.stream().anyMatch(subscope -> subscope.isVariableUsed(variable));
    }

    @Override
    public List<VariableDeclaration<N>> getVariableDeclarations(String variable) {
        return subscopes.stream()
                .flatMap(scope -> scope.getVariableDeclarations(variable).stream())
                .collect(Collectors.toList());
    }

    @Override
    public List<VariableDefinition<N>> getVariableDefinitions(String variable) {
        return subscopes.stream()
                .flatMap(scope -> scope.getVariableDefinitions(variable).stream())
                .collect(Collectors.toList());
    }

    @Override
    public List<VariableUse<N>> getVariableUses(String variable) {
        return subscopes.stream()
                .flatMap(scope -> scope.getVariableUses(variable).stream())
                .collect(Collectors.toList());
    }

    @Override
    public Set<String> getDeclaredVariables() {
        return subscopes.stream()
                .flatMap(scope -> scope.getDeclaredVariables().stream())
                .collect(Collectors.toSet());
    }

    @Override
    public Set<String> getDefinedVariables() {
        return subscopes.stream()
                .flatMap(scope -> scope.getDefinedVariables().stream())
                .collect(Collectors.toSet());
    }

    @Override
    public Set<String> getUsedVariables() {
        return subscopes.stream()
                .flatMap(scope -> scope.getUsedVariables().stream())
                .collect(Collectors.toSet());
    }

    @Override
    public List<VariableDefinition<N>> getLastDefinitions(String variable) {
        Optional<Scope<N>> scope = subscopes.stream()
                .filter(_scope -> _scope.isVariableDefined(variable))
                .findFirst();

        if (!scope.isPresent())
            return new ArrayList<>(0);

        return scope.get().getLastDefinitions(variable);
    }

    @Override
    public List<VariableDefinition<N>> getLastDefinitionsBeforeNode(String variable, N node) {
        Optional<Scope<N>> scope = subscopes.stream()
                .filter(_scope -> _scope.isVariableDefined(variable) && _scope.root.getId() <= node.getId())
                .findFirst();

        if (!scope.isPresent())
            return new ArrayList<>(0);

        return scope.get().getLastDefinitions(variable);
    }


}
+134 −0
Original line number Diff line number Diff line
package tfm.scopes;

import tfm.nodes.Node;
import tfm.variables.actions.VariableAction;
import tfm.variables.actions.VariableDeclaration;
import tfm.variables.actions.VariableDefinition;
import tfm.variables.actions.VariableUse;

import java.util.*;
import java.util.stream.Collectors;

public class VariableScope<N extends Node> extends Scope<N> {

    private Map<String, List<VariableDeclaration<N>>> variableDeclarations;
    private Map<String, List<VariableDefinition<N>>> variableDefinitions;
    private Map<String, List<VariableUse<N>>> variableUses;

    public VariableScope(N root) {
        super(root);

        variableDeclarations = new HashMap<>();
        variableDefinitions = new HashMap<>();
        variableUses = new HashMap<>();
    }

    @Override
    public boolean isVariableDeclared(String variable) {
        return variableDeclarations.containsKey(variable);
    }

    @Override
    public boolean isVariableDefined(String variable) {
        return variableDefinitions.containsKey(variable);
    }

    @Override
    public boolean isVariableUsed(String variable) {
        return variableUses.containsKey(variable);
    }

    @Override
    public List<VariableDeclaration<N>> getVariableDeclarations(String variable) {
        return new ArrayList<>(variableDeclarations.getOrDefault(variable, new ArrayList<>()));
    }

    @Override
    public List<VariableDefinition<N>> getVariableDefinitions(String variable) {
        return new ArrayList<>(variableDefinitions.getOrDefault(variable, new ArrayList<>()));
    }

    @Override
    public List<VariableUse<N>> getVariableUses(String variable) {
        return new ArrayList<>(variableUses.getOrDefault(variable, new ArrayList<>()));
    }

    @Override
    public Set<String> getDeclaredVariables() {
        return new HashSet<>(variableDeclarations.keySet());
    }

    @Override
    public Set<String> getDefinedVariables() {
        return new HashSet<>(variableDefinitions.keySet());
    }

    @Override
    public Set<String> getUsedVariables() {
        return new HashSet<>(variableUses.keySet());
    }

    @Override
    public List<VariableDefinition<N>> getLastDefinitions(String variable) {
        List<VariableDefinition<N>> res = getVariableDefinitions(variable);

        if (res.isEmpty())
            return res;

        return res.subList(res.size() - 1, res.size());
    }

    @Override
    public List<VariableDefinition<N>> getLastDefinitionsBeforeNode(String variable, N node) {
        List<VariableDefinition<N>> res = getVariableDefinitions(variable);

        if (res.isEmpty())
            return res;

        Optional<VariableDefinition<N>> target = res.stream()
                .filter(variableDefinition -> variableDefinition.getNode().getId() <= node.getId())
                .max(Comparator.comparingInt(variableDefinition -> variableDefinition.getNode().getId()));

        return target.map(variableDefinition -> new ArrayList<>(Collections.singletonList(variableDefinition)))
                .orElseGet(ArrayList::new);
    }

    @Override
    public void addVariableDeclaration(String variable, N context) {
        appendValue(variableDeclarations, variable, new VariableDeclaration<>(variable, context));
    }

    @Override
    public void addVariableDefinition(String variable, N context) {
        appendValue(variableDefinitions, variable, new VariableDefinition<>(variable, context));
    }

    @Override
    public void addVariableUse(String variable, N context) {
        appendValue(variableUses, variable, new VariableUse<>(variable, context));
    }

    private <E extends VariableAction<N>> void appendValue(Map<String, List<E>> map, String variable, E action) {
        List<E> value = map.getOrDefault(variable, new ArrayList<>());

        boolean exists = !value.isEmpty();

        value.add(action);

        if (!exists) {
            map.put(variable, value);
        }
    }

    private <E extends VariableAction<N>> void appendValues(Map<String, List<E>> map, String variable, List<E> actions) {
        List<E> value = map.getOrDefault(variable, new ArrayList<>());

        boolean exists = !value.isEmpty();

        value.addAll(actions);

        if (!exists) {
            map.put(variable, value);
        }
    }
}
Loading