Loading e-Knife/src/main/java/eknife/erlang/ErlangCodeFactory.java +142 −43 Original line number Diff line number Diff line Loading @@ -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()); Loading @@ -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) Loading @@ -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); } Loading Loading @@ -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) { Loading @@ -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); Loading Loading @@ -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)) { Loading Loading @@ -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"); Loading @@ -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) { Loading Loading @@ -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; Loading Loading
e-Knife/src/main/java/eknife/erlang/ErlangCodeFactory.java +142 −43 Original line number Diff line number Diff line Loading @@ -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()); Loading @@ -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) Loading @@ -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); } Loading Loading @@ -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) { Loading @@ -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); Loading Loading @@ -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)) { Loading Loading @@ -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"); Loading @@ -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) { Loading Loading @@ -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; Loading