Commit a70c8934 authored by Sergio Pérez's avatar Sergio Pérez
Browse files

Improvement of anonymous functions and function calls

* AdHoc anonymous function calls (fun(X)-> X+1 end(5))
* Named anonymous function / function calls
parent 890a1bef
Loading
Loading
Loading
Loading
+53 −42
Original line number Diff line number Diff line
@@ -370,57 +370,68 @@ public class InterproceduralEdgeGenerator extends EdgeGenerator
		// Function
		final Node name = edg.getChild(nameNode, Node.Type.Value);
		final Node.Type nameType = name.getType();
		String routineName = name.getName();
		final String routineName = name.getName();

		// - M:R()	all routines of all modules				=> _:_
		// - m:R()	all routines of module m				=> m:_
		// - M:r()	routine r of all modules				=> _:r
		// - m:r()	routine f of module m					=> m:r
		// - r()	routine f of current module				=> m:r
		// - ar()	this anonymous routine					=> null:_
		// - X()	all routines (including anonymous ones)	=> null:null
		if (moduleRefType != Node.Type.Literal && moduleRefType != Node.Type.Module)
			moduleName = "_";
		if (nameType != Node.Type.Literal)
			routineName = "_";
		if (nameType != Node.Type.Literal && scopeValue == null)
			moduleName = null;
		if (moduleName == null && nameType != Node.Type.Routine)
			routineName = null;
		// - M:R()	all routines of all modules				=> ANY:ANY
		// - m:R()	all routines of module m				=> m:ANY
		// - M:r()	routine r of all modules				=> ANY:r
		// - m:r()	routine f of module m					=> module:r
		// - r()	routine f of current module				=> current:r
		// - ar()	this anonymous routine					=> current:ar 	Ex: fun(X) -> X+1 end(5)
		// - X()	all routines (including anonymous ones)	=> current:ANY

		final List<Node> possibleClauses = new LinkedList<>();
		final List<Node> clauses = edg.getNodes(Node.Type.Clause);
		final boolean thisAnonymousRoutine = moduleName == null && routineName != null;
		final boolean allRoutines = moduleName == null && routineName == null;

		for (Node clause : clauses)
		{
			final Node routine = edg.getParent(clause);
			if (thisAnonymousRoutine && routine != name)
				continue;
			if (!thisAnonymousRoutine && !allRoutines)
			{
				final Node module = edg.getParent(routine);
				final Node.Type moduleType = module.getType();
				if (moduleType != Node.Type.Module)
					continue;
				final String moduleText = module.getName();
				if (!moduleName.equals(moduleText) && !moduleName.equals("_"))
					continue;
				final String routineText = routine.getName();
				if (!routineName.equals(routineText) && !routineName.equals("_"))
		// MODULE MUST BE A LITERAL OR IT IS THE MODULE THAT CONTAINS THE CALL
		if (moduleRefType != Node.Type.Literal && moduleRefType != Node.Type.Module)
			moduleName = "_";
		// FUNCTION NAME CAN BE (1) A LITERAL OR (2) A VARIABLE
		//		(1) A FUNCTION CALL OF A PARTICULAR FUNCTION REPRESENTED BY ITS NAME
		//		(2) A FUNCTION CALL TO:
		//			(2.1) AN ANONYMOUS NAMED FUNCTION
		//			(2.2) A CALL TO AN AD-HOC DEFINED ANONYMOUS FUNCTION
		//			(2.3) A FUNCTION STORED IN A VARIABLE (CAN BE ANY FUNCTION)

		final List<Node> routines = new LinkedList<>();
		if (nameType == Node.Type.Literal) { // (1) A FUNCTION CALL OF A PARTICULAR FUNCTION
			routines.addAll(edg.getNodes(Node.Type.Routine));
		}
		else if (nameType == Node.Type.Variable) { // (2.1) NAMED ANONYMOUS FUNCTIONS
			routines.addAll(edg.getNodes(Node.Type.AnonymousRoutine));
		}

		routines.removeIf(n -> !n.getName().equals(routineName)); // CONNECT TO MATCHING ROUTINE DEFINITIONS
		for (Node routine : routines){
			Node module = edg.getAncestor(routine,Node.Type.Module);
			if (moduleName.equals("_") || moduleName.equals(module.getName())) {
				final List<Node> clauses = edg.getChildrenNonResult(routine);
				final Node clauseParameters = edg.getChild(clauses.get(0), Node.Type.Parameters);
				final List<Node> parameters = edg.getChildrenNonResult(clauseParameters);

				if (arguments.size() != parameters.size())
					continue;
				possibleClauses.addAll(clauses);
			}
		}

		if (possibleClauses.isEmpty()) {
			if (nameType == Node.Type.AnonymousRoutine) // (2.2) A CALL TO AN AD-HOC DEFINED ANONYMOUS FUNCTION
				possibleClauses.addAll(edg.getChildrenNonResult(name));
			else { // (2.3) CONNECT TO ALL POTENTIAL FUNCTION DEFINITIONS
				final List<Node> clauses = edg.getNodes(Node.Type.Clause);
				for (Node clause : clauses){
					Node clauseModule = edg.getAncestor(clause, Node.Type.Module);
					if (moduleName.equals("_") || moduleName.equals(clauseModule.getName())) {
						final Node clauseParameters = edg.getChild(clause, Node.Type.Parameters);
						final List<Node> parameters = edg.getChildrenNonResult(clauseParameters);


						if (arguments.size() != parameters.size())
							continue;

						possibleClauses.add(clause);
					}
				}
			}
		}

		return possibleClauses;
	}
+2 −3
Original line number Diff line number Diff line
@@ -129,12 +129,11 @@ System.out.println(work.getId() + " - " + work.getConstraints().getEdgeConstrain
	{
		final List<Work> workList = new LinkedList<>();
		final List<Node> routines = edg.getNodes(Node.Type.Routine);
		routines.addAll(edg.getNodes(Node.Type.AnonymousRoutine));

		for (Node routine : routines)
		{
			final List<Node> clauses = edg.getChildren(routine);
			clauses.removeIf(c -> c.getType() == Node.Type.Result);
			
			final List<Node> clauses = edg.getChildrenNonResult(routine);
			for (Node clause : clauses)
			{
				// Summary Edges for the result node
+2 −2
Original line number Diff line number Diff line
@@ -121,14 +121,14 @@ public class EKnife
	{
		final LAST last = LASTFactory.createLAST(Language.Erlang, a.inputPath, true);

		boolean showIP = false;
		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, true);
		edgeFlags.put(Edge.Type.Input, showIP);
		edgeFlags.put(Edge.Type.Call, true);
		edgeFlags.put(Edge.Type.Call, showIP);
		edgeFlags.put(Edge.Type.Output, showIP);
		edgeFlags.put(Edge.Type.Summary, false);

+1 −0
Original line number Diff line number Diff line
@@ -408,6 +408,7 @@ public class ErlangLASTFactory extends LASTFactory
		final OtpErlangList functionClauses = (OtpErlangList) namedFunction.elementAt(3);
		final LDASTNodeInfo ldNodeInfo = new LDASTNodeInfo(line, "named function");

		createContext(true);
		super.addRoutine(name, functionClauses, true, ldNodeInfo);
	}
	private void processClause(OtpErlangTuple clause)