Skip to content
EKnife.java 5.45 KiB
Newer Older
Carlos Galindo's avatar
Carlos Galindo committed
/*
 * e-Knife, a program slicing tool for Erlang based on the EDG
 * Copyright (c) 2021. David Insa, Sergio Pérez, Josep Silva, Salvador Tamarit.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

Carlos Galindo's avatar
Carlos Galindo committed
package eknife;

import edg.DotFactory;
import edg.EDGFactory;
Carlos Galindo's avatar
Carlos Galindo committed
import edg.graph.EDG;
import edg.graph.Edge;
import edg.graph.LAST;
Carlos Galindo's avatar
Carlos Galindo committed
import edg.graph.Node;
import edg.slicing.ConstrainedAlgorithm;
import edg.slicing.SlicingAlgorithm;
import edg.slicing.SlicingCriterion;

import java.io.File;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
Carlos Galindo's avatar
Carlos Galindo committed

public class EKnife
{
	public enum Language { Java, Erlang, Php }

	public static void main(String[] args)
	{
		final Args arguments = EKnife.processArguments(args);

		if (!arguments.isValid()) {
			EKnife.printHelp();
			System.exit(3);
		}
		EKnife.run(arguments);
	}

	private static Args processArguments(String[] args)
	{
		Args kArgs = new Args();

		for (int argIndex = 0; argIndex < args.length; argIndex++)
		{
			final String arg = args[argIndex];

			switch (arg)
			{
				case "-i": case "--input":
				case "-o": case "--output":
				case "-f": case "--file":
				case "-l": case "--line":
				case "-v": case "--var":
				case "-n": case "--occurrence":
				if (argIndex == args.length - 1) {
					System.out.printf("Parameter %s requires an argument\n", arg);
					printHelp();
					System.exit(1);
				}
				default:
					break;
			}
			switch (arg)
			{
				case "--help":
					printHelp();
					System.exit(0);
				case "-i": case "--input":
				kArgs.inputPath = args[argIndex + 1];
				break;
				case "-o": case "--output":
				kArgs.outputFile = new File(args[argIndex + 1]);
				break;
				case "-f": case "--file":
				kArgs.file = args[argIndex + 1];
				break;
				case "-l": case "--line":
				kArgs.line = Integer.parseInt(args[argIndex + 1]);
				break;
				case "-v": case "--var":
				kArgs.name = args[argIndex + 1];
				break;
				case "-n": case "--occurrence":
				kArgs.occurrence = Integer.parseInt(args[argIndex + 1]);
				break;
			}
		}

		kArgs.completeData();
		return kArgs;
	}
	private static void printHelp()
	{
		String help = "";

		help += "Use the following options:\n";
		help += "  -i,--input  <file/folder>   The file/folder where the source code is\n";
		help += "  -o,--output <file/folder>   The file/folder where the slice will be stored\n";
		help += "  -f,--file   <file>          The file (relative to -i) where the slicing criterion is\n";
		help += "  -l,--line   <num>           The line of the slicing criterion\n";
		help += "  -v,--var    <name>          The name of the slicing criterion (must be a variable)\n";
		help += "  -n,--occurrence <num>       The occurrence of the slicing criterion in that line\n";
		help += "  --help                      Show this message.\n";

		System.out.print(help);
	}

	private static void run(Args a)
	{
		final LAST last = LASTFactory.createLAST(Language.Erlang, a.inputPath, true);

		boolean showIP = true;
		Map<Edge.Type, Boolean> edgeFlags = new HashMap<>();
		edgeFlags.put(Edge.Type.Value, false);
		edgeFlags.put(Edge.Type.ControlFlow, false);
		edgeFlags.put(Edge.Type.Control, false);
		edgeFlags.put(Edge.Type.Flow, false);
		edgeFlags.put(Edge.Type.Input, showIP);
		edgeFlags.put(Edge.Type.Call, showIP);
		edgeFlags.put(Edge.Type.Output, false);
		edgeFlags.put(Edge.Type.Summary, false);

		DotFactory.createDot(new File("/Users/serperu/Desktop/SlicerOutput/graph.dot"), new EDG(last), edgeFlags);

		final EDG edg = new EDGFactory(last).createEDG();

		DotFactory.createDot(new File("/Users/serperu/Desktop/SlicerOutput/graph.dot"), edg, edgeFlags);

Carlos Galindo's avatar
Carlos Galindo committed
		final SlicingCriterion slicingCriterion = new SlicingCriterion(a.file, a.line, a.name, a.occurrence);
		final Node SC = edg.getNode(slicingCriterion);
		if (SC == null) {
			System.out.println("Error: the slicing criterion could not be found! " + slicingCriterion);
			System.exit(1);
		}
		final SlicingAlgorithm slicingAlgorithm = new ConstrainedAlgorithm(edg);
		final Set<Node> slice = slicingAlgorithm.slice(SC);
Carlos Galindo's avatar
Carlos Galindo committed
		if (slice.isEmpty()) {
			System.out.println("Warning: no files will be written, as the slice is empty.");
			System.exit(2);
		}
		DotFactory.createDot(new File("/Users/serperu/Desktop/SlicerOutput/graphSliced.dot"), edg, SC, slice, edgeFlags);
Carlos Galindo's avatar
Carlos Galindo committed
		CodeFactory.createCode(Language.Erlang, a.outputFile, edg, slice);
	}

	static class Args {
		String inputPath;
		File outputFile;
		String file;
		int line;
		String name;
		int occurrence = 1;

		void completeData() {
			if (file == null && inputPath != null && new File(inputPath).isFile())
				file = new File(inputPath).getName();
		}

		boolean isValid() {
			return inputPath != null && new File(inputPath).exists() &&
					outputFile != null && (outputFile.exists() || outputFile.getAbsoluteFile().getParentFile().isDirectory()) &&
					file != null &&
					line > 0 &&
					name != null && !name.isEmpty() &&
					occurrence > 0;
		}
	}
}