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

Better Erlang code generation of inner components

parent 4f86a8e4
Loading
Loading
Loading
Loading
+142 −43
Original line number Diff line number Diff line
@@ -235,13 +235,37 @@ public class ErlangCodeFactory

		for (Node node : nodes)
		{
			if (!transformUnused && this.slice != null &&
					!this.slice.contains(node) && !mayContainInternalSliceCode(node))
			if (this.slice != null && !this.slice.contains(node)) {
				if (!transformUnused && !mayContainInternalSliceCode(node))
					continue;
				else if (transformUnused && !mayContainInternalSliceCode(node))
					expressionsList.add(this.parseEmpty(node));
				else if (!transformUnused && mayContainInternalSliceCode(node)) {
					final List<OtpErlangTuple> expressionTuple = this.parse(node, false);
					expressionsList.addAll(expressionTuple);
				}
				else { // transformUnused && mayContainInternalSliceCode(node)
					final List<OtpErlangTuple> expressionTuple = this.parse(node, false);
					if (expressionTuple.isEmpty())
						expressionsList.add(this.parseEmpty(node));
					else if (expressionTuple.size() == 1)
						expressionsList.addAll(expressionTuple);
					else{
						final OtpErlangObject[] blockElements = new OtpErlangObject[3];
						blockElements[0] = new OtpErlangAtom("block");
						blockElements[1] = new OtpErlangLong(1);
						final OtpErlangObject[] innerElements = this.toArray(expressionsList);
						blockElements[2] = new OtpErlangList(innerElements);

			final List<OtpErlangTuple> expressionTuple = this.parse(node, transformUnused);
						expressionsList.add(new OtpErlangTuple(blockElements));
					}
				}
			}
			else{
				final List<OtpErlangTuple> expressionTuple = this.parse(node, false);
				expressionsList.addAll(expressionTuple);
			}
		}
		if (!nodes.isEmpty() && expressionsList.isEmpty() && transformUnused)
			expressionsList.add(this.parseEmptyLiteral());

@@ -253,48 +277,69 @@ public class ErlangCodeFactory
		return this.parse(node, true);
	}

	private List<OtpErlangTuple> parse(Node node, boolean transformUnused)
	{
		if (this.slice != null && !this.slice.contains(node) && !mayContainInternalSliceCode(node))
	private List<OtpErlangTuple> parse(Node node, boolean transformUnused) {
		if (this.slice != null && !this.slice.contains(node) && !mayContainInternalSliceCode(node)){
			if (transformUnused)
				return List.of(this.parseEmpty(node));
			else
				return List.of();

		}
		List<OtpErlangTuple> result;
		switch (node.getType())
		{
			case Block:
				return List.of(this.parseBlock(node));
				result = List.of(this.parseBlock(node));
				break;
			case Switch:
				return this.parseSwitch(node);
				result = this.parseSwitch(node);
				break;
			case Call:
				return this.parseCall(node);
				result = this.parseCall(node);
				break;
			case Variable:
				return List.of(this.parseVariable(node));
				result = List.of(this.parseVariable(node));
				break;
			case Literal:
				return List.of(this.parseLiteral(node));
				result = List.of(this.parseLiteral(node));
				break;
			case Operation:
				return this.parseOperation(node);
				result = this.parseOperation(node);
				break;
			case Equality:
				return this.parseEquality(node);
				result = this.parseEquality(node);
				break;
			case DataConstructor:
				return this.parseDataConstructor(node);
				result = this.parseDataConstructor(node);
				break;
			case List:
				return this.parseList(node);
				result = this.parseList(node, transformUnused);
				break;
			case ListComprehension:
				return List.of(this.parseListComprehension(node));
				result = this.parseListComprehension(node);
				break;
			case Generator:
				return List.of(this.parseGenerator(node));
				result = this.parseGenerator(node);
				break;
			case Filter:
				return List.of(this.parseFilter(node));
				result = this.parseFilter(node);
				break;
			case Return:
				return this.parseReturn(node);
				result = this.parseReturn(node);
				break;
			case Routine:
			case AnonymousRoutine:
				return List.of(this.parseAnonymousRoutine(node));
				result = List.of(this.parseAnonymousRoutine(node));
				break;
			default:
				throw new RuntimeException("Expression type not contemplated: " + node.getType());
		}
		if (!transformUnused || !mayContainInternalSliceCode(node) || !result.isEmpty())
			return result;

		List<OtpErlangTuple> transformedList = new LinkedList<>();
		transformedList.add(parseEmpty(node));
		return transformedList;

	}

	private OtpErlangTuple parseBlock(Node block)
@@ -304,7 +349,12 @@ public class ErlangCodeFactory

		blockElements[0] = new OtpErlangAtom("block");
		blockElements[1] = new OtpErlangLong(1);
		blockElements[2] = this.parse(blockExpressions, false);
		OtpErlangList exprs = this.parse(blockExpressions, false);
		if (exprs.elements().length == 0) {
			final OtpErlangObject[] expressionsElements = this.toArray(List.of(this.parseEmptyLiteral()));
			blockElements[2] = new OtpErlangList(expressionsElements);
		} else
			blockElements[2] = exprs;

		return new OtpErlangTuple(blockElements);
	}
@@ -408,8 +458,9 @@ public class ErlangCodeFactory
	{
		final Node argumentsNode = edg.getChild(call, Node.Type.Arguments);
		final List<Node> arguments = edg.getChildrenNonResult(argumentsNode);
		final Node callee = edg.getChild(call, Node.Type.Callee);

		if (slice != null && !slice.contains(call)){ // TODO: Think a better way
		if (slice != null && (!slice.contains(callee) && !slice.contains(call))){
			final List<OtpErlangTuple> containedArgs = new LinkedList<>();
			OtpErlangList parsedArgs = this.parse(arguments, false);
			for (OtpErlangObject parsedArg : parsedArgs) {
@@ -420,7 +471,6 @@ public class ErlangCodeFactory
			return containedArgs;
		}

		final Node callee = edg.getChild(call, Node.Type.Callee);
		final Node scopeNode = edg.getChild(callee, Node.Type.Scope);
		final Node nameNode = edg.getChild(callee, Node.Type.Name);
		final List<Node> scopeChildren = edg.getChildrenNonResult(scopeNode);
@@ -525,15 +575,18 @@ public class ErlangCodeFactory

		return List.of(new OtpErlangTuple(tupleElements));
	}
	private List<OtpErlangTuple> parseList(Node list)
	private List<OtpErlangTuple> parseList(Node list, boolean transformUnused)
	{
		if (edg.getChildren(list).isEmpty())
		{
			if (slice != null && (slice.contains(list) || transformUnused)) {
				final OtpErlangObject[] nilElements = new OtpErlangObject[2];
				nilElements[0] = new OtpErlangAtom("nil");
				nilElements[1] = new OtpErlangLong(1);
				return List.of(new OtpErlangTuple(nilElements));
			}
			return List.of();
		}

		final List<Node> listChildren = edg.getChildrenNonResult(list);
		if (slice != null && !slice.contains(list)) {
@@ -577,24 +630,68 @@ public class ErlangCodeFactory

		return List.of(new OtpErlangTuple(patternMatchingElements));
	}
	private OtpErlangTuple parseListComprehension(Node listComprehension)
	private List<OtpErlangTuple> parseListComprehension(Node listComprehension)
	{
		final List<Node> generators = edg.getChildren(listComprehension, Node.Type.Generator);
		// CASES
		// IMPORTANT: THE LC HAS ITS OWN SCOPE (SHADOWING)
		// 1. Only the expression part of the generator is included in the slice
		// 2. Only an expression of a filter is included in the slice
		// 3. Only an expression in the expression part is included in the slice

		final Node restrictions = edg.getChild(listComprehension, Node.Type.Restrictions);
		final List<Node> generators = edg.getChildren(restrictions, Node.Type.Generator);
		final List<Node> filters = edg.getChildren(restrictions, Node.Type.Filter);
		final Node valueNode = edg.getChild(listComprehension, Node.Type.Value);
		final Node value = edg.getChild(valueNode, Node.Type.Value);

		if (slice != null && !slice.contains(listComprehension)) {
			final OtpErlangList genExprs = this.parse(generators, false);
			final OtpErlangList filExprs = this.parse(filters, false);
			final List<OtpErlangTuple> valExprs = this.parse(value, false);
			List<OtpErlangTuple> res = new LinkedList<>();
			res.addAll(valExprs);
			for (OtpErlangObject expr : genExprs) {
				if (!(expr instanceof OtpErlangTuple))
					throw new RuntimeException("The parsed args are not OtpTuples");
				res.add((OtpErlangTuple) expr);
			}
			for (OtpErlangObject expr : filExprs) {
				if (!(expr instanceof OtpErlangTuple))
					throw new RuntimeException("The parsed args are not OtpTuples");
				res.add((OtpErlangTuple) expr);
			}
			return res;
		}


		final OtpErlangObject[] listComprehensionElements = new OtpErlangObject[4];

		listComprehensionElements[0] = new OtpErlangAtom("lc");
		listComprehensionElements[1] = new OtpErlangLong(1);
		listComprehensionElements[2] = this.parse(value).get(0);
		listComprehensionElements[3] = this.parse(generators, false);
		listComprehensionElements[2] = this.parse(value, true).get(0);

		OtpErlangList gens = this.parse(generators, true);
		OtpErlangList fils = this.parse(filters, false);

		final List<OtpErlangObject> expressionsList = new LinkedList<>();
		for (OtpErlangObject gen : gens)
			expressionsList.add(gen);
		for (OtpErlangObject fil : fils)
			expressionsList.add(fil);

		final OtpErlangObject[] genFils = this.toArray(expressionsList);
		listComprehensionElements[3] = new OtpErlangList(genFils);

		return new OtpErlangTuple(listComprehensionElements);
		return List.of(new OtpErlangTuple(listComprehensionElements));
	}
	private OtpErlangTuple parseGenerator(Node generator)
	private List<OtpErlangTuple> parseGenerator(Node generator)
	{
		final Node pattern = edg.getChild(generator, Node.Type.Variable);
		final Node expression = edg.getChild(generator, Node.Type.Iterator);
		if (slice != null && !slice.contains(generator)){
			return this.parse(expression, false);
		}

		final Node pattern = edg.getChild(generator, Node.Type.Variable);
		final OtpErlangObject[] generatorElements = new OtpErlangObject[4];

		generatorElements[0] = new OtpErlangAtom("generate");
@@ -602,17 +699,17 @@ public class ErlangCodeFactory
		generatorElements[2] = this.parse(pattern).get(0);
		generatorElements[3] = this.parse(expression).get(0);

		return new OtpErlangTuple(generatorElements);
		return List.of(new OtpErlangTuple(generatorElements));
	}
	private OtpErlangTuple parseFilter(Node filter)
	private List<OtpErlangTuple> parseFilter(Node filter)
	{
		final Node filterExpr = edg.getChild(filter, Node.Type.Value);
		return this.parse(filterExpr).get(0);
		return this.parse(filterExpr, false);
	}
	private List<OtpErlangTuple> parseReturn(Node returnNode)
	{
		final Node returnExpression = edg.getChild(returnNode, Node.Type.Value);
		return this.parse(returnExpression);
		return this.parse(returnExpression, false);
	}
	private OtpErlangTuple parseAnonymousRoutine(Node anonymousRoutine)
	{
@@ -910,11 +1007,13 @@ public class ErlangCodeFactory
			case Case:
			case Enclosed:
			case Generator:
			case Filter:
			case Iterator:
			case DataConstructor:
			case DataConstructorAccess:
			case List:
			case Return:
			case ListComprehension:
				return true;
			default:
				return false;