| |
---|
| | public ArrayList<CompilationUnit> generateCode(DataTransferModel model, DataFlowGraph flowGraph, ILanguageSpecific langSpec) { |
---|
| | CodeGenerator.langSpec = langSpec; |
---|
| | ArrayList<CompilationUnit> codes = new ArrayList<>(); |
---|
| | |
---|
| | // Get the dependency among root nodes. |
---|
| | Map<ResourceHierarchy, Set<ResourceHierarchy>> dependedRootComponentGraph = getDependedRootComponentGraph(model); |
---|
| | |
---|
| | // Sort the all components. |
---|
| | ArrayList<ResourceNode> components = determineComponentOrder(flowGraph); |
---|
| | ArrayList<ResourceNode> components = determineComponentOrder(flowGraph, dependedRootComponentGraph); |
---|
| | |
---|
| | // Add the main component. |
---|
| | if (mainTypeName == null) { |
---|
| | mainTypeName = langSpec.getMainComponentName(); |
---|
| |
---|
| | CompilationUnit mainCU = langSpec.newCompilationUnit(mainComponent); |
---|
| | codes.add(mainCU); |
---|
| | |
---|
| | // Generate the other components. |
---|
| | generateCodeFromFlowGraph(model, flowGraph, components, mainComponent, mainConstructor, codes, langSpec); |
---|
| | generateCodeFromFlowGraph(model, flowGraph, components, dependedRootComponentGraph, mainComponent, mainConstructor, codes, langSpec); |
---|
| | |
---|
| | return codes; |
---|
| | } |
---|
| | |
---|
| | public abstract void generateCodeFromFlowGraph(DataTransferModel model, DataFlowGraph flowGraph, ArrayList<ResourceNode> components, |
---|
| | public abstract void generateCodeFromFlowGraph(DataTransferModel model, DataFlowGraph flowGraph, ArrayList<ResourceNode> components, Map<ResourceHierarchy, Set<ResourceHierarchy>> dependedRootComponentGraph, |
---|
| | TypeDeclaration mainComponent, MethodDeclaration mainConstructor, ArrayList<CompilationUnit> codes, ILanguageSpecific langSpec); |
---|
| | |
---|
| | private static ArrayList<ResourceNode> determineComponentOrder(DataFlowGraph graph) { |
---|
| | private static Map<ResourceHierarchy, Set<ResourceHierarchy>> getDependedRootComponentGraph(DataTransferModel model) { |
---|
| | Map<ResourceHierarchy, Set<ResourceHierarchy>> dependedComponentGraph = new HashMap<>(); |
---|
| | for (Channel ch: model.getChannels()) { |
---|
| | DataTransferChannel dtCh = (DataTransferChannel) ch; |
---|
| | Set<ResourceHierarchy> inRes = new HashSet<>(); |
---|
| | Set<ResourceHierarchy> outRes = new HashSet<>(); |
---|
| | for (ChannelMember cm: dtCh.getChannelMembers()) { |
---|
| | if (cm.isOutside()) { |
---|
| | outRes.add(cm.getResource().getResourceHierarchy()); |
---|
| | } else { |
---|
| | inRes.add(cm.getResource().getResourceHierarchy()); |
---|
| | } |
---|
| | } |
---|
| | if (outRes.size() > 0 && inRes.size() > 0) { |
---|
| | for (ResourceHierarchy out: outRes) { |
---|
| | for (ResourceHierarchy in: inRes) { |
---|
| | Set<ResourceHierarchy> dependings = dependedComponentGraph.get(out.getRoot()); |
---|
| | if (dependings == null) { |
---|
| | dependings = new HashSet<>(); |
---|
| | dependedComponentGraph.put(out.getRoot(), dependings); |
---|
| | } |
---|
| | dependings.add(in.getRoot()); |
---|
| | } |
---|
| | } |
---|
| | } |
---|
| | } |
---|
| | return dependedComponentGraph; |
---|
| | } |
---|
| | |
---|
| | private static ArrayList<ResourceNode> determineComponentOrder(DataFlowGraph graph, Map<ResourceHierarchy, Set<ResourceHierarchy>> dependedRootComponentGraph) { |
---|
| | ArrayList<ResourceNode> objects = new ArrayList<>(); |
---|
| | Set<ResourceNode> visited = new HashSet<>(); |
---|
| | Collection<ResourceNode> allNodes = graph.getResourceNodes(); |
---|
| | for (ResourceNode resNode: allNodes) { |
---|
| | topologicalSort(allNodes, resNode, visited, objects); |
---|
| | topologicalSort(resNode, allNodes, dependedRootComponentGraph, visited, objects); |
---|
| | } |
---|
| | return objects; |
---|
| | } |
---|
| | |
---|
| | private static void topologicalSort(Collection<ResourceNode> allNodes, ResourceNode curResNode, Set<ResourceNode> visited, List<ResourceNode> orderedList) { |
---|
| | private static void topologicalSort(ResourceNode curResNode, Collection<ResourceNode> allNodes, Map<ResourceHierarchy, Set<ResourceHierarchy>> dependedRootComponentGraph, Set<ResourceNode> visited, List<ResourceNode> orderedList) { |
---|
| | if (visited.contains(curResNode)) return; |
---|
| | visited.add(curResNode); |
---|
| | // a caller is before the callee |
---|
| | // A caller is before the callee |
---|
| | |
---|
| | // For each incoming PUSH transfer. |
---|
| | for (Edge chToRes: curResNode.getInEdges()) { |
---|
| | for (Edge resToCh: chToRes.getSource().getInEdges()) { |
---|
| | if (!(resToCh instanceof DataFlowEdge) || ((PushPullAttribute)((DataFlowEdge) resToCh).getAttribute()).getOptions().get(0) == PushPullValue.PUSH) { |
---|
| | topologicalSort(allNodes, (ResourceNode) resToCh.getSource(), visited, orderedList); |
---|
| | } |
---|
| | } |
---|
| | } |
---|
| | topologicalSort((ResourceNode) resToCh.getSource(), allNodes, dependedRootComponentGraph, visited, orderedList); |
---|
| | } |
---|
| | } |
---|
| | } |
---|
| | // For each outgoing PULL transfer. |
---|
| | if (curResNode instanceof ResourceNode) { |
---|
| | for (Edge resToCh: curResNode.getOutEdges()) { |
---|
| | DataFlowEdge de = (DataFlowEdge) resToCh; |
---|
| | if (((PushPullAttribute) de.getAttribute()).getOptions().get(0) != PushPullValue.PUSH) { |
---|
| | for (Edge chToRes : resToCh.getDestination().getOutEdges()) { |
---|
| | topologicalSort(allNodes, (ResourceNode) chToRes.getDestination(), visited, orderedList); |
---|
| | } |
---|
| | } |
---|
| | } |
---|
| | } |
---|
| | // For reference resources. |
---|
| | topologicalSort((ResourceNode) chToRes.getDestination(), allNodes, dependedRootComponentGraph, visited, orderedList); |
---|
| | } |
---|
| | } |
---|
| | } |
---|
| | } |
---|
| | // For each depending root node. |
---|
| | if (curResNode instanceof ResourceNode && dependedRootComponentGraph.get(curResNode.getResourceHierarchy()) != null) { |
---|
| | for (ResourceHierarchy dependingRes: dependedRootComponentGraph.get(curResNode.getResourceHierarchy())) { |
---|
| | for (ResourceNode rootNode: allNodes) { |
---|
| | ResourceHierarchy rootRes = rootNode.getResourceHierarchy(); |
---|
| | if (rootRes.getParent() == null && rootRes.equals(dependingRes)) { |
---|
| | topologicalSort(rootNode, allNodes, dependedRootComponentGraph, visited, orderedList); |
---|
| | } |
---|
| | } |
---|
| | } |
---|
| | } |
---|
| | // For each reference resource. |
---|
| | ResourceNode cn = null; |
---|
| | if (curResNode instanceof ResourceNode) { |
---|
| | cn = (ResourceNode) curResNode; |
---|
| | } |
---|
| |
---|
| | for (Edge resToCh: resNode.getOutEdges()) { |
---|
| | ChannelNode chNode = (ChannelNode) resToCh.getDestination(); |
---|
| | for (ChannelMember m: chNode.getChannel().getReferenceChannelMembers()) { |
---|
| | if (m.getResource().equals(curResNode.getOutSideResource())) { |
---|
| | topologicalSort(allNodes, resNode, visited, orderedList); |
---|
| | topologicalSort(resNode, allNodes, dependedRootComponentGraph, visited, orderedList); |
---|
| | } |
---|
| | } |
---|
| | } |
---|
| | } |
---|
| |
---|
| | orderedList.add(0, curResNode); |
---|
| | } |
---|
| | |
---|
| | protected void updateMainComponent(DataTransferModel model, TypeDeclaration mainType, MethodDeclaration mainConstructor, Node componentNode, |
---|
| | final List<ResourcePath> depends, ILanguageSpecific langSpec) { |
---|
| | final List<ResourceHierarchy> depends, ILanguageSpecific langSpec) { |
---|
| | // Declare the field to refer to each object in the main type. |
---|
| | ResourceNode resNode = null; |
---|
| | String nodeName = null; |
---|
| | if (componentNode instanceof ResourceNode) { |
---|
| |
---|
| | mainType.addField(refField); |
---|
| | } |
---|
| | // Add a statement to instantiate each object to the main constructor. |
---|
| | List<String> parameters = new ArrayList<>(); |
---|
| | for (ResourcePath res: depends) { |
---|
| | for (ResourceHierarchy res: depends) { |
---|
| | // For the callee objects (the destination resource of push transfer or the source resource of pull transfer). |
---|
| | parameters.add(res.getResourceName()); |
---|
| | } |
---|
| | // For the refs. |
---|
| |
---|
| | Set<ResourcePath> refs = new HashSet<>(); |
---|
| | for (Channel cg : model.getChannels()) { |
---|
| | DataTransferChannel ch = (DataTransferChannel) cg; |
---|
| | if (ch.getInputResources().contains(resNode.getOutSideResource())) { |
---|
| | for (ResourcePath id: ch.getReferenceResources()) { |
---|
| | if (!refs.contains(id) && !depends.contains(id)) { |
---|
| | refs.add(id); |
---|
| | String refResName = id.getResourceName(); |
---|
| | for (ResourcePath resPath: ch.getReferenceResources()) { |
---|
| | if (!refs.contains(resPath) && !depends.contains(resPath.getResourceHierarchy())) { |
---|
| | refs.add(resPath); |
---|
| | String refResName = resPath.getResourceName(); |
---|
| | parameters.add(refResName); |
---|
| | } |
---|
| | } |
---|
| | } |
---|
| |
---|
| | } |
---|
| | mainConstructorBody.addStatement(langSpec.getFieldAccessor(nodeName) + langSpec.getAssignment() + langSpec.getConstructorInvocation(componentName, parameters) + langSpec.getStatementDelimiter()); |
---|
| | } |
---|
| | |
---|
| | protected ResourcePath addReference(TypeDeclaration component, MethodDeclaration constructor, ResourcePath dstRes, ILanguageSpecific langSpec) { |
---|
| | if (!generatesComponent(dstRes.getResourceHierarchy())) { |
---|
| | protected ResourceHierarchy addReference(TypeDeclaration component, MethodDeclaration constructor, ResourceHierarchy dstRes, ILanguageSpecific langSpec) { |
---|
| | if (!generatesComponent(dstRes)) { |
---|
| | dstRes = dstRes.getParent(); |
---|
| | } |
---|
| | String dstComponentName = getComponentName(dstRes.getResourceHierarchy(), langSpec); |
---|
| | String dstComponentName = getComponentName(dstRes, langSpec); |
---|
| | if (dstComponentName != null) { |
---|
| | String dstNodeName = langSpec.toVariableName(dstComponentName); |
---|
| | if (langSpec.declareField()) { |
---|
| | // Declare a field to refer to another component. |
---|
| |
---|
| | String fieldName = langSpec.toVariableName(childTypeName); |
---|
| | Term childGetter = null; |
---|
| | if ((child.getChildren() == null || child.getChildren().size() == 0) && child.getNumParameters() == 0) { |
---|
| | // the child is not a class |
---|
| | childGetter = new Field(fieldName, getImplStateType(child, langSpec)); |
---|
| | childGetter = new Term(new Symbol("get" + childTypeName, 1, Symbol.Type.METHOD)); |
---|
| | childGetter.addChild(new Constant("this")); |
---|
| | } else { |
---|
| | // the child is a class |
---|
| | childGetter = new Term(new Symbol(getterOfResourceState, 1, Symbol.Type.METHOD)); |
---|
| | childGetter.addChild(new Field(fieldName, getImplStateType(child, langSpec))); |
---|
| |
---|
| | mainComponent.addMethod(accessor); |
---|
| | } |
---|
| | |
---|
| | protected void declareFieldsToReferenceResources(DataTransferModel model, ResourceNode resourceNode, TypeDeclaration component, MethodDeclaration constructor, |
---|
| | final List<ResourcePath> depends, ILanguageSpecific langSpec) { |
---|
| | final List<ResourceHierarchy> depends, ILanguageSpecific langSpec) { |
---|
| | Set<ResourcePath> refs = new HashSet<>(); |
---|
| | for (Channel ch : model.getChannels()) { |
---|
| | DataTransferChannel c = (DataTransferChannel) ch; |
---|
| | if (c.getInputResources().contains(resourceNode.getOutSideResource())) { |
---|
| | for (ResourcePath res: c.getReferenceResources()) { |
---|
| | if (!refs.contains(res) && !depends.contains(res)) { |
---|
| | if (!refs.contains(res) && !depends.contains(res.getResourceHierarchy())) { |
---|
| | refs.add(res); |
---|
| | String refResName = langSpec.toComponentName(res.getResourceName()); |
---|
| | component.addField(langSpec.newFieldDeclaration(new Type(refResName, refResName), res.getResourceName())); |
---|
| | constructor.addParameter(langSpec.newVariableDeclaration(new Type(refResName, refResName), res.getResourceName())); |
---|
| |
---|
| | } |
---|
| | } |
---|
| | } |
---|
| | } |
---|
| | |
---|
| | protected MethodDeclaration getConstructor(TypeDeclaration component) { |
---|
| | for (MethodDeclaration m: component.getMethods()) { |
---|
| | if (m.isConstructor()) return m; |
---|
| | } |
---|
| | return null; |
---|
| | } |
---|
| | |
---|
| | protected MethodDeclaration getUpdateMethod(Edge inEdge, TypeDeclaration component, |
---|
| | Map<Edge, Map<PushPullValue, List<ResourceNode>>> dataFlowInform, ILanguageSpecific langSpec) { |
---|
| | List<ResourceNode> passedResoueces = dataFlowInform.get(inEdge).get(PushPullValue.PUSH); |
---|
| |
---|
| | |