package edg; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Stack; import java.util.function.BiConsumer; import edg.LASTBuilder.Where; import edg.graph.LAST; import edg.graph.Node; public abstract class LASTFactory { private LAST last; private final Stack branches = new Stack(); final protected Map currentLabels = new HashMap<>(); final protected Map> unresolvedLabels = new HashMap<>(); private void processElements(R[] elements) { for (int elementIndex = 0; elementIndex < elements.length; elementIndex++) { final R element = elements[elementIndex]; this.processElement(element, elementIndex + 1, elements.length); } } private void processElement(Object element, int index, int length) { final Map info = new HashMap<>(); final Branch parent = this.branches.isEmpty() ? null : this.branches.get(this.branches.size() - 1); if (parent != null) { parent.setIndex(index); parent.setLength(length); } final boolean isPatternZone = this.isPatternZone(this.branches); info.put("ancestors", this.branches); info.put("parent", parent); info.put("patternZone", isPatternZone); this.processElement(element, info); } protected abstract void processElement(Object element, Map info); protected LAST createLAST(Iterable classes, LDASTNodeInfo info) { final R[] classes0 = this.getArray(classes); return this.createLAST(true, classes0, info); } protected LAST createLAST(boolean generateArcs, Iterable classes, LDASTNodeInfo info) { final R[] classes0 = this.getArray(classes); return this.createLAST(generateArcs, classes0, info); } protected LAST createLAST(R[] classes, LDASTNodeInfo info) { return this.createLAST(true, classes, info); } protected LAST createLAST(boolean generateArcs, R[] classes, LDASTNodeInfo info) { this.branches.clear(); this.last = LASTBuilder.createLAST(info); this.processElements(classes); return this.last; } protected void addModule(String name, Iterable members, LDASTNodeInfo info) { final R[] members0 = this.getArray(members); this.addModule(name, members0, info); } protected void addModule(String name, R[] members, LDASTNodeInfo info) { final int moduleId = LASTBuilder.addModule(this.last, name, info); this.branches.push(new Branch(moduleId, Node.Type.Module, info)); this.processElements(members); this.branches.pop(); } protected void addRoutine(String name, Iterable clauses, LDASTNodeInfo info) { final R[] clauses0 = this.getArray(clauses); this.addRoutine(name, clauses0, false, info); } protected void addRoutine(String name, Iterable clauses, boolean anonymous, LDASTNodeInfo info) { final R[] clauses0 = this.getArray(clauses); this.addRoutine(name, clauses0, anonymous, info); } protected void addRoutine(String name, R[] clauses, boolean anonymous, LDASTNodeInfo info) { final Branch parent = this.branches.peek(); final int parentId = parent.getNodeId(); final Where where = parent.getWhere(); final int routineId = LASTBuilder.addRoutine(this.last, parentId, where, name, anonymous, info); Node.Type routineType = anonymous ? Node.Type.AnonymousRoutine : Node.Type.Routine; this.branches.push(new Branch(routineId, routineType, info)); this.processElements(clauses); this.branches.pop(); } protected void addClause(Iterable parameters, S guard, T body, LDASTNodeInfo info) { final R[] parameters0 = this.getArray(parameters); this.addClause(parameters0, guard, body, info); } protected void addClause(R[] parameters, S guard, T body, LDASTNodeInfo info) { final Branch parent = this.branches.peek(); final int parentId = parent.getNodeId(); final int clauseId = LASTBuilder.addClause(this.last, parentId, info); final Branch branch = this.branches.push(new Branch(clauseId, Node.Type.Clause, info)); currentLabels.clear(); // Clear Label list when generating a Clause branch.setWhere(Where.Parameters); this.processElements(parameters); branch.setWhere(Where.Guard); if (guard != null) this.processElement(guard, 1, 1); branch.setWhere(Where.Body); if (body != null) this.processElement(body, 1, 1); this.branches.pop(); } protected void addClause(Iterable parameters, S guard, Iterable expressions, LDASTNodeInfo info) { final R[] parameters0 = this.getArray(parameters); final T[] expressions0 = this.getArray(expressions); this.addClause(parameters0, guard, expressions0, info); } protected void addClause(R[] parameters, S guard, T[] expressions, LDASTNodeInfo info) { final Branch parent = this.branches.peek(); final int parentId = parent.getNodeId(); boolean previousLockState = this.last.getLockState(); final int clauseId = LASTBuilder.addClause(this.last, parentId, info); final Branch branch = this.branches.push(new Branch(clauseId, Node.Type.Clause, info)); branch.setWhere(Where.ParameterIn); branch.setWhere(Where.Parameters); this.processElements(parameters); branch.setWhere(Where.ParameterOut); branch.setWhere(Where.Guard); if (guard != null) this.processElement(guard, 1, 1); branch.setWhere(Where.Body); this.processElements(expressions); this.branches.pop(); this.last.setLockState(previousLockState); } protected void addVariable(String name, boolean declaration, boolean definition, boolean use, boolean global, LDASTNodeInfo info) { final Branch parent = this.branches.peek(); final int parentId = parent.getNodeId(); final Where where = parent.getWhere(); LASTBuilder.addVariable(this.last, parentId, where, name, declaration, definition, use, global, info); } protected void addVariable(String name, boolean declaration, boolean definition, boolean use, boolean global, boolean shadowed, LDASTNodeInfo info) { final Branch parent = this.branches.peek(); final int parentId = parent.getNodeId(); final Where where = parent.getWhere(); LASTBuilder.addVariable(this.last, parentId, where, name, declaration, definition, use, global, shadowed, info); } protected void addLiteral(String value, LDASTNodeInfo info) { final Branch parent = this.branches.peek(); final int parentId = parent.getNodeId(); final Where where = parent.getWhere(); LASTBuilder.addLiteral(this.last, parentId, where, value, info); } protected void addEquality(R left, S right, LDASTNodeInfo info) { final Branch parent = this.branches.peek(); final int parentId = parent.getNodeId(); final Where where = parent.getWhere(); final int equalityId = LASTBuilder.addEquality(this.last, parentId, where, info); boolean previousLockState = last.getLockState(); this.last.lockSDGid(); this.branches.push(new Branch(equalityId, Node.Type.Equality, info)); this.processElement(left, 1, 2); this.processElement(right, 2, 2); this.branches.pop(); last.setLockState(previousLockState); } protected void addEquality(String operator, R left, S right, LDASTNodeInfo info) { final Branch parent = this.branches.peek(); final int parentId = parent.getNodeId(); final Where where = parent.getWhere(); final int equalityId = LASTBuilder.addEquality(this.last, parentId, where, operator, info); this.branches.push(new Branch(equalityId, Node.Type.Equality, info)); this.processElement(left, 1, 2); this.processElement(right, 2, 2); this.branches.pop(); } protected void addOperation(String operation, Iterable operands, LDASTNodeInfo info) { final R[] operands0 = this.getArray(operands); this.addOperation(operation, operands0, info); } protected void addOperation(String operation, R[] operands, LDASTNodeInfo info) { final Branch parent = this.branches.peek(); final int parentId = parent.getNodeId(); final Where where = parent.getWhere(); final int operationId = LASTBuilder.addOperation(this.last, parentId, where, operation, info); boolean previousLockState = last.getLockState(); this.last.lockSDGid(); this.branches.push(new Branch(operationId, Node.Type.Operation, info)); this.processElements(operands); this.branches.pop(); last.setLockState(previousLockState); } protected void addUnaryOperation(String operation, R expression, LDASTNodeInfo info) { final Branch parent = this.branches.peek(); final int parentId = parent.getNodeId(); final Where where = parent.getWhere(); final int operationId = LASTBuilder.addOperation(this.last, parentId, where, operation, info); this.branches.push(new Branch(operationId, Node.Type.Operation, info)); this.processElement(expression,1,1); this.branches.pop(); } // Types protected void addTypeCheck(R expression, T type, LDASTNodeInfo info) { final Branch parent = this.branches.peek(); final int parentId = parent.getNodeId(); final Where where = parent.getWhere(); final int typeCheckId = LASTBuilder.addTypeCheck(this.last, parentId, where, info); this.branches.push(new Branch(typeCheckId, Node.Type.TypeCheck, info)); this.processElement(expression,1,1); this.processElement(type,2,1); this.branches.pop(); } protected void addTypeTransformation(T type, R expression, LDASTNodeInfo info, boolean isEnclosedExpr) { final Branch parent = this.branches.peek(); final int parentId = parent.getNodeId(); final Where where = parent.getWhere(); final int typeTransformId = LASTBuilder.addTypeTransformation(this.last, parentId, where, info, isEnclosedExpr); this.branches.push(new Branch(typeTransformId, Node.Type.TypeTransformation, info)); this.processElement(type,1,1); this.processElement(expression,2,1); this.branches.pop(); } protected void addTypeTransformation(T type, R expression, LDASTNodeInfo info) { final Branch parent = this.branches.peek(); final int parentId = parent.getNodeId(); final Where where = parent.getWhere(); final int typeTransformId = LASTBuilder.addTypeTransformation(this.last, parentId, where, info); this.branches.push(new Branch(typeTransformId, Node.Type.TypeTransformation, info)); this.processElement(type,1,1); this.processElement(expression,2,1); this.branches.pop(); } protected void addType(String value, LDASTNodeInfo info) { final Branch parent = this.branches.peek(); final int parentId = parent.getNodeId(); final Where where = parent.getWhere(); LASTBuilder.addType(this.last, parentId, where, value, info); } // Expressions protected void addDataConstructor(Iterable elements, LDASTNodeInfo info) { final R[] elements0 = this.getArray(elements); this.addDataConstructor(elements0, info); } protected void addDataConstructor(R[] elements, LDASTNodeInfo info) { final Branch parent = this.branches.peek(); final int parentId = parent.getNodeId(); final Where where = parent.getWhere(); final int dataConstructorId = LASTBuilder.addDataConstructor(this.last, parentId, where, info); boolean previousLockState = last.getLockState(); this.last.lockSDGid(); this.branches.push(new Branch(dataConstructorId, Node.Type.DataConstructor, info)); this.processElements(elements); this.branches.pop(); last.setLockState(previousLockState); } protected void addList(Iterable elements, LDASTNodeInfo info) { final R[] elements0 = this.getArray(elements); this.addList(elements0, info); } protected void addList(R[] elements, LDASTNodeInfo info) { final Branch parent = this.branches.peek(); final int parentId = parent.getNodeId(); final Where where = parent.getWhere(); final int listId = LASTBuilder.addList(this.last, parentId, where, info); boolean previousLockState = last.getLockState(); this.last.lockSDGid(); this.branches.push(new Branch(listId, Node.Type.List, info)); this.processElements(elements); this.branches.pop(); this.last.setLockState(previousLockState); } protected void addDataConstructorAccess(R dataConstructor, S access, LDASTNodeInfo info) { final Branch parent = this.branches.peek(); final int parentId = parent.getNodeId(); final Where where = parent.getWhere(); final int dataConstructorId = LASTBuilder.addDataConstructorAccess(this.last, parentId, where, info); this.branches.push(new Branch(dataConstructorId, Node.Type.DataConstructorAccess, info)); this.processElement(dataConstructor, 1, 2); this.processElement(access, 2, 2); this.branches.pop(); } protected void addFieldAccess(R structure, S field, LDASTNodeInfo info) { final Branch parent = this.branches.peek(); final int parentId = parent.getNodeId(); final Where where = parent.getWhere(); final int fieldAccessId = LASTBuilder.addFieldAccess(this.last, parentId, where, info); this.branches.push(new Branch(fieldAccessId, Node.Type.FieldAccess, info)); this.processElement(structure, 1, 2); this.processElement(field, 2, 2); this.branches.pop(); } protected void addBlock(Iterable expressions, LDASTNodeInfo info) { final R[] expressions0 = this.getArray(expressions); this.addBlock(expressions0, info); } protected void addBlock(R[] expressions, LDASTNodeInfo info) { final Branch parent = this.branches.peek(); final int parentId = parent.getNodeId(); final Where where = parent.getWhere(); final int blockId = LASTBuilder.addBlock(this.last, parentId, where, info); this.branches.push(new Branch(blockId, Node.Type.Block, info)); this.processElements(expressions); this.branches.pop(); } protected void addIf(R condition, Iterable thenExpressions, Iterable elseExpressions, LDASTNodeInfo info) { final S[] thenExpressions0 = this.getArray(thenExpressions); final T[] elseExpressions0 = this.getArray(elseExpressions); this.addIf(condition, thenExpressions0, elseExpressions0, info); } protected void addIf(R condition, S[] thenExpressions, T[] elseExpressions, LDASTNodeInfo info) { final Branch parent = this.branches.peek(); final int parentId = parent.getNodeId(); final Where where = parent.getWhere(); final int ifId = LASTBuilder.addIf(this.last, parentId, where, info); final Branch branch = this.branches.push(new Branch(ifId, Node.Type.If, info)); this.last.lockSDGid(); branch.setWhere(Where.Condition); this.processElement(condition, 1, 1); this.last.unlockSDGid(); branch.setWhere(Where.Then); this.processElements(thenExpressions); branch.setWhere(Where.Else); this.processElements(elseExpressions); this.branches.pop(); } protected void addSwitch(R selector, Iterable cases, LDASTNodeInfo info) { final S[] cases0 = this.getArray(cases); this.addSwitch(selector, cases0, info); } protected void addSwitch(R selector, S[] cases, LDASTNodeInfo info) { final Branch parent = this.branches.peek(); final int parentId = parent.getNodeId(); final Where where = parent.getWhere(); final int switchId = LASTBuilder.addSwitch(this.last, parentId, where, info); final Branch branch = this.branches.push(new Branch(switchId, Node.Type.Switch, info)); this.last.lockSDGid(); branch.setWhere(Where.Selector); if (selector != null) this.processElement(selector, 1, 1); this.last.unlockSDGid(); branch.setWhere(Where.Cases); this.processElements(cases); this.branches.pop(); } protected void addCase(R selectable, S guard, T body, LDASTNodeInfo info) { final Branch parent = this.branches.peek(); final int parentId = parent.getNodeId(); final int caseId = LASTBuilder.addCase(this.last, parentId, info); final Branch branch = this.branches.push(new Branch(caseId, Node.Type.Case, info)); branch.setWhere(Where.Selectable); this.processElement(selectable, 1, 1); branch.setWhere(Where.Guard); if (guard != null) this.processElement(guard, 1, 1); branch.setWhere(Where.Body); if (body != null) this.processElement(body, 1, 1); this.branches.pop(); } protected void addCase(R selectable, S guard, Iterable expressions, LDASTNodeInfo info) { final T[] expressions0 = this.getArray(expressions); this.addCase(selectable, guard, expressions0, info); } protected void addCase(R selectable, S guard, T[] expressions, LDASTNodeInfo info) { final Branch parent = this.branches.peek(); final int parentId = parent.getNodeId(); final int caseId = LASTBuilder.addCase(this.last, parentId, info); final Branch branch = this.branches.push(new Branch(caseId, Node.Type.Case, info)); this.last.lockSDGid(); branch.setWhere(Where.Selectable); if (selectable != null) this.processElement(selectable, 1, 1); branch.setWhere(Where.Guard); if (guard != null) this.processElement(guard, 1, 1); this.last.unlockSDGid(); branch.setWhere(Where.Body); this.processElements(expressions); this.branches.pop(); } protected void addDefaultCase(R body, LDASTNodeInfo info) { final Branch parent = this.branches.peek(); final int parentId = parent.getNodeId(); final int defaultCaseId = LASTBuilder.addDefaultCase(this.last, parentId, info); final Branch branch = this.branches.push(new Branch(defaultCaseId, Node.Type.DefaultCase, info)); branch.setWhere(Where.Body); if (body != null) this.processElement(body, 1, 1); this.branches.pop(); } protected void addDefaultCase(Iterable expressions, LDASTNodeInfo info) { final T[] expressions0 = this.getArray(expressions); this.addDefaultCase(expressions0, info); } protected void addDefaultCase(R[] expressions, LDASTNodeInfo info) { final Branch parent = this.branches.peek(); final int parentId = parent.getNodeId(); final int defaultCaseId = LASTBuilder.addDefaultCase(this.last, parentId, info); final Branch branch = this.branches.push(new Branch(defaultCaseId, Node.Type.DefaultCase, info)); branch.setWhere(Where.Body); this.processElements(expressions); this.branches.pop(); } protected void addCall(R scope, S function, Iterable arguments, LDASTNodeInfo info) { final T[] arguments0 = this.getArray(arguments); this.addCall(scope, function, arguments0, info); } protected void addCall(R scope, S function, T[] arguments, LDASTNodeInfo info) { final Branch parent = this.branches.peek(); final int parentId = parent.getNodeId(); final Where where = parent.getWhere(); boolean previousLockState = last.getLockState(); final int callId = LASTBuilder.addCall(this.last, parentId, where, info); final Branch branch = this.branches.push(new Branch(callId, Node.Type.Call, info)); branch.setWhere(Where.Scope); if (scope != null) this.processElement(scope, 1, 2); branch.setWhere(Where.Name); if (function != null) this.processElement(function, 2, 2); this.last.unlockSDGid(); branch.setWhere(Where.ArgumentIn); branch.setWhere(Where.Arguments); this.processElements(arguments); branch.setWhere(Where.ArgumentOut); this.branches.pop(); this.last.setLockState(previousLockState); } protected void addListComprehension(Iterable restrictions, S value, LDASTNodeInfo info) { final R[] restrictions0 = this.getArray(restrictions); this.addListComprehension(restrictions0, value, info); } protected void addListComprehension(R[] restrictions, S value, LDASTNodeInfo info) { final Branch parent = this.branches.peek(); final int parentId = parent.getNodeId(); final Where where = parent.getWhere(); final int listComprehensionId = LASTBuilder.addListComprehension(this.last, parentId, where, info); final Branch branch = this.branches.push(new Branch(listComprehensionId, Node.Type.ListComprehension, info)); boolean previousLockState = last.getLockState(); this.last.lockSDGid(); branch.setWhere(Where.Restrictions); this.processElements(restrictions); branch.setWhere(Where.Value); if (value != null) this.processElement(value, 1, 1); this.branches.pop(); this.last.setLockState(previousLockState); } protected void addGenerator(R left, S right, LDASTNodeInfo info) { final Branch parent = this.branches.peek(); final int parentId = parent.getNodeId(); final Where where = parent.getWhere(); final int generatorId = LASTBuilder.addGenerator(this.last, parentId, where, info); this.branches.push(new Branch(generatorId, Node.Type.Generator, info)); if (left != null) this.processElement(left, 1, 2); if (right != null) this.processElement(right, 2, 2); this.branches.pop(); } protected void addFilter(R filter, LDASTNodeInfo info) { final Branch parent = this.branches.peek(); final int parentId = parent.getNodeId(); final Where where = parent.getWhere(); final int filterId = LASTBuilder.addFilter(this.last, parentId, where, info); this.branches.push(new Branch(filterId, Node.Type.Filter, info)); this.processElement(filter, 1, 1); this.branches.pop(); } /** Processes a catch expression catch exp. * @param exp The expression inside the catch expression. * @see Node.Type#Catch */ protected void addCatch(Object exp, LDASTNodeInfo info) { final Branch parent = this.branches.peek(); final int id = LASTBuilder.addCatch(this.last, parent.getNodeId(), parent.getWhere(), info); this.branches.push(new Branch(id, Node.Type.Catch, info)); processElement(exp, 1, 1); this.branches.pop(); } protected void addBin(Iterable binElements, LDASTNodeInfo info) { final R[] elements0 = this.getArray(binElements); this.addBin(elements0, info); } protected void addBin(R[] exp, LDASTNodeInfo info) { final Branch parent = this.branches.peek(); final int id = LASTBuilder.addBin(this.last, parent.getNodeId(), parent.getWhere(), info); this.branches.push(new Branch(id, Node.Type.Bin, info)); this.processElements(exp); this.branches.pop(); } protected void addBinElement(Object exp, LDASTNodeInfo info) { final Branch parent = this.branches.peek(); final int id = LASTBuilder.addBinElement(this.last, parent.getNodeId(), parent.getWhere(), info); this.branches.push(new Branch(id, Node.Type.BinElement, info)); processElement(exp, 1, 1); this.branches.pop(); } protected void addMap(Object[] exp, LDASTNodeInfo info) { final Branch parent = this.branches.peek(); final int id = LASTBuilder.addMap(this.last, parent.getNodeId(), parent.getWhere(), info); this.branches.push(new Branch(id, Node.Type.Map, info)); processElements(exp); this.branches.pop(); } protected void addMap(Object name, Object[] exp, LDASTNodeInfo info) { final Branch parent = this.branches.peek(); final int id = LASTBuilder.addMap(this.last, parent.getNodeId(), parent.getWhere(), info); this.branches.push(new Branch(id, Node.Type.Map, info)); processElement(name, 1, exp.length + 1); for (int i = 0; i < exp.length; i++) processElement(exp[i], i, exp.length + 1); this.branches.pop(); } protected void addMapFieldAssoc(Object exp, LDASTNodeInfo info) { final Branch parent = this.branches.peek(); final int id = LASTBuilder.addMapFieldAssoc(this.last, parent.getNodeId(), parent.getWhere(), info); this.branches.push(new Branch(id, Node.Type.MapFieldAssoc, info)); processElement(exp, 1, 1); this.branches.pop(); } protected void addMapFieldExact(Object exp1, Object exp2, LDASTNodeInfo info) { final Branch parent = this.branches.peek(); final int id = LASTBuilder.addMapFieldExact(this.last, parent.getNodeId(), parent.getWhere(), info); this.branches.push(new Branch(id, Node.Type.MapFieldAssoc, info)); processElement(exp1, 1, 2); processElement(exp2, 2, 2); this.branches.pop(); } protected void addRecord(Object[] fields, LDASTNodeInfo info) { final Branch parent = this.branches.peek(); final int id = LASTBuilder.addRecord(this.last, parent.getNodeId(), parent.getWhere(), info); this.branches.push(new Branch(id, Node.Type.Record, info)); for (int i = 0; i < fields.length; i++) processElement(fields[i], i + 1, fields.length); this.branches.pop(); } protected void addRecord(Object name, Object[] fields, LDASTNodeInfo info) { final Branch parent = this.branches.peek(); final int id = LASTBuilder.addRecord(this.last, parent.getNodeId(), parent.getWhere(), info); this.branches.push(new Branch(id, Node.Type.Record, info)); processElement(name, 1, fields.length + 1); for (int i = 0; i < fields.length; i++) processElement(fields[i], i + 2, fields.length + 1); this.branches.pop(); } protected void addRecordField(Object name, Object value, LDASTNodeInfo info) { final Branch parent = this.branches.peek(); final int id = LASTBuilder.addRecordField(this.last, parent.getNodeId(), parent.getWhere(), info); this.branches.push(new Branch(id, Node.Type.RecordField, info)); processElement(name, 1, 2); processElement(value, 2, 2); this.branches.pop(); } protected void addRecordAccess(Object name, Object value1, Object value2, LDASTNodeInfo info) { final Branch parent = this.branches.peek(); final int id = LASTBuilder.addRecordAccess(this.last, parent.getNodeId(), parent.getWhere(), info); this.branches.push(new Branch(id, Node.Type.RecordAccess, info)); processElement(name, 1, 3); processElement(value1, 2, 3); processElement(value2, 3, 3); this.branches.pop(); } protected void addRecordIndex(Object name, Object assign, LDASTNodeInfo info) { final int id = LASTBuilder.addRecordIndex(last, branches.peek().getNodeId(), branches.peek().getWhere(), info); branches.push(new Branch(id, Node.Type.RecordIndex, info)); processElement(name, 1, 2); processElement(assign, 2, 2); branches.pop(); } protected void addTry(T[] tryBody, T[] tryClauses, R catchClauses, T[] afterBody, LDASTNodeInfo info, LDASTNodeInfo tryInfo, LDASTNodeInfo catchInfo, BiConsumer catchClauseHandler) { int id = LASTBuilder.addTryCatch(last, branches.peek().getNodeId(), branches.peek().getWhere(), info); Node node = last.getNode(id); branches.push(new Branch(node)); Node tryNode = LASTBuilder.addNode(last, node, Node.Type.Try, "try", tryInfo); branches.push(new Branch(tryNode)); branches.peek().setWhere(Where.Body); processElements(tryBody); branches.peek().setWhere(Where.Cases); processElements(tryClauses); branches.pop(); Node catchNode = LASTBuilder.addNode(last, node, Node.Type.Catch, "catch", catchInfo); branches.push(new Branch(catchNode)); catchClauseHandler.accept(catchNode, catchClauses); branches.pop(); Node afterNode = LASTBuilder.addNode(last, node, Node.Type.AfterTry, "after_try", info); branches.push(new Branch(afterNode)); processElements(afterBody); branches.pop(); branches.pop(); } // LOOPS protected void addForLoop(Iterable initialization, R condition, Iterable bodyExpressions, Iterable update, LDASTNodeInfo info) { final T[] initExpressions = this.getArray(initialization); final S[] bodyExpressions0 = this.getArray(bodyExpressions); final T[] updateExpressions = this.getArray(update); this.addForLoop(initExpressions, condition, bodyExpressions0, updateExpressions, info); } protected void addForLoop(T[] initExpressions, R condition, S[] bodyExpressions, T[] updateExpressions, LDASTNodeInfo info) { final Branch parent = this.branches.peek(); final int parentId = parent.getNodeId(); final Where where = parent.getWhere(); final int loopId = LASTBuilder.addForLoop(this.last, parentId, where, info, true); final Branch branch = this.branches.push(new Branch(loopId, Node.Type.FLoop, info)); branch.setWhere(Where.Init); this.processElements(initExpressions); branch.setWhere(Where.Condition); this.processElement(condition, 1, 1); branch.setWhere(Where.Body); this.processElements(bodyExpressions); branch.setWhere(Where.Update); this.processElements(updateExpressions); this.branches.pop(); } protected void addCondLoop(R condition, Iterable bodyExpressions, LDASTNodeInfo info) { final S[] bodyExpressions0 = this.getArray(bodyExpressions); this.addCondLoop(condition, bodyExpressions0, info); } protected void addCondLoop(R condition, S[] bodyExpressions, LDASTNodeInfo info) { final Branch parent = this.branches.peek(); final int parentId = parent.getNodeId(); final Where where = parent.getWhere(); final int loopId = LASTBuilder.addCondLoop(this.last, parentId, where, info, false); final Branch branch = this.branches.push(new Branch(loopId, Node.Type.CLoop, info)); branch.setWhere(Where.Condition); this.processElement(condition, 1, 1); branch.setWhere(Where.Body); this.processElements(bodyExpressions); this.branches.pop(); } protected void addRepeatLoop(R condition, Iterable bodyExpressions, LDASTNodeInfo info) { final S[] bodyExpressions0 = this.getArray(bodyExpressions); this.addRepeatLoop(condition, bodyExpressions0, info); } protected void addRepeatLoop(R condition, S[] bodyExpressions, LDASTNodeInfo info) { final Branch parent = this.branches.peek(); final int parentId = parent.getNodeId(); final Where where = parent.getWhere(); final int loopId = LASTBuilder.addRepeatLoop(this.last, parentId, where, info, false); final Branch branch = this.branches.push(new Branch(loopId, Node.Type.RLoop, info)); branch.setWhere(Where.Body); this.processElements(bodyExpressions); branch.setWhere(Where.Condition); this.processElement(condition, 1, 1); this.branches.pop(); } protected void addForeach(R varDeclaration, S iterableExpr, Iterable bodyExpressions, LDASTNodeInfo info) { final T[] bodyExpressions0 = this.getArray(bodyExpressions); this.addForeach(varDeclaration, iterableExpr, bodyExpressions0, info); } protected void addForeach(R varDeclaration, S iterableExpr, T[] bodyExpressions, LDASTNodeInfo info) { final Branch parent = this.branches.peek(); final int parentId = parent.getNodeId(); final Where where = parent.getWhere(); final int foreachId = LASTBuilder.addForeach(this.last, parentId, where, info); final Branch branch = this.branches.push(new Branch(foreachId, Node.Type.Foreach, info)); branch.setWhere(Where.Iterator); this.addGenerator(varDeclaration, iterableExpr, info); branch.setWhere(Where.Body); this.processElements(bodyExpressions); this.branches.pop(); } protected void addReturn(R expression, int dstId, LDASTNodeInfo info) { final Branch parent = this.branches.peek(); final int parentId = parent.getNodeId(); final Where where = parent.getWhere(); final int returnId = LASTBuilder.addReturn(this.last, parentId, where, dstId, info); this.branches.push(new Branch(returnId, Node.Type.Return, info)); if (expression != null) this.processElement(expression, 1, 1); this.branches.pop(); } protected void addBreak(int dstId, LDASTNodeInfo info) { final Branch parent = this.branches.peek(); final int parentId = parent.getNodeId(); final Where where = parent.getWhere(); LASTBuilder.addBreak(this.last, parentId, where, dstId, info); } protected void addContinue(int dstId, String labelText, LDASTNodeInfo info) { final Branch parent = this.branches.peek(); final int parentId = parent.getNodeId(); final Where where = parent.getWhere(); final int continueId = LASTBuilder.addContinue(this.last, parentId, where, dstId, info); if(dstId == -1) { final List unresolvedContinues = unresolvedLabels.get(labelText); final List continueList = new LinkedList(); if(unresolvedContinues != null) continueList.addAll(unresolvedContinues); continueList.add(continueId); unresolvedLabels.put(labelText, continueList); } } // Exceptions protected void addExHandler(Iterable tryExpressions, Iterable catchClauses, Iterable finallyExpressions, LDASTNodeInfo info) { final R[] tryExpressions0 = this.getArray(tryExpressions); final S[] catchClauses0 = this.getArray(catchClauses); final T[] finallyExpressions0 = this.getArray(finallyExpressions); this.addExHandler(tryExpressions0, catchClauses0, finallyExpressions0, info); } protected void addExHandler(R[] tryExpressions, S[] catchClauses, T[] finallyExpressions, LDASTNodeInfo info) { final Branch parent = this.branches.peek(); final int parentId = parent.getNodeId(); final Where where = parent.getWhere(); final int tryId = LASTBuilder.addExHandler(this.last, parentId, where, info); final Branch branch = this.branches.push(new Branch(tryId, Node.Type.ExHandler, info)); branch.setWhere(Where.Try); this.processElements(tryExpressions); branch.setWhere(Where.Catch); this.processElements(catchClauses); branch.setWhere(Where.Finally); this.processElements(finallyExpressions); this.branches.pop(); } protected void addCatchClause(R parameter, S guard, Iterable catchBlock, LDASTNodeInfo info) { final T[] catchBlock0 = this.getArray(catchBlock); this.addCatchClause(parameter, guard, catchBlock0, info); } protected void addCatchClause(R parameter, S guard, T[] catchBlock, LDASTNodeInfo info) { final Branch parent = this.branches.peek(); final int parentId = parent.getNodeId(); final Where where = parent.getWhere(); final int catchClauseId = LASTBuilder.addCatchClause(this.last, parentId, where, info); final Branch branch = this.branches.push(new Branch(catchClauseId, Node.Type.CatchClause, info)); branch.setWhere(Where.Parameters); this.processElement(parameter,1,1); branch.setWhere(Where.Guard); this.processElement(guard, 1, 1); branch.setWhere(Where.Body); this.processElements(catchBlock); this.branches.pop(); } protected void addThrow(R expression, LDASTNodeInfo info) { final Branch parent = this.branches.peek(); final int parentId = parent.getNodeId(); final Where where = parent.getWhere(); final int throwId = LASTBuilder.addThrow(this.last, parentId, where, info); this.branches.push(new Branch(throwId, Node.Type.Throw, info)); this.processElement(expression,1,1); this.branches.pop(); } // Reference protected void addReference(String value, LDASTNodeInfo info) { final Branch parent = this.branches.peek(); final int parentId = parent.getNodeId(); final Where where = parent.getWhere(); LASTBuilder.addReference(this.last, parentId, where, value, info); } protected void addLabel(String labelText, R labeledExpr, LDASTNodeInfo info) { final Branch parent = this.branches.peek(); final int parentId = parent.getNodeId(); final Where where = parent.getWhere(); final int labelId = LASTBuilder.addLabel(this.last, parentId, where, labelText, info); currentLabels.put(labelText, labelId); resolveLabel(labelText, labelId); this.branches.push(new Branch(labelId, Node.Type.Label, info)); this.processElement(labeledExpr,1,1); this.branches.pop(); } @SuppressWarnings("unchecked") private R[] getArray(Iterable iterable) { final List list = new LinkedList(); for (R element : iterable) list.add(element); return (R[]) list.toArray(); } private boolean isPatternZone(List ancestors) { for (int ancestorIndex = ancestors.size() - 1; ancestorIndex >= 0; ancestorIndex--) { final Branch ancestor = ancestors.get(ancestorIndex); final Node.Type type = ancestor.getNodeType(); final Where where = ancestor.getWhere(); final int index = ancestor.getIndex(); switch (type) { case Clause: if (where == Where.Parameters) return true; break; case Case: if (where == Where.Selectable) return true; break; case Equality: case Generator: if (index == 1) return true; break; default: break; } } return false; } private void resolveLabel(String labelText, Integer jumpId) { if (!unresolvedLabels.containsKey(labelText)) return; final List unresolvedIds = unresolvedLabels.get(labelText); for (Integer id : unresolvedIds) { Node jumpNode = last.getNode(id); jumpNode.setName("continue "+jumpId); } } public static class Branch { private final int nodeId; private final Node.Type nodeType; private final LDASTNodeInfo ldNodeInfo; private Where where; private int index; private int length; public Branch(int nodeId, Node.Type nodeType, LDASTNodeInfo ldNodeInfo) { this.nodeId = nodeId; this.nodeType = nodeType; this.ldNodeInfo = ldNodeInfo; } public Branch(Node node) { this(node.getId(), node.getType(), node.getInfo()); } public int getNodeId() { return this.nodeId; } public Node.Type getNodeType() { return this.nodeType; } public LDASTNodeInfo getLdASTNodeInfo() { return this.ldNodeInfo; } public Where getWhere() { return this.where; } public int getIndex() { return this.index; } public int getLength() { return this.length; } public void setWhere(Where where) { this.where = where; } public void setIndex(int index) { this.index = index; } public void setLength(int length) { this.length = length; } } }