package generators; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.Stack; import code.ast.Block; import code.ast.CompilationUnit; import code.ast.FieldDeclaration; import code.ast.MethodDeclaration; import code.ast.TypeDeclaration; import code.ast.VariableDeclaration; import models.Edge; import models.Node; import models.algebra.Constant; import models.algebra.Expression; import models.algebra.Field; import models.algebra.Parameter; import models.algebra.Symbol; import models.algebra.Term; import models.algebra.Type; import models.algebra.Variable; import models.dataConstraintModel.Channel; import models.dataConstraintModel.ChannelMember; import models.dataConstraintModel.DataConstraintModel; import models.dataConstraintModel.ResourceHierarchy; import models.dataConstraintModel.ResourcePath; import models.dataConstraintModel.Selector; import models.dataFlowModel.ChannelNode; import models.dataFlowModel.DataFlowEdge; import models.dataFlowModel.DataFlowGraph; import models.dataFlowModel.DataTransferChannel; import models.dataFlowModel.DataTransferModel; import models.dataFlowModel.PushPullAttribute; import models.dataFlowModel.PushPullValue; import models.dataFlowModel.ResourceNode; import models.dataFlowModel.DataTransferChannel.IResourceStateAccessor; /** * Common generator for prototypes * * @author Nitta * */ public abstract class CodeGenerator { public static final String fieldOfResourceState = "value"; public static final String getterPrefix = "get"; public static final String getterOfResourceState = "getValue"; public static final String updateMethodPrefix = "update"; public static final String from = "From"; public static final String _for = "For"; private static String mainTypeName = null; private static ILanguageSpecific langSpec = null; public static String getMainTypeName() { return mainTypeName; } public static void setMainTypeName(String mainTypeName) { CodeGenerator.mainTypeName = mainTypeName; } public static void resetMainTypeName() { CodeGenerator.mainTypeName = null; } public static String getComponentName(ResourceHierarchy res, ILanguageSpecific langSpec) { String name = res.getResourceName(); if (res.getNumParameters() > 0) { if (name.length() > 3 && name.endsWith("ies")) { name = name.substring(0, name.length() - 3) + "y"; } else if (name.length() > 1 && name.endsWith("s")) { name = name.substring(0, name.length() - 1); } else { name += "Element"; } } return langSpec.toComponentName(name); } public static Type getImplStateType(ResourceHierarchy res, ILanguageSpecific langSpec) { Set<ResourceHierarchy> children = res.getChildren(); if (children == null || children.size() == 0) { // leaf resource. return res.getResourceStateType(); } else { ResourceHierarchy child = children.iterator().next(); if (children.size() == 1 && child.getNumParameters() > 0) { // map or list. if (DataConstraintModel.typeList.isAncestorOf(res.getResourceStateType())) { // list. if (generatesComponent(child)) { return langSpec.newListType(getComponentName(child, langSpec)); } else { return langSpec.newListType(getImplStateType(child, langSpec).getInterfaceTypeName()); } } else if (DataConstraintModel.typeMap.isAncestorOf(res.getResourceStateType())) { // map. if (generatesComponent(child)) { return langSpec.newMapType(DataConstraintModel.typeString, getComponentName(child, langSpec)); } else { return langSpec.newMapType(DataConstraintModel.typeString, getImplStateType(child, langSpec).getInterfaceTypeName()); } } return null; } else { // class return res.getResourceStateType(); } } } public static boolean generatesComponent(ResourceHierarchy res) { if (res.getParent() == null) return true; if (res.getChildren() == null || res.getChildren().size() == 0) return false; if (res.getNumParameters() > 0 && res.getChildren().size() == 1 && res.getChildren().iterator().next().getNumParameters() > 0) return false; return true; // return res.getParent() == null || !(res.getChildren() == null || res.getChildren().size() == 0); } /** * Generate source codes in specified language from data-flow/control-flow graph. * * @param model architecture model * @param flowGraph data-flow or control-flow graph * @param langSpec specified language * @return source codes */ 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, dependedRootComponentGraph); // Add the main component. if (mainTypeName == null) { mainTypeName = langSpec.getMainComponentName(); } TypeDeclaration mainComponent = langSpec.newTypeDeclaration(mainTypeName); MethodDeclaration mainConstructor = mainComponent.createConstructor(); CompilationUnit mainCU = langSpec.newCompilationUnit(mainComponent); codes.add(mainCU); // Generate the other components. generateCodeFromFlowGraph(model, flowGraph, components, dependedRootComponentGraph, mainComponent, mainConstructor, codes, langSpec); return codes; } 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 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(resNode, allNodes, dependedRootComponentGraph, visited, objects); } return objects; } 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 // 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((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((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; } if (cn != null) { for (Node n: allNodes) { ResourceNode resNode = null; if (n instanceof ResourceNode) { resNode = (ResourceNode) n; } if (resNode != null) { for (Edge resToCh: resNode.getOutEdges()) { ChannelNode chNode = (ChannelNode) resToCh.getDestination(); for (ChannelMember m: chNode.getChannel().getReferenceChannelMembers()) { if (curResNode.getOutSideResources().contains(m.getResource())) { topologicalSort(resNode, allNodes, dependedRootComponentGraph, visited, orderedList); } } } } } } orderedList.add(0, curResNode); } protected void updateMainComponent(TypeDeclaration mainType, MethodDeclaration mainConstructor, Node componentNode, MethodDeclaration constructor, 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) { resNode = (ResourceNode) componentNode; nodeName = resNode.getResourceName(); } String componentName = langSpec.toComponentName(nodeName); // Declare a field to refer each object. if (langSpec.declareField()) { FieldDeclaration refField = langSpec.newFieldDeclaration(new Type(componentName, componentName), nodeName); mainType.addField(refField); } // Add a statement to instantiate each object to the main constructor. List<String> parameters = new ArrayList<>(); for (ResourceHierarchy res: depends) { parameters.add(res.getResourceName()); } if (constructor.getParameters() != null) { for (VariableDeclaration var: constructor.getParameters()) { parameters.add(var.getName()); } } Block mainConstructorBody = mainConstructor.getBody(); if (mainConstructorBody == null) { mainConstructorBody = new Block(); mainConstructor.setBody(mainConstructorBody); } mainConstructorBody.addStatement(langSpec.getFieldAccessor(nodeName) + langSpec.getAssignment() + langSpec.getConstructorInvocation(componentName, parameters) + langSpec.getStatementDelimiter()); } protected ResourceHierarchy addReference(TypeDeclaration component, MethodDeclaration constructor, ResourceHierarchy dstRes, ILanguageSpecific langSpec) { if (!generatesComponent(dstRes)) { dstRes = dstRes.getParent(); } String dstComponentName = getComponentName(dstRes, langSpec); if (dstComponentName != null) { String dstNodeName = langSpec.toVariableName(dstComponentName); if (langSpec.declareField()) { // Declare a field to refer to another component. component.addField(langSpec.newFieldDeclaration(new Type(dstComponentName, dstComponentName), dstNodeName)); } // Initialize the field to refer to another component. constructor.addParameter(langSpec.newVariableDeclaration(new Type(dstComponentName, dstComponentName), dstNodeName)); constructor.getBody().addStatement(langSpec.getFieldAccessor(dstNodeName) + langSpec.getAssignment() + dstNodeName + langSpec.getStatementDelimiter()); } return dstRes; } protected void fillStateGetterMethod(MethodDeclaration stateGetter, ResourceHierarchy resourceHierarchy, Type resStateType, ILanguageSpecific langSpec) { // returns the state field when all incoming data-flow edges are PUSH-style. if (langSpec.isValueType(resStateType)) { stateGetter.addStatement(langSpec.getReturnStatement(langSpec.getFieldAccessor(fieldOfResourceState)) + langSpec.getStatementDelimiter()); // return value; } else { if (resourceHierarchy.getChildren() != null && resourceHierarchy.getChildren().size() == 1 && resourceHierarchy.getChildren().iterator().next().getNumParameters() > 0) { // list or map String implTypeName = resStateType.getImplementationTypeName(); // copy the current state to be returned as a 'value' List<String> parameters = new ArrayList<>(); parameters.add(langSpec.getFieldAccessor(fieldOfResourceState)); stateGetter.addStatement(langSpec.getReturnStatement(langSpec.getConstructorInvocation(implTypeName, parameters)) + langSpec.getStatementDelimiter()); // return new Resource(value); } else { if (resourceHierarchy.getChildren() == null || resourceHierarchy.getChildren().size() == 0) { // a leaf resource String implTypeName = resStateType.getImplementationTypeName(); // copy the current state to be returned as a 'value' List<String> parameters = new ArrayList<>(); parameters.add(langSpec.getFieldAccessor(fieldOfResourceState)); stateGetter.addStatement(langSpec.getReturnStatement(langSpec.getConstructorInvocation(implTypeName, parameters)) + langSpec.getStatementDelimiter()); // return new Resource(value); } else { Term composer = null; Term composerSub = new Constant(DataConstraintModel.nil); composerSub.setType(DataConstraintModel.typeMap); for (ResourceHierarchy child: resourceHierarchy.getChildren()) { String childTypeName = getComponentName(child, langSpec); 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 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))); } composer = new Term(DataConstraintModel.insert); composer.addChild(composerSub); composer.addChild(new Constant(fieldName, DataConstraintModel.typeString)); // key composer.addChild(childGetter); // value composer.setType(DataConstraintModel.typeMap); composerSub = composer; } composer.setType(stateGetter.getReturnType()); String[] sideEffects = new String[] {null}; String returnValue = composer.toImplementation(sideEffects); if (sideEffects[0] != null) { stateGetter.addStatement(sideEffects[0] + langSpec.getReturnStatement(returnValue) + langSpec.getStatementDelimiter()); } else { stateGetter.addStatement(langSpec.getReturnStatement(returnValue) + langSpec.getStatementDelimiter()); } } } } } protected void fillDescendantGetterMethod(MethodDeclaration descendantGetter, ResourceHierarchy descendant, ResourceHierarchy ancestor, TypeDeclaration ancestorComponent, ILanguageSpecific langSpec) { Expression selector; if (DataConstraintModel.typeList.isAncestorOf(ancestor.getResourceStateType())) { selector = new Variable(langSpec.getFieldAccessor(fieldOfResourceState)); } else if (DataConstraintModel.typeMap.isAncestorOf(ancestor.getResourceStateType())) { selector = new Variable(langSpec.getFieldAccessor(fieldOfResourceState)); } else { String fieldName = langSpec.toVariableName(getComponentName(descendant, langSpec)); selector = new Variable(langSpec.getFieldAccessor(fieldName)); } if (descendantGetter.getParameters() != null) { for (VariableDeclaration param: descendantGetter.getParameters()) { if (DataConstraintModel.typeInt.isAncestorOf(param.getType())) { Term newSelector = new Term(DataConstraintModel.get); newSelector.addChild(selector); newSelector.addChild(new Variable(param.getName())); selector = newSelector; } else if (DataConstraintModel.typeString.isAncestorOf(param.getType())) { Term newSelector = new Term(DataConstraintModel.lookup); newSelector.addChild(selector); newSelector.addChild(new Variable(param.getName())); selector = newSelector; } } } if (descendantGetter != null && (descendantGetter.getBody() == null || descendantGetter.getBody().getStatements().size() == 0)) { String[] sideEffects = new String[] {null}; String returnValue = selector.toImplementation(sideEffects); if (sideEffects[0] != null) descendantGetter.addStatement(sideEffects[0]); descendantGetter.addStatement(langSpec.getReturnStatement(returnValue) + langSpec.getStatementDelimiter()); } } protected void declareAccessorInMainComponent(TypeDeclaration mainComponent, ResourceNode accessRes, MethodDeclaration stateGetter, ILanguageSpecific langSpec) { List<VariableDeclaration> mainGetterParams = new ArrayList<>(); int v = 1; for (Expression param: accessRes.getPrimaryResourcePath().getPathParams()) { if (param instanceof Variable) { Variable var = (Variable) param; mainGetterParams.add(langSpec.newVariableDeclaration(var.getType(), var.getName())); } else if (param instanceof Term) { Term var = (Term) param; mainGetterParams.add(new VariableDeclaration(var.getType(), "v" + v)); } v++; } MethodDeclaration accessor = null; if (mainGetterParams.size() == 0) { accessor = langSpec.newMethodDeclaration(getterPrefix + getComponentName(accessRes.getResourceHierarchy(), langSpec), getImplStateType(accessRes.getResourceHierarchy(), langSpec)); } else { accessor = langSpec.newMethodDeclaration(getterPrefix + getComponentName(accessRes.getResourceHierarchy(), langSpec), false, getImplStateType(accessRes.getResourceHierarchy(), langSpec), mainGetterParams); } Block block = new Block(); Expression getState = getPullAccessor().getDirectStateAccessorFor(accessRes.getPrimaryResourcePath(), null); block.addStatement(langSpec.getReturnStatement(getState.toImplementation(new String[] {null})) + langSpec.getStatementDelimiter()); // if (stateGetter.getParameters() == null || stateGetter.getParameters().size() == 0) { // block.addStatement(langSpec.getReturnStatement(langSpec.getMethodInvocation(accessRes.getResourceName(), stateGetter.getName())) + langSpec.getStatementDelimiter()); // } else { // List<String> resParams = new ArrayList<>(); // for (VariableDeclaration var: stateGetter.getParameters()) { // resParams.add(var.getName()); // } // block.addStatement(langSpec.getReturnStatement(langSpec.getMethodInvocation(accessRes.getResourceName(), stateGetter.getName(), resParams)) + langSpec.getStatementDelimiter()); // } accessor.setBody(block); mainComponent.addMethod(accessor); } protected void declareFieldsToReferenceResources(DataTransferModel model, ResourceNode resourceNode, TypeDeclaration component, MethodDeclaration constructor, final List<ResourceHierarchy> depends, ILanguageSpecific langSpec) { Set<ResourcePath> refs = new HashSet<>(); for (Channel ch : model.getChannels()) { DataTransferChannel c = (DataTransferChannel) ch; if (resourceNode.getOutSideResource(c) != null) { for (ResourcePath res: c.getReferenceResources()) { if (!refs.contains(res) && !depends.contains(res.getResourceHierarchy())) { refs.add(res); String refResName = langSpec.toComponentName(res.getLeafResourceName()); component.addField(langSpec.newFieldDeclaration(new Type(refResName, refResName), res.getLeafResourceName())); constructor.addParameter(langSpec.newVariableDeclaration(new Type(refResName, refResName), res.getLeafResourceName())); constructor.getBody().addStatement(langSpec.getFieldAccessor(res.getLeafResourceName()) + langSpec.getAssignment() + res.getLeafResourceName() + langSpec.getStatementDelimiter()); } } } } } protected MethodDeclaration getConstructor(TypeDeclaration component) { for (MethodDeclaration m: component.getMethods()) { if (m.isConstructor()) return m; } return null; } protected static List<MethodDeclaration> getGetterMethods(TypeDeclaration component, String resourceName) { List<MethodDeclaration> getters = new ArrayList<>(); for (MethodDeclaration m: component.getMethods()) { if (m.getName().startsWith(getterPrefix + resourceName)) { getters.add(m); } } return getters; } 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); String methodName = updateMethodPrefix; for (ResourceNode rn: passedResoueces) { methodName += langSpec.toComponentName(rn.getResourceName()); } return getMethod(component, methodName); } protected MethodDeclaration getInputMethod(ResourceNode resourceNode, DataTransferChannel ch, TypeDeclaration component) { MethodDeclaration input = null; for (ChannelMember out : ch.getOutputChannelMembers()) { if (resourceNode.getInSideResources().contains(out.getResource())) { Expression message = out.getStateTransition().getMessageExpression(); if (message instanceof Term) { input = getMethod(component, ((Term) message).getSymbol().getImplName()); } else if (message instanceof Variable) { // Declare an input method in this component. input = getMethod(component, ((Variable) message).getName()); } break; } } return input; } protected MethodDeclaration getMethod(TypeDeclaration component, String methodName) { for (MethodDeclaration m: component.getMethods()) { if (m.getName().equals(methodName)) return m; } return null; } protected IResourceStateAccessor getPushAccessor() { return new IResourceStateAccessor() { @Override public Expression getCurrentStateAccessorFor(ChannelMember target, ChannelMember from) { ResourcePath targetRes= target.getResource(); ResourcePath fromRes= from.getResource(); if (targetRes.equals(fromRes)) { return new Field(fieldOfResourceState, targetRes.getResourceStateType() != null ? targetRes.getResourceStateType() : DataConstraintModel.typeInt); } // use the cached value as the current state return new Field(targetRes.getLeafResourceName(), targetRes.getResourceStateType() != null ? targetRes.getResourceStateType() : DataConstraintModel.typeInt); } @Override public Expression getNextStateAccessorFor(ChannelMember target, ChannelMember from) { ResourcePath targerRes= target.getResource(); return new Parameter(targerRes.getLeafResourceName(), targerRes.getResourceStateType() != null ? targerRes.getResourceStateType() : DataConstraintModel.typeInt); } @Override public Expression getDirectStateAccessorFor(ResourcePath targetRes, ResourcePath fromRes) { if (fromRes != null && targetRes.equals(fromRes)) { return new Field(fieldOfResourceState, targetRes.getResourceStateType() != null ? targetRes.getResourceStateType() : DataConstraintModel.typeInt); } // for reference channel member return new Parameter(targetRes.getLeafResourceName(), targetRes.getResourceStateType() != null ? targetRes.getResourceStateType() : DataConstraintModel.typeInt); } }; } protected IResourceStateAccessor getPullAccessor() { return new IResourceStateAccessor() { @Override public Expression getCurrentStateAccessorFor(ChannelMember target, ChannelMember from) { ResourcePath targetRes= target.getResource(); if (from != null) { ResourcePath fromRes= from.getResource(); if (!target.isOutside()) { return getDirectStateAccessorFor(targetRes, fromRes); } Term getter = null; String targetComponentName = getComponentName(targetRes.getResourceHierarchy(), langSpec); if (generatesComponent(targetRes.getResourceHierarchy())) { getter = new Term(new Symbol(getterOfResourceState, 1, Symbol.Type.METHOD)); getter.addChild(new Field(langSpec.toVariableName(targetComponentName), targetRes.getResourceStateType())); } else { String parentName = langSpec.toVariableName(getComponentName(targetRes.getResourceHierarchy().getParent(), langSpec)); Type parentType = targetRes.getResourceHierarchy().getParent().getResourceStateType(); getter = new Term(new Symbol(getterPrefix + targetComponentName, 1, Symbol.Type.METHOD)); getter.addChild(new Field(parentName, parentType)); } return getter; } else { return getDirectStateAccessorFor(targetRes, null); } } @Override public Expression getNextStateAccessorFor(ChannelMember target, ChannelMember from) { ResourcePath targetRes= target.getResource(); if (from != null) { ResourcePath fromRes= from.getResource(); if (!target.isOutside()) { return getDirectStateAccessorFor(targetRes, fromRes); } Term getter = null; String targetComponentName = getComponentName(targetRes.getResourceHierarchy(), langSpec); if (generatesComponent(targetRes.getResourceHierarchy())) { getter = new Term(new Symbol(getterOfResourceState, 1, Symbol.Type.METHOD)); getter.addChild(new Field(langSpec.toVariableName(targetComponentName), targetRes.getResourceStateType())); } else { String parentName = langSpec.toVariableName(getComponentName(targetRes.getResourceHierarchy().getParent(), langSpec)); Type parentType = targetRes.getResourceHierarchy().getParent().getResourceStateType(); getter = new Term(new Symbol(getterPrefix + targetComponentName, 1, Symbol.Type.METHOD)); getter.addChild(new Field(parentName, parentType)); } return getter; } else { return getDirectStateAccessorFor(targetRes, null); } } @Override public Expression getDirectStateAccessorFor(ResourcePath targetRes, ResourcePath fromRes) { if (fromRes != null) { if (targetRes.equals(fromRes)) { return new Field(fieldOfResourceState, targetRes.getResourceStateType() != null ? targetRes.getResourceStateType() : DataConstraintModel.typeInt); } // for reference channel member Term getter = new Term(new Symbol(getterOfResourceState, 1, Symbol.Type.METHOD)); getter.addChild(new Field(targetRes.getLeafResourceName(), targetRes.getResourceStateType())); return getter; } else { // access from the outside of the hierarchy Stack<ResourcePath> pathStack = new Stack<>(); ResourcePath curPath = targetRes; do { pathStack.push(curPath); curPath = curPath.getParent(); } while (curPath != null); // iterate from the root resource Term getter = null; int v = 1; int arity = 2; while (!pathStack.empty()) { curPath = pathStack.pop(); String typeName = getComponentName(curPath.getResourceHierarchy(), langSpec); if (getter == null) { // root resource String fieldName = langSpec.toVariableName(typeName); getter = new Field(fieldName, new Type(typeName, typeName)); } else { if (generatesComponent(curPath.getResourceHierarchy())) { if (arity == 2) { Term newGetter = new Term(new Symbol(getterPrefix + typeName, -1, Symbol.Type.METHOD)); newGetter.addChild(getter); if (curPath.getResourceHierarchy().getNumParameters() > 0) { Variable var = null; Expression param = curPath.getLastParam(); if (param instanceof Variable) { var = (Variable) param; } else if (param instanceof Term) { var = new Variable("v" + v, ((Term) param).getType()); } if (var != null) { newGetter.addChild(var); newGetter.getSymbol().setArity(2); } v++; } getter = newGetter; } else { if (curPath.getResourceHierarchy().getNumParameters() > 0) { Variable var = null; Expression param = curPath.getLastParam(); if (param instanceof Variable) { var = (Variable) param; } else if (param instanceof Term) { var = new Variable("v" + v, ((Term) param).getType()); } if (var != null) { getter.getSymbol().setArity(arity); getter.addChild(var); } v++; } } arity = 2; } else { // to get a descendant resource directly. if (arity == 2) { Term newGetter = new Term(new Symbol(getterPrefix + typeName, -1, Symbol.Type.METHOD)); newGetter.addChild(getter); getter = newGetter; } if (curPath.getResourceHierarchy().getNumParameters() > 0) { Variable var = null; Expression param = curPath.getLastParam(); if (param instanceof Variable) { var = (Variable) param; } else if (param instanceof Term) { var = new Variable("v" + v, ((Term) param).getType()); } if (var != null) { getter.getSymbol().setArity(arity); getter.addChild(var); arity++; } v++; } } } } if (generatesComponent(targetRes.getResourceHierarchy())) { Term newGetter = new Term(new Symbol(getterOfResourceState, 1, Symbol.Type.METHOD)); newGetter.addChild(getter); getter = newGetter; } return getter; } } }; } protected IResourceStateAccessor getRefAccessor() { return new IResourceStateAccessor() { @Override public Expression getCurrentStateAccessorFor(ChannelMember target, ChannelMember from) { ResourcePath targetRes= target.getResource(); ResourcePath fromRes= from.getResource(); if (targetRes.equals(fromRes)) { return new Field(fieldOfResourceState, targetRes.getResourceStateType() != null ? targetRes.getResourceStateType() : DataConstraintModel.typeInt); } // use the cached value as the current state return new Parameter(targetRes.getLeafResourceName(), targetRes.getResourceStateType() != null ? targetRes.getResourceStateType() : DataConstraintModel.typeInt); } @Override public Expression getNextStateAccessorFor(ChannelMember target, ChannelMember from) { ResourcePath targerRes= target.getResource(); return new Parameter(targerRes.getLeafResourceName(), targerRes.getResourceStateType() != null ? targerRes.getResourceStateType() : DataConstraintModel.typeInt); } @Override public Expression getDirectStateAccessorFor(ResourcePath targetRes, ResourcePath fromRes) { if (fromRes != null && targetRes.equals(fromRes)) { return new Field(fieldOfResourceState, targetRes.getResourceStateType() != null ? targetRes.getResourceStateType() : DataConstraintModel.typeInt); } // for reference channel member return new Parameter(targetRes.getLeafResourceName(), targetRes.getResourceStateType() != null ? targetRes.getResourceStateType() : DataConstraintModel.typeInt); } }; } }