diff --git a/AlgebraicDataflowArchitectureModel/models/Citrus.model b/AlgebraicDataflowArchitectureModel/models/Citrus.model new file mode 100644 index 0000000..746129c --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/models/Citrus.model @@ -0,0 +1,75 @@ +channel Signup { + out accounts(accDB:Map, signup(aid:Str)) = insert(accDB, aid, {"favorites": nil, "books": nil}) +} + +channel CreateBook(aid:Str) { + out accounts.{aid}.books(bookList:List, createBook(title:Str)) = append(bookList, {"title": title, "todos": nil, "favorited": nil}) +} + +channel DeleteAccount { + out accounts(accDB:Map, deleteAccount(aid:Str)) = if(contains(accDB, aid), delete(accDB, aid), accDB) +} + +channel ChangeAccountName { + out accounts(accDB:Map, changeAccountId(aid:Str, newAid:Str)) = if(aid == newAid, accDB, delete(insert(accDB, newAid, lookup(accDB, aid)), aid)) +} + +channel ChangeBookName(aid:Str, bid:Int) { + out accounts.{aid}.books.{bid}.title(title:Str, changeBookName(newTitle)) = newTitle +} + +channel DeleteBook(aid:Str) { + out accounts.{aid}.books(bookList:List, deleteBook(bid:Int)) = if(bid < length(bookList), remove(bookList, bid), bookList) +} + +channel CreateToDo(aid:Str, bid:Int) { + out accounts.{aid}.books.{bid}.todos(toDoDB:Map, createtodo(year:Str, month:Str, day:Str, title:Str)) = + if( + contains(toDoDB,year), + if( + contains(lookup(toDoDB,year),month), + if( + contains(lookup(lookup(toDoDB,year),month),day), + insert(toDoDB,year,insert(lookup(toDoDB,year),month,insert(lookup(lookup(toDoDB,year),month),day,append(lookup(lookup(lookup(toDoDB,year),month),day),{"title":title,"check":false})))), + insert(toDoDB,year,insert(lookup(toDoDB,year),month,insert(lookup(lookup(toDoDB,year),month),day,append(nil,{"title":title,"check":false})))) + ), + insert(toDoDB,year,insert(lookup(toDoDB,year),month,insert(nil,day,append(nil,{"title":title,"check":false})))) + ), + insert(toDoDB,year,insert(nil,month,insert(nil,day,append(nil,{"title":title,"check":false})))) + ) +} + +channel ChangeToDoName(aid:Str, bid:Int, year:Str, month:Str, day:Str, tid:Int) { + out accounts.{aid}.books.{bid}.todos.{year}.{month}.{day}.{tid}.title(title:Str, changeToDoName(newTitle)) = newTitle +} + +channel ChangeCheck(aid:Str, bid:Int, year:Str, month:Str, day:Str, tid:Int) { + out accounts.{aid}.books.{bid}.todos.{year}.{month}.{day}.{tid}.check(check:Bool, changeCheck(newCheck)) = newCheck +} + +channel DeleteToDo(aid:Str, bid:Int) { + out accounts.{aid}.books.{bid}.todos(toDoDB:Map, deleteToDo(year:Str, month:Str, day:Str, tid:Int)) = insert(toDoDB, + year, + insert(lookup(toDoDB, year), + month, + insert(lookup(lookup(toDoDB, year), month), + day, + remove(lookup(lookup(lookup(toDoDB, year), month), day), + tid)))) +} + +channel AddFavorited(aid:Str, bid:Int) { + out accounts.{aid}.books.{bid}.favorited(faList:List, addFavorited(o_aid:Str)) = if(aid==o_aid, + faList, + if(contains(faList, o_aid), + remove(faList, indexOf(faList, o_aid)), + append(faList, o_aid))) + out accounts.{o_aid}.favorites(aDB:Map, addFavorited(o_aid:Str)) + = if(aid==o_aid, + aDB, + if(contains(aDB, aid), + if(contains(lookup(aDB, aid), bid), + insert(aDB, aid, remove(lookup(aDB, aid), indexOf(lookup(aDB, aid), bid))), + insert(aDB, aid, append(lookup(aDB, aid), bid))), + insert(aDB, aid, append(nil, bid)))) +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/models/NemophilaAccounts.model b/AlgebraicDataflowArchitectureModel/models/NemophilaAccounts.model index c2cc23a..0158d26 100644 --- a/AlgebraicDataflowArchitectureModel/models/NemophilaAccounts.model +++ b/AlgebraicDataflowArchitectureModel/models/NemophilaAccounts.model @@ -36,7 +36,7 @@ out accounts.{sendId}.requesting(sendRequesting:Map, sync1(recvId:Str, sendRequested:Map, recvRequesting:Map, sendFriends:Map)) = if(contains(sendFriends:Map, recvId) == true, sendRequesting, insert(sendRequesting:Map, recvId:Str, true)) - out accounts.{recvId}.requested(recvRequested:Map, sync1(recvId:Str, sendRequested:Map, recvRequesting:Map, sendFriends:Map)) = if(ontains(sendFriends:Map, recvId) == true, + out accounts.{recvId}.requested(recvRequested:Map, sync1(recvId:Str, sendRequested:Map, recvRequesting:Map, sendFriends:Map)) = if(contains(sendFriends:Map, recvId) == true, recvRequested, insert(recvRequested:Map, sendId:Str, true)) } diff --git a/AlgebraicDataflowArchitectureModel/src/algorithms/TypeInference.java b/AlgebraicDataflowArchitectureModel/src/algorithms/TypeInference.java index 1be6a1d..45a82b9 100644 --- a/AlgebraicDataflowArchitectureModel/src/algorithms/TypeInference.java +++ b/AlgebraicDataflowArchitectureModel/src/algorithms/TypeInference.java @@ -379,7 +379,7 @@ } for (Term t : terms) { Symbol symbol = t.getSymbol(); - if (symbol.equals(DataConstraintModel.cons) || symbol.equals(DataConstraintModel.set)) { + if (symbol.equals(DataConstraintModel.cons) || symbol.equals(DataConstraintModel.set) || symbol.equals(DataConstraintModel.append)) { // If the root symbol of the term is cons or set. List consExps = new ArrayList<>(); consExps.add(t); // list term @@ -390,10 +390,18 @@ consExps.add(e); updateExpressionBelonging(expToConsOrSet, e, consExps); } + } else if (symbol.equals(DataConstraintModel.append)) { + // If the root symbol of the term is append. + Expression e = t.getChildren().get(1); + consExps.add(e); // list element + updateExpressionBelonging(expToConsOrSet, e, consExps); + e = t.getChildren().get(0); + consExps.add(e); // list argument + updateExpressionBelonging(expToConsOrSet, e, consExps); } else { // If the root symbol of the term is set. Expression e = t.getChildren().get(2); - consExps.add(e); // list component + consExps.add(e); // list element updateExpressionBelonging(expToConsOrSet, e, consExps); e = t.getChildren().get(0); consExps.add(e); // list argument @@ -401,7 +409,7 @@ } Type newType = getExpTypeIfUpdatable(t.getType(), consExps.get(2)); if (newType != null) { - // If the type of the 2nd argument of cons (1st argument of set) is more concrete than the type of the term. + // If the type of the 2nd argument of cons (1st argument of set/append) is more concrete than the type of the term. t.setType(newType); Map updateCons = getUpdateSet(updateFromConsOrSet, consExps); updateCons.put(System.identityHashCode(t), t); @@ -410,7 +418,7 @@ if (consExps.get(2) != null && consExps.get(2) instanceof Variable) { arg2Type = ((Variable) consExps.get(2)).getType(); if (compareTypes(arg2Type, t.getType())) { - // If the type of the term is more concrete than the type of the 2nd argument of cons (1st argument of set). + // If the type of the term is more concrete than the type of the 2nd argument of cons (1st argument of set/append). ((Variable) consExps.get(2)).setType(t.getType()); Map updateCons = getUpdateSet(updateFromConsOrSet, consExps); updateCons.put(System.identityHashCode(consExps.get(2)), consExps.get(2)); @@ -418,7 +426,7 @@ } else if (consExps.get(2) != null && consExps.get(2) instanceof Term) { arg2Type = ((Term) consExps.get(2)).getType(); if (compareTypes(arg2Type, t.getType())) { - // If the type of the term is more concrete than the type of the 2nd argument of cons (1st argument of set). + // If the type of the term is more concrete than the type of the 2nd argument of cons (1st argument of set/append). ((Term) consExps.get(2)).setType(t.getType()); Map updateCons = getUpdateSet(updateFromConsOrSet, consExps); updateCons.put(System.identityHashCode(consExps.get(2)), consExps.get(2)); @@ -815,6 +823,33 @@ } else { newCompTypeList.add(null); } + Type newTermType = getExpTypeIfUpdatable(termType, mapExps.get(3)); + if (newTermType != null) { + // If the type of the 1st argument of insert is more concrete than the type of the term. + t.setType(newTermType); + termType = newTermType; + Map updateExps = getUpdateSet(updateFromMap, mapExps); + updateExps.put(System.identityHashCode(t), t); + } else { + Type arg3Type = null; + if (mapExps.get(3) != null && mapExps.get(3) instanceof Variable) { + arg3Type = ((Variable) mapExps.get(3)).getType(); + if (compareTypes(arg3Type, t.getType())) { + // If the type of the term is more concrete than the type of the 1st argument of insert. + ((Variable) mapExps.get(3)).setType(t.getType()); + Map updateExps = getUpdateSet(updateFromMap, mapExps); + updateExps.put(System.identityHashCode(mapExps.get(3)), mapExps.get(3)); + } + } else if (mapExps.get(3) != null && mapExps.get(3) instanceof Term) { + arg3Type = ((Term) mapExps.get(3)).getType(); + if (compareTypes(arg3Type, t.getType())) { + // If the type of the term is more concrete than the type of the 1st argument of insert. + ((Term) mapExps.get(3)).setType(t.getType()); + Map updateExps = getUpdateSet(updateFromMap, mapExps); + updateExps.put(System.identityHashCode(mapExps.get(3)), mapExps.get(3)); + } + } + } if (termType == DataConstraintModel.typeMap || termType == null) { Type newMapType = mapTypes.get(newCompTypeList); if (newMapType == null) { @@ -823,9 +858,16 @@ } // Update the type of the map term and record the updated expression. t.setType(newMapType); - termType = newMapType; Map updateExps = getUpdateSet(updateFromMap, mapExps); updateExps.put(System.identityHashCode(t), t); + if (mapExps.get(3) != null && mapExps.get(3) instanceof Variable) { + ((Variable) mapExps.get(3)).setType(newMapType); + updateExps.put(System.identityHashCode(mapExps.get(3)), mapExps.get(3)); + } else if (mapExps.get(3) != null && mapExps.get(3) instanceof Term) { + ((Term) mapExps.get(3)).setType(newMapType); + updateExps.put(System.identityHashCode(mapExps.get(3)), mapExps.get(3)); + } + termType = newMapType; } map.put(System.identityHashCode(mapExps), termType); } else if (symbol.equals(DataConstraintModel.addMember)) { diff --git a/AlgebraicDataflowArchitectureModel/src/application/actions/SaveAsAction.java b/AlgebraicDataflowArchitectureModel/src/application/actions/SaveAsAction.java index 1a38b08..9542cdb 100644 --- a/AlgebraicDataflowArchitectureModel/src/application/actions/SaveAsAction.java +++ b/AlgebraicDataflowArchitectureModel/src/application/actions/SaveAsAction.java @@ -65,9 +65,7 @@ lastDir = fc.getSelectedFile().getParent(); String fileName = fc.getSelectedFile().getAbsolutePath() + extension; - - // checking file duplicates - if(! (fc.getSelectedFile().exists())) editor.setCurFilePath(fileName); + editor.setCurFilePath(fileName); // overwriting file editor.save(); diff --git a/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerator.java b/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerator.java index fe86c0c..2a7db3b 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerator.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerator.java @@ -98,14 +98,14 @@ if (generatesComponent(child)) { return langSpec.newListType(getComponentName(child, langSpec)); } else { - return langSpec.newListType(getImplStateType(child, langSpec).getImplementationTypeName()); + 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).getImplementationTypeName()); + return langSpec.newMapType(DataConstraintModel.typeString, getImplStateType(child, langSpec).getInterfaceTypeName()); } } return null; @@ -117,9 +117,11 @@ } public static boolean generatesComponent(ResourceHierarchy res) { - return res.getParent() == null || !(res.getChildren() == null || res.getChildren().size() == 0); -// Type resType = res.getResourceStateType(); -// return DataConstraintModel.typeJson.isAncestorOf(resType) || DataConstraintModel.typeList.isAncestorOf(resType) || DataConstraintModel.typeMap.isAncestorOf(resType); + 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); } /** @@ -367,29 +369,37 @@ } } - protected void fillChildGetterMethod(MethodDeclaration childGetter, ResourceHierarchy child, Type parentResourceType, ILanguageSpecific langSpec) { - if (DataConstraintModel.typeList.isAncestorOf(parentResourceType)) { - Term selector = new Term(DataConstraintModel.get); - selector.addChild(new Variable(langSpec.getFieldAccessor(fieldOfResourceState))); - selector.addChild(new Variable(childGetter.getParameters().get(childGetter.getParameters().size() - 1).getName())); - selector.setType(childGetter.getReturnType()); - String[] sideEffects = new String[] {null}; - String returnValue = selector.toImplementation(sideEffects); - if (sideEffects[0] != null) childGetter.addStatement(sideEffects[0]); - childGetter.addStatement(langSpec.getReturnStatement(returnValue) + langSpec.getStatementDelimiter()); - } else if (DataConstraintModel.typeMap.isAncestorOf(parentResourceType)) { - Term selector = new Term(DataConstraintModel.lookup); - selector.addChild(new Variable(langSpec.getFieldAccessor(fieldOfResourceState))); - selector.addChild(new Variable(childGetter.getParameters().get(childGetter.getParameters().size() - 1).getName())); - selector.setType(childGetter.getReturnType()); - String[] sideEffects = new String[] {null}; - String returnValue = selector.toImplementation(sideEffects); - if (sideEffects[0] != null) childGetter.addStatement(sideEffects[0]); - childGetter.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(child, langSpec)); - childGetter.addStatement(langSpec.getReturnStatement(langSpec.getFieldAccessor(fieldName)) + langSpec.getStatementDelimiter()); - } + 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) { @@ -453,6 +463,16 @@ return null; } + protected static List getGetterMethods(TypeDeclaration component, String resourceName) { + List getters = new ArrayList<>(); + for (MethodDeclaration m: component.getMethods()) { + if (m.getName().equals(getterPrefix + resourceName)) { + getters.add(m); + } + } + return getters; + } + protected MethodDeclaration getUpdateMethod(Edge inEdge, TypeDeclaration component, Map>> dataFlowInform, ILanguageSpecific langSpec) { List passedResoueces = dataFlowInform.get(inEdge).get(PushPullValue.PUSH); @@ -602,6 +622,7 @@ // 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); @@ -610,23 +631,65 @@ String fieldName = langSpec.toVariableName(typeName); getter = new Field(fieldName, new Type(typeName, typeName)); } else { - 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 (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++; + } } - if (var != null) { - newGetter.addChild(var); - newGetter.getSymbol().setArity(2); + 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; } - v++; + 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++; + } } - getter = newGetter; } } diff --git a/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java b/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java index fc6b3f4..2586162 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java @@ -9,6 +9,7 @@ import java.util.Map; import java.util.Map.Entry; import java.util.Set; +import java.util.Stack; import java.util.AbstractMap.SimpleEntry; import code.ast.Block; @@ -35,6 +36,7 @@ import models.dataConstraintModel.ChannelMember; import models.dataConstraintModel.DataConstraintModel; import models.dataConstraintModel.JsonAccessor; +import models.dataConstraintModel.JsonTerm; import models.dataConstraintModel.ResourceHierarchy; import models.dataConstraintModel.ResourcePath; import models.dataConstraintModel.Selector; @@ -58,8 +60,8 @@ Map resourceConstructors = new HashMap<>(); List> constructorParams = new ArrayList<>(); List> constructorStatements = new ArrayList<>(); - Map> updateStatements = new HashMap<>(); - Map> childGetters = new HashMap<>(); + Map>> updateStatements = new HashMap<>(); + Map> descendantGetters = new HashMap<>(); // For each components (1st pass). for (Node componentNode: components) { @@ -108,8 +110,8 @@ declareAccessorInMainComponent(mainComponent, resourceNode, stateGetter, langSpec); } if (component != null) { - // Declare the getter methods in this resource to obtain the children resources. - declareChildGetterMethod(resourceNode, component, childGetters, langSpec); + // Declare the getter methods in this resource to obtain the descendant resources. + declareDescendantGetterMethods(resourceNode, component, descendantGetters, langSpec); } } } @@ -129,23 +131,23 @@ } // Declare cache fields and update methods in this resource. - Map.Entry, Map>> initStatementsAndUpdateUpdates = declareCacheFieldsAndUpdateMethods(resourceNode, component, parentComponent, langSpec); + Map.Entry, Map>>> initStatementsAndUpdateUpdates = declareCacheFieldsAndUpdateMethods(resourceNode, component, parentComponent, langSpec); if (component == null) { // Constructor statements were not added to any component because no component had been generated. for (String statement: initStatementsAndUpdateUpdates.getKey()) { constructorStatements.add(new AbstractMap.SimpleEntry<>(resourceNode.getResourceHierarchy().getParent(), statement)); } } - for (Map.Entry> entry: initStatementsAndUpdateUpdates.getValue().entrySet()) { + for (Map.Entry>> entry: initStatementsAndUpdateUpdates.getValue().entrySet()) { updateStatements.put(entry.getKey(), entry.getValue()); } // Declare the fields to refer to other resources in the parent/this component, and the state field in the parent component. declareFieldsToReferToOtherResourcesAndStateFieldInParentComponent(resourceNode, component, parentComponent, constructorParams, langSpec); - // Declare the getter method in this resource to obtain the state. + // Declare the getter method to obtain the resource state in an ancestor resource. if (component == null) { - MethodDeclaration stateGetter = declareStateGetterMethodInParent(resourceNode, parentComponent, resStateType, langSpec); + MethodDeclaration stateGetter = declareStateGetterMethodInAncestor(resourceNode, resourceComponents, resStateType, langSpec); if (stateGetter != null) { // Declare the accessor method in the main component to call the getter method. @@ -154,14 +156,14 @@ } // Declare input methods in this component and the main component. - Map.Entry, Map>> initStatementsAndInputUpdates = declareInputMethodsInThisAndMainComponents(resourceNode, component, parentComponent, mainComponent, model, langSpec); + Map.Entry, Map>>> initStatementsAndInputUpdates = declareInputMethodsInThisAndMainComponents(resourceNode, component, parentComponent, mainComponent, model, langSpec); if (component == null) { // Constructor statements were not added to any component because no component had been generated. for (String statement: initStatementsAndInputUpdates.getKey()) { constructorStatements.add(new AbstractMap.SimpleEntry<>(resourceNode.getResourceHierarchy().getParent(), statement)); } } - for (Map.Entry> entry: initStatementsAndInputUpdates.getValue().entrySet()) { + for (Map.Entry>> entry: initStatementsAndInputUpdates.getValue().entrySet()) { updateStatements.put(entry.getKey(), entry.getValue()); } } @@ -179,9 +181,10 @@ // Add update statements. for (MethodDeclaration method: updateStatements.keySet()) { Expression updateExp = updateStatements.get(method).getKey(); - ResourceHierarchy childRes = updateStatements.get(method).getValue(); - TypeDeclaration childComponent = resourceComponents.get(childRes); - addUpdateStatementWithConstructorInvocationToMethod(method, updateExp, childRes, childComponent, langSpec); + ResourceHierarchy resource = updateStatements.get(method).getValue().getKey(); + ResourceHierarchy descendantRes = updateStatements.get(method).getValue().getValue(); + TypeDeclaration descendantComponent = resourceComponents.get(descendantRes); + addUpdateStatementWithConstructorInvocationToMethod(method, updateExp, resource, descendantRes, descendantComponent, langSpec); } } @@ -230,42 +233,70 @@ return params; } - private void addUpdateStatementWithConstructorInvocationToMethod(MethodDeclaration method, Expression exp, ResourceHierarchy childRes, TypeDeclaration childComponent, ILanguageSpecific langSpec) { - Type replacedJsonType = childRes.getResourceStateType(); - String replacingClassName = getComponentName(childRes, langSpec); + private void addUpdateStatementWithConstructorInvocationToMethod(MethodDeclaration method, Expression exp, ResourceHierarchy resource, ResourceHierarchy descendantRes, TypeDeclaration descendantComponent, ILanguageSpecific langSpec) { + Type replacedJsonType = descendantRes.getResourceStateType(); + String replacingClassName = getComponentName(descendantRes, langSpec); + Type descendantType = new Type(replacingClassName, replacingClassName); Map subTerms = ((Term) exp).getSubTerms(Term.class); Iterator> termEntItr = subTerms.entrySet().iterator(); while (termEntItr.hasNext()) { Entry termEnt = termEntItr.next(); Term jsonTerm = termEnt.getValue(); - if (jsonTerm.getType() != null && jsonTerm.getType().equals(replacedJsonType)) { - MethodDeclaration childConstructor = getConstructor(childComponent); - List params = new ArrayList<>(); - for (VariableDeclaration var: childConstructor.getParameters()) { - JsonAccessor jsonMember = new JsonAccessor(DataConstraintModel.dot); - jsonMember.addChild(jsonTerm); - jsonMember.addChild(new Constant("\"" + var.getName() + "\"")); - Expression param = jsonMember.reduce(); - if (param != null) { - if (param instanceof Term) { - if (((Term) param).getType() == null) { - ((Term) param).setType(var.getType()); - } - } else if (param instanceof Variable) { - if (((Variable) param).getType() == null) { - ((Variable) param).setType(var.getType()); + if (jsonTerm.getType() != null) { + if (jsonTerm.getType().equals(replacedJsonType)) { + if (jsonTerm instanceof JsonTerm || jsonTerm.getSymbol().equals(DataConstraintModel.addMember)) { + MethodDeclaration childConstructor = getConstructor(descendantComponent); + List params = new ArrayList<>(); + for (VariableDeclaration var: childConstructor.getParameters()) { + JsonAccessor jsonMember = new JsonAccessor(DataConstraintModel.dot); + jsonMember.addChild(jsonTerm); + jsonMember.addChild(new Constant(var.getName(), DataConstraintModel.typeString)); + Expression param = jsonMember.reduce(); + if (param != null) { + if (param instanceof Term) { + if (((Term) param).getType() == null) { + ((Term) param).setType(var.getType()); + } + } else if (param instanceof Variable) { + if (((Variable) param).getType() == null) { + ((Variable) param).setType(var.getType()); + } + } + params.add(param.toImplementation(new String[] {""})); + } else { + params.add(var.getName()); } } - params.add(param.toImplementation(null)); + ((Term) exp).replaceSubTerm(termEnt.getKey(), new Constant(langSpec.getConstructorInvocation(replacingClassName, params))); + subTerms = ((Term) exp).getSubTerms(Term.class); + termEntItr = subTerms.entrySet().iterator(); } else { - params.add(var.getName()); + jsonTerm.setType(descendantType); } + } else { + Type oldType = jsonTerm.getType(); + Type newType = new Type(oldType.getTypeName(), + oldType.getImplementationTypeName().replace(replacedJsonType.getInterfaceTypeName(), replacingClassName), + oldType.getInterfaceTypeName().replace(replacedJsonType.getInterfaceTypeName(), replacingClassName)); + for (Type parent: oldType.getParentTypes()) { + newType.addParentType(parent); + } + jsonTerm.setType(newType); } - ((Term) exp).replaceSubTerm(termEnt.getKey(), new Constant(langSpec.getConstructorInvocation(replacingClassName, params))); - subTerms = ((Term) exp).getSubTerms(Term.class); - termEntItr = subTerms.entrySet().iterator(); } } + // Replace the type of the state field. + Type fieldType = getImplStateType(resource, langSpec); + if (exp instanceof Term) { + ((Term) exp).setType(fieldType); + for (Map.Entry varEnt: ((Term) exp).getVariables().entrySet()) { + if (varEnt.getValue().getName().equals(fieldOfResourceState)) { + varEnt.getValue().setType(fieldType); + } + } + } else if (exp instanceof Variable) { + ((Variable) exp).setType(fieldType); + } String[] sideEffects = new String[] {""}; String newState = exp.toImplementation(sideEffects); String updateStatement; @@ -622,38 +653,48 @@ return stateGetter; } - private MethodDeclaration declareStateGetterMethodInParent(ResourceNode resourceNode, TypeDeclaration parentComponent, Type resStateType, ILanguageSpecific langSpec) { - // Check duplication. - String getterName = getterPrefix + getComponentName(resourceNode.getResourceHierarchy(), langSpec); - for (MethodDeclaration method: parentComponent.getMethods()) { - if (method.getName().equals(getterName)) return null; - } - - // Declare the getter method of the resource state. + private MethodDeclaration declareStateGetterMethodInAncestor(ResourceNode resourceNode, Map resourceComponents, Type resStateType, ILanguageSpecific langSpec) { + // Search an ancestor in which the getter method is declared. + ResourceNode ancestorNode = resourceNode; + Stack ancestors = new Stack<>(); + do { + ancestors.push(ancestorNode); + ancestorNode = ancestorNode.getParent(); + } while (!generatesComponent(ancestorNode.getResourceHierarchy())); + TypeDeclaration ancestorComponent = resourceComponents.get(ancestorNode.getResourceHierarchy()); List getterParams = new ArrayList<>(); int v = 1; - for (Selector param: resourceNode.getSelectors()) { - if (param.getExpression() instanceof Variable) { - Variable var = (Variable) param.getExpression(); - getterParams.add(new VariableDeclaration(var.getType(), var.getName())); - } else if (param.getExpression() instanceof Term) { - Term var = (Term) param.getExpression(); - getterParams.add(new VariableDeclaration(var.getType(), "v" + v)); + while (ancestors.size() > 0) { + ResourceNode curAncestor = ancestors.pop(); + Expression param = curAncestor.getPrimaryResourcePath().getLastParam(); + if (param instanceof Variable) { + Variable var = (Variable) param; + getterParams.add(langSpec.newVariableDeclaration(var.getType(), var.getName())); + } else if (param instanceof Term) { + Term var = (Term) param; + getterParams.add(langSpec.newVariableDeclaration(var.getType(), "v" + v)); } v++; } + // Check duplication. + String getterName = getterPrefix + getComponentName(resourceNode.getResourceHierarchy(), langSpec); + for (MethodDeclaration method: ancestorComponent.getMethods()) { + if (method.getName().equals(getterName) && method.getParameters().size() == getterParams.size()) return null; + } + + // Declare the getter method of the resource state. MethodDeclaration stateGetter = null; if (getterParams.size() == 0) { - stateGetter = new MethodDeclaration(getterName, resStateType); + stateGetter = langSpec.newMethodDeclaration(getterName, resStateType); } else { - stateGetter = new MethodDeclaration(getterName, false, resStateType, getterParams); + stateGetter = langSpec.newMethodDeclaration(getterName, false, resStateType, getterParams); } - if (parentComponent != null) { - parentComponent.addMethod(stateGetter); + if (ancestorComponent != null) { + ancestorComponent.addMethod(stateGetter); } if (((StoreAttribute) resourceNode.getAttribute()).isStored()) { - fillChildGetterMethod(stateGetter, resourceNode.getResourceHierarchy(), resourceNode.getResourceHierarchy().getParent().getResourceStateType(), langSpec); + fillDescendantGetterMethod(stateGetter, resourceNode.getResourceHierarchy(), ancestorNode.getResourceHierarchy(), ancestorComponent, langSpec); } else { addOtherGetterInvocationsToStateGatter(stateGetter, resourceNode, langSpec); } @@ -716,52 +757,59 @@ } } - private void declareChildGetterMethod(ResourceNode resourceNode, TypeDeclaration component, Map> childGetters, ILanguageSpecific langSpec) { - // Declare the getter methods in this resource to obtain the children resources. - Set children = childGetters.get(resourceNode.getResourceHierarchy()); - if (children == null) { - children = new HashSet<>(); - childGetters.put(resourceNode.getResourceHierarchy(), children); + private void declareDescendantGetterMethods(ResourceNode resourceNode, TypeDeclaration component, Map> descendantGetters, ILanguageSpecific langSpec) { + // Declare the getter methods in this resource to obtain descendant resources. + Set descendants = descendantGetters.get(resourceNode.getResourceHierarchy()); + if (descendants == null) { + descendants = new HashSet<>(); + descendantGetters.put(resourceNode.getResourceHierarchy(), descendants); } for (ResourceNode child: resourceNode.getChildren()) { - if (generatesComponent(child.getResourceHierarchy())) { - // A component for the child is generated. - if (!children.contains(child.getResourceHierarchy())) { - children.add(child.getResourceHierarchy()); - List params = new ArrayList<>(); - int v = 1; - Expression param = child.getPrimaryResourcePath().getLastParam(); - if (param != null) { - if (param instanceof Variable) { - Variable var = (Variable) param; - params.add(langSpec.newVariableDeclaration(var.getType(), var.getName())); - } else if (param instanceof Term) { - Term var = (Term) param; - params.add(langSpec.newVariableDeclaration(var.getType(), "v" + v)); - } - v++; + // A descendant of the child may generate a component. + List params = new ArrayList<>(); + int v = 1; + ResourceNode descendant = child; + Set childNodes; + do { + Expression param = descendant.getPrimaryResourcePath().getLastParam(); + if (param != null) { + if (param instanceof Variable) { + Variable var = (Variable) param; + params.add(langSpec.newVariableDeclaration(var.getType(), var.getName())); + } else if (param instanceof Term) { + Term var = (Term) param; + params.add(langSpec.newVariableDeclaration(var.getType(), "v" + v)); } - String childCompName = getComponentName(child.getResourceHierarchy(), langSpec); - Type childType = new Type(childCompName, childCompName); - MethodDeclaration childGetter = null; - if (params.size() == 0) { - childGetter = langSpec.newMethodDeclaration(getterPrefix + childCompName, childType); - } else { - childGetter = langSpec.newMethodDeclaration(getterPrefix + childCompName, false, childType, params); - } - - fillChildGetterMethod(childGetter, child.getResourceHierarchy(), resourceNode.getResourceStateType(), langSpec); - component.addMethod(childGetter); + v++; } - } + if (generatesComponent(descendant.getResourceHierarchy())) { + // If the descendant generates a component. + if (!descendants.contains(descendant.getResourceHierarchy())) { + descendants.add(descendant.getResourceHierarchy()); + String descendantCompName = getComponentName(descendant.getResourceHierarchy(), langSpec); + Type descendantType = new Type(descendantCompName, descendantCompName); + MethodDeclaration descendantGetter = null; + if (params.size() == 0) { + descendantGetter = langSpec.newMethodDeclaration(getterPrefix + descendantCompName, descendantType); + } else { + descendantGetter = langSpec.newMethodDeclaration(getterPrefix + descendantCompName, false, descendantType, params); + } + + fillDescendantGetterMethod(descendantGetter, descendant.getResourceHierarchy(), resourceNode.getResourceHierarchy(), component, langSpec); + component.addMethod(descendantGetter); + } + break; + } + childNodes = descendant.getChildren(); + } while (childNodes != null && childNodes.size() == 1 && (descendant = childNodes.iterator().next()) != null); } } - private Map.Entry, Map>> declareCacheFieldsAndUpdateMethods(ResourceNode resourceNode, TypeDeclaration component, TypeDeclaration parentComponent, ILanguageSpecific langSpec) { + private Map.Entry, Map>>> declareCacheFieldsAndUpdateMethods(ResourceNode resourceNode, TypeDeclaration component, TypeDeclaration parentComponent, ILanguageSpecific langSpec) { // Declare cash fields and update methods in the component. String resComponentName = getComponentName(resourceNode.getResourceHierarchy(), langSpec); List constructorStatements = new ArrayList<>(); - Map> updateStatements = new HashMap<>(); + Map>> updateStatements = new HashMap<>(); for (Edge chToRes: resourceNode.getInEdges()) { for (Edge resToCh: chToRes.getSource().getInEdges()) { DataTransferChannel ch = ((ChannelNode) resToCh.getDestination()).getChannel(); @@ -866,12 +914,17 @@ // Replace Json constructor with a constructor of the child resource. ResourceHierarchy outRes = out.getResource().getResourceHierarchy(); if (outRes.getChildren().size() == 1 && outRes.getChildren().iterator().next().getNumParameters() > 0) { - ResourceHierarchy childRes = outRes.getChildren().iterator().next(); - Type childStateType = childRes.getResourceStateType(); - if (DataConstraintModel.typeJson.isAncestorOf(childStateType)) { - updateStatements.put(update, new AbstractMap.SimpleEntry<>(updateExp, childRes)); - break; - } + ResourceHierarchy descendantRes = outRes; + Set children = descendantRes.getChildren(); + do { + descendantRes = children.iterator().next(); + if (generatesComponent(descendantRes)) { + updateStatements.put(update, new AbstractMap.SimpleEntry<>(updateExp, new AbstractMap.SimpleEntry<>(outRes, descendantRes))); + updateExp = null; + break; + } + children = descendantRes.getChildren(); + } while (children != null && children.size() == 1); } // Add statements to the update method. String[] sideEffects = new String[] {""}; @@ -1212,15 +1265,15 @@ return new AbstractMap.SimpleEntry<>(constructorStatements, updateStatements); } - private Map.Entry, Map>> declareInputMethodsInThisAndMainComponents(ResourceNode resourceNode, TypeDeclaration component, + private Map.Entry, Map>>> declareInputMethodsInThisAndMainComponents(ResourceNode resourceNode, TypeDeclaration component, TypeDeclaration parentComponent, TypeDeclaration mainComponent, DataTransferModel model, ILanguageSpecific langSpec) { // Declare input methods. String resName = resourceNode.getResourceName(); String resComponentName = langSpec.toComponentName(resName); List constructorStatements = new ArrayList<>(); - Map> inputStatements = new HashMap<>(); - for (Channel ch : model.getInputChannels()) { - for (ChannelMember out : ((DataTransferChannel) ch).getOutputChannelMembers()) { + Map>> inputStatements = new HashMap<>(); + for (Channel ch: model.getInputChannels()) { + for (ChannelMember out: ((DataTransferChannel) ch).getOutputChannelMembers()) { if (resourceNode.getInSideResources().contains(out.getResource())) { Expression message = out.getStateTransition().getMessageExpression(); MethodDeclaration input = null; @@ -1427,7 +1480,7 @@ ResourcePath ref = rc.getResource(); if (!out.getResource().equals(ref)) { String refVarName = ref.getLeafResourceName(); - Expression refGetter = JavaCodeGenerator.pullAccessor.getDirectStateAccessorFor(ref, null); + Expression refGetter = getPullAccessor().getDirectStateAccessorFor(ref, null); String[] sideEffects = new String[] {""}; String refExp = refGetter.toImplementation(sideEffects); String refTypeName = ref.getResourceStateType().getInterfaceTypeName(); @@ -1443,7 +1496,7 @@ } resExp = ((Term) resExp).getChild(0); } - String resourceAccess = resExp.toImplementation(new String[] {null}); + String resourceAccess = resExp.toImplementation(new String[] {""}); // Values of channel parameters. for (Selector selector: ch.getAllSelectors()) { if (selector.getExpression() instanceof Variable) { @@ -1480,15 +1533,20 @@ // Add a statement to update the state field to the input method. try { Expression updateExp = ((DataTransferChannel) ch).deriveUpdateExpressionOf(out, getRefAccessor()).getKey(); - // Replace Json constructor with a constructor of the child resource. + // Replace Json constructor with a constructor of a descendant resource. ResourceHierarchy outRes = out.getResource().getResourceHierarchy(); if (outRes.getChildren().size() == 1 && outRes.getChildren().iterator().next().getNumParameters() > 0) { - ResourceHierarchy childRes = outRes.getChildren().iterator().next(); - Type childStateType = childRes.getResourceStateType(); - if (DataConstraintModel.typeJson.isAncestorOf(childStateType)) { - inputStatements.put(input, new AbstractMap.SimpleEntry<>(updateExp, childRes)); - updateExp = null; - } + ResourceHierarchy descendantRes = outRes; + Set children = descendantRes.getChildren(); + do { + descendantRes = children.iterator().next(); + if (generatesComponent(descendantRes)) { + inputStatements.put(input, new AbstractMap.SimpleEntry<>(updateExp, new AbstractMap.SimpleEntry<>(outRes, descendantRes))); + updateExp = null; + break; + } + children = descendantRes.getChildren(); + } while (children != null && children.size() == 1); } // Add statements to the input method. if (updateExp != null) { diff --git a/AlgebraicDataflowArchitectureModel/src/generators/JavaCodeGenerator.java b/AlgebraicDataflowArchitectureModel/src/generators/JavaCodeGenerator.java index 7c9ad00..b646911 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/JavaCodeGenerator.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/JavaCodeGenerator.java @@ -101,14 +101,14 @@ if (generatesComponent(child)) { return new Type("List", "ArrayList<>", "List<" + getComponentName(child) + ">", DataConstraintModel.typeList); } else { - return new Type("List", "ArrayList<>", "List<" + getImplStateType(child).getImplementationTypeName() + ">", DataConstraintModel.typeList); + return new Type("List", "ArrayList<>", "List<" + getImplStateType(child).getInterfaceTypeName() + ">", DataConstraintModel.typeList); } } else if (DataConstraintModel.typeMap.isAncestorOf(res.getResourceStateType())) { // map. if (generatesComponent(child)) { return new Type("Map", "HashMap<>", "Map", DataConstraintModel.typeMap); } else { - return new Type("Map", "HashMap<>", "Map", DataConstraintModel.typeMap); + return new Type("Map", "HashMap<>", "Map", DataConstraintModel.typeMap); } } return null; @@ -120,9 +120,11 @@ } public static boolean generatesComponent(ResourceHierarchy res) { - return res.getParent() == null || !(res.getChildren() == null || res.getChildren().size() == 0); -// Type resType = res.getResourceStateType(); -// return DataConstraintModel.typeJson.isAncestorOf(resType) || DataConstraintModel.typeList.isAncestorOf(resType) || DataConstraintModel.typeMap.isAncestorOf(resType); + 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); } static public ArrayList doGenerate(DataFlowGraph graph, DataTransferModel model) { @@ -133,7 +135,7 @@ Map> updates = new HashMap<>(); Map> inputs = new HashMap<>(); List> fields = new ArrayList<>(); - Map> childGetters = new HashMap<>(); + Map> descendantGetters = new HashMap<>(); List> constructorParams = new ArrayList<>(); Map> dependedRootComponentGraph = getDependedRootComponentGraph(model); @@ -260,7 +262,7 @@ // The child has a component. childType = new Type(childTypeName, childTypeName); String fieldName = toVariableName(childTypeName); - component.addField(new FieldDeclaration(childType, fieldName, "new " + childTypeName + "()")); + component.addField(new FieldDeclaration(childType, fieldName, "new " + childTypeName + "()")); } } } @@ -275,43 +277,50 @@ declareAccessorMethodInMainComponent(resourceNode, mainComponent); } if (component != null) { - // Declare the getter methods to obtain the children resources. - Set children = childGetters.get(resourceNode.getResourceHierarchy()); - if (children == null) { - children = new HashSet<>(); - childGetters.put(resourceNode.getResourceHierarchy(), children); + // Declare the getter methods in this resource to obtain descendant resources. + Set descendants = descendantGetters.get(resourceNode.getResourceHierarchy()); + if (descendants == null) { + descendants = new HashSet<>(); + descendantGetters.put(resourceNode.getResourceHierarchy(), descendants); } for (ResourceNode child: resourceNode.getChildren()) { - if (generatesComponent(child.getResourceHierarchy())) { - // A component for the child is generated. - if (!children.contains(child.getResourceHierarchy())) { - children.add(child.getResourceHierarchy()); - List params = new ArrayList<>(); - int v = 1; - Expression param = child.getPrimaryResourcePath().getLastParam(); - if (param != null) { - if (param instanceof Variable) { - Variable var = (Variable) param; - params.add(new VariableDeclaration(var.getType(), var.getName())); - } else if (param instanceof Term) { - Term var = (Term) param; - params.add(new VariableDeclaration(var.getType(), "v" + v)); - } - v++; + // A descendant of the child may generate a component. + List params = new ArrayList<>(); + int v = 1; + ResourceNode descendant = child; + Set childNodes; + do { + Expression param = descendant.getPrimaryResourcePath().getLastParam(); + if (param != null) { + if (param instanceof Variable) { + Variable var = (Variable) param; + params.add(new VariableDeclaration(var.getType(), var.getName())); + } else if (param instanceof Term) { + Term var = (Term) param; + params.add(new VariableDeclaration(var.getType(), "v" + v)); } - String childCompName = getComponentName(child.getResourceHierarchy()); - Type childType = new Type(childCompName, childCompName); - MethodDeclaration childGetter = null; - if (params.size() == 0) { - childGetter = new MethodDeclaration("get" + childCompName, childType); - } else { - childGetter = new MethodDeclaration("get" + childCompName, false, childType, params); - } - component.addMethod(childGetter); + v++; } - } + if (generatesComponent(descendant.getResourceHierarchy())) { + // If the descendant generates a component. + if (!descendants.contains(descendant.getResourceHierarchy())) { + descendants.add(descendant.getResourceHierarchy()); + String descendantCompName = getComponentName(descendant.getResourceHierarchy()); + Type descendantType = new Type(descendantCompName, descendantCompName); + MethodDeclaration descendantGetter = null; + if (params.size() == 0) { + descendantGetter = new MethodDeclaration("get" + descendantCompName, descendantType); + } else { + descendantGetter = new MethodDeclaration("get" + descendantCompName, false, descendantType, params); + } + component.addMethod(descendantGetter); + } + break; + } + childNodes = descendant.getChildren(); + } while (childNodes != null && childNodes.size() == 1 && (descendant = childNodes.iterator().next()) != null); } - } + } } // Declare the state field in the parent component. @@ -354,30 +363,40 @@ } } - // Declare the getter method to obtain the resource state in the parent component. + // Declare the getter method to obtain the resource state in an ancestor component. if (component == null) { // No component is created for this resource. + ResourceNode ancestorNode = resourceNode; + Stack ancestors = new Stack<>(); + do { + ancestors.push(ancestorNode); + ancestorNode = ancestorNode.getParent(); + } while (!generatesComponent(ancestorNode.getResourceHierarchy())); + List getterParams = new ArrayList<>(); + int v = 1; + while (ancestors.size() > 0) { + ResourceNode curAncestor = ancestors.pop(); + Expression param = curAncestor.getPrimaryResourcePath().getLastParam(); + if (param instanceof Variable) { + Variable var = (Variable) param; + getterParams.add(new VariableDeclaration(var.getType(), var.getName())); + } else if (param instanceof Term) { + Term var = (Term) param; + getterParams.add(new VariableDeclaration(var.getType(), "v" + v)); + } + v++; + } String getterName = "get" + getComponentName(resourceNode.getResourceHierarchy()); boolean bExists = false; for (Map.Entry entry: getters) { - if (entry.getKey() == resourceNode.getParent().getResourceHierarchy() && entry.getValue().getName().equals(getterName)) { + ResourceHierarchy r = entry.getKey(); + MethodDeclaration m = entry.getValue(); + if (r == ancestorNode.getResourceHierarchy() && m.getName().equals(getterName) && m.getParameters().size() == getterParams.size()) { bExists = true; break; } } if (!bExists) { - List getterParams = new ArrayList<>(); - int v = 1; - for (Selector param: resourceNode.getSelectors()) { - if (param.getExpression() instanceof Variable) { - Variable var = (Variable) param.getExpression(); - getterParams.add(new VariableDeclaration(var.getType(), var.getName())); - } else if (param.getExpression() instanceof Term) { - Term var = (Term) param.getExpression(); - getterParams.add(new VariableDeclaration(var.getType(), "v" + v)); - } - v++; - } Type resType = getImplStateType(resourceNode.getResourceHierarchy()); MethodDeclaration stateGetter = null; if (getterParams.size() == 0) { @@ -385,7 +404,7 @@ } else { stateGetter = new MethodDeclaration(getterName, false, resType, getterParams); } - getters.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), stateGetter)); + getters.add(new AbstractMap.SimpleEntry<>(ancestorNode.getResourceHierarchy(), stateGetter)); // Declare the accessor method in the main type to call the getter method. declareAccessorMethodInMainComponent(resourceNode, mainComponent); @@ -1253,6 +1272,7 @@ // 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()); @@ -1261,23 +1281,65 @@ String fieldName = toVariableName(typeName); getter = new Field(fieldName, new Type(typeName, typeName)); } else { - Term newGetter = new Term(new Symbol("get" + 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 (generatesComponent(curPath.getResourceHierarchy())) { + if (arity == 2) { + Term newGetter = new Term(new Symbol("get" + 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++; + } } - if (var != null) { - newGetter.addChild(var); - newGetter.getSymbol().setArity(2); + arity = 2; + } else { + // to get a descendant resource directly. + if (arity == 2) { + Term newGetter = new Term(new Symbol("get" + typeName, -1, Symbol.Type.METHOD)); + newGetter.addChild(getter); + getter = newGetter; } - v++; + 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++; + } } - getter = newGetter; } } if (generatesComponent(targetRes.getResourceHierarchy())) { diff --git a/AlgebraicDataflowArchitectureModel/src/generators/JavaMethodBodyGenerator.java b/AlgebraicDataflowArchitectureModel/src/generators/JavaMethodBodyGenerator.java index 8c2337a..c56d194 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/JavaMethodBodyGenerator.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/JavaMethodBodyGenerator.java @@ -32,6 +32,7 @@ import models.dataConstraintModel.ChannelMember; import models.dataConstraintModel.DataConstraintModel; import models.dataConstraintModel.JsonAccessor; +import models.dataConstraintModel.JsonTerm; import models.dataConstraintModel.ResourceHierarchy; import models.dataConstraintModel.ResourcePath; import models.dataConstraintModel.Selector; @@ -110,17 +111,34 @@ } updateExp = ch.deriveUpdateExpressionOf(out, JavaCodeGenerator.pushAccessor, inputResourceToStateAccessor).getKey(); } - // Replace Json constructor with a constructor of the child resource. + // Replace Json constructor with a constructor of a descendant resource. ResourceHierarchy outRes = out.getResource().getResourceHierarchy(); if (outRes.getChildren().size() == 1 && outRes.getChildren().iterator().next().getNumParameters() > 0) { - ResourceHierarchy childRes = outRes.getChildren().iterator().next(); - Type childStateType = childRes.getResourceStateType(); - String childComponentName = JavaCodeGenerator.getComponentName(childRes); - TypeDeclaration childComponent = componentMap.get(childComponentName); - if (DataConstraintModel.typeJson.isAncestorOf(childStateType)) { - replaceJsonTermWithConstructorInvocation(updateExp, childStateType, childComponentName, childComponent); + ResourceHierarchy descendantRes = outRes.getChildren().iterator().next(); + Set children; + do { + if (JavaCodeGenerator.generatesComponent(descendantRes)) break; + children = descendantRes.getChildren(); + } while (children != null && children.size() == 1 && (descendantRes = children.iterator().next()) != null); + Type descendantStateType = descendantRes.getResourceStateType(); + String descendantComponentName = JavaCodeGenerator.getComponentName(descendantRes); + TypeDeclaration descendantComponent = componentMap.get(descendantComponentName); + if (DataConstraintModel.typeJson.isAncestorOf(descendantStateType)) { + replaceJsonTermWithConstructorInvocation(updateExp, descendantStateType, descendantComponentName, descendantComponent); } } + // Replace the type of the state field. + Type fieldType = JavaCodeGenerator.getImplStateType(outRes); + if (updateExp instanceof Term) { + ((Term) updateExp).setType(fieldType); + for (Map.Entry varEnt: ((Term) updateExp).getVariables().entrySet()) { + if (varEnt.getValue().getName().equals("value")) { + varEnt.getValue().setType(fieldType); + } + } + } else if (updateExp instanceof Variable) { + ((Variable) updateExp).setType(fieldType); + } // Add statements to the update method. String[] sideEffects = new String[] {""}; String newState = updateExp.toImplementation(sideEffects); @@ -198,7 +216,7 @@ } v++; } - String ifStatement = "if (" + conditions.toImplementation(new String[] {})+ ") {\n"; + String ifStatement = "if (" + conditions.toImplementation(new String[] {""})+ ") {\n"; update.addFirstStatement(ifStatement + "\t" + updateStatement.replace("\n", "\n\t") + "\n}"); } } @@ -563,97 +581,125 @@ } } } + // for source nodes TypeDeclaration mainComponent = componentMap.get(JavaCodeGenerator.mainTypeName); for (ResourceHierarchy resource: model.getResourceHierarchies()) { -// ResourceNode resource = (ResourceNode) n; String resourceName = JavaCodeGenerator.getComponentName(resource); TypeDeclaration component = componentMap.get(resourceName); - if (component != null) { - // state getter method - Type resourceType = JavaCodeGenerator.getImplStateType(resource); - MethodDeclaration stateGetter = getMethod(component, "getValue"); - if (stateGetter != null && (stateGetter.getBody() == null || stateGetter.getBody().getStatements().size() == 0)) { - if (model.isPrimitiveType(resourceType)) { - // primitive type - stateGetter.addStatement("return value;"); - } else { - if (resource.getChildren() != null && resource.getChildren().size() == 1 && resource.getChildren().iterator().next().getNumParameters() > 0) { - // list or map - String implTypeName = resourceType.getImplementationTypeName(); - // copy the current state to be returned as a 'value' - stateGetter.addStatement("return new " + implTypeName + "(value);"); + if (JavaCodeGenerator.generatesComponent(resource)) { + if (component != null) { + // state getter method + Type resourceType = JavaCodeGenerator.getImplStateType(resource); + MethodDeclaration stateGetter = getMethod(component, "getValue"); + if (stateGetter != null && (stateGetter.getBody() == null || stateGetter.getBody().getStatements().size() == 0)) { + if (model.isPrimitiveType(resourceType)) { + // primitive type + stateGetter.addStatement("return value;"); } else { - if (resource.getChildren() == null || resource.getChildren().size() == 0) { - // a leaf resource + if (resource.getChildren() != null && resource.getChildren().size() == 1 && resource.getChildren().iterator().next().getNumParameters() > 0) { + // list or map String implTypeName = resourceType.getImplementationTypeName(); + // copy the current state to be returned as a 'value' stateGetter.addStatement("return new " + implTypeName + "(value);"); } else { - Term composer = null; - Term composerSub = new Constant(DataConstraintModel.nil); - composerSub.setType(DataConstraintModel.typeMap); - for (ResourceHierarchy child: resource.getChildren()) { - String childTypeName = JavaCodeGenerator.getComponentName(child); - String fieldName = JavaCodeGenerator.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("getValue", 1, Symbol.Type.METHOD)); - childGetter.addChild(new Field(fieldName, JavaCodeGenerator.getImplStateType(child))); - } - 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] + "return " + returnValue+ ";"); + if (resource.getChildren() == null || resource.getChildren().size() == 0) { + // a leaf resource + String implTypeName = resourceType.getImplementationTypeName(); + stateGetter.addStatement("return new " + implTypeName + "(value);"); } else { - stateGetter.addStatement("return " + returnValue+ ";"); + Term composer = null; + Term composerSub = new Constant(DataConstraintModel.nil); + composerSub.setType(DataConstraintModel.typeMap); + for (ResourceHierarchy child: resource.getChildren()) { + String childTypeName = JavaCodeGenerator.getComponentName(child); + String fieldName = JavaCodeGenerator.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("getValue", 1, Symbol.Type.METHOD)); + childGetter.addChild(new Field(fieldName, JavaCodeGenerator.getImplStateType(child))); + } + 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[] {""}; + String returnValue = composer.toImplementation(sideEffects); + if (sideEffects[0] != null) { + stateGetter.addStatement(sideEffects[0] + "return " + returnValue+ ";"); + } else { + stateGetter.addStatement("return " + returnValue+ ";"); + } } } } } - } - - // child getter method - if (resource.getChildren().size() > 0) { - for (ResourceHierarchy child: resource.getChildren()) { - String methodName = "get" + JavaCodeGenerator.getComponentName(child); - MethodDeclaration childGetter = getMethod(component, methodName); - if (childGetter != null && (childGetter.getBody() == null || childGetter.getBody().getStatements().size() == 0)) { - if (DataConstraintModel.typeList.isAncestorOf(resource.getResourceStateType())) { - Term selector = new Term(DataConstraintModel.get); - selector.addChild(new Field("value")); - selector.addChild(new Variable(childGetter.getParameters().get(childGetter.getParameters().size() - 1).getName())); - selector.setType(childGetter.getReturnType()); - String[] sideEffects = new String[] {null}; - String returnValue = selector.toImplementation(sideEffects); - if (sideEffects[0] != null) childGetter.addStatement(sideEffects[0]); - childGetter.addStatement("return " + returnValue + ";"); - } else if (DataConstraintModel.typeMap.isAncestorOf(resource.getResourceStateType())) { - Term selector = new Term(DataConstraintModel.lookup); - selector.addChild(new Field("value")); - selector.addChild(new Variable(childGetter.getParameters().get(childGetter.getParameters().size() - 1).getName())); - selector.setType(childGetter.getReturnType()); - String[] sideEffects = new String[] {null}; - String returnValue = selector.toImplementation(sideEffects); - if (sideEffects[0] != null) childGetter.addStatement(sideEffects[0]); - childGetter.addStatement("return " + returnValue+ ";"); + + // descendant getter method + if (resource.getChildren().size() > 0) { + for (ResourceHierarchy child: resource.getChildren()) { + ResourceHierarchy parent = resource; + ResourceHierarchy descendant = child; + Set children; + Expression selector; + int params = 0; + if (DataConstraintModel.typeList.isAncestorOf(parent.getResourceStateType())) { + selector = new Field("value"); + params++; + } else if (DataConstraintModel.typeMap.isAncestorOf(parent.getResourceStateType())) { + selector = new Field("value"); + params++; } else { - String fieldName = JavaCodeGenerator.getComponentName(child); - String returnValue = JavaCodeGenerator.toVariableName(fieldName); - childGetter.addStatement("return this." + returnValue + ";"); + String fieldName = JavaCodeGenerator.getComponentName(descendant); + selector = new Field(JavaCodeGenerator.toVariableName(fieldName)); } + do { + String methodName = JavaCodeGenerator.getComponentName(descendant); + MethodDeclaration descendantGetter = null; + for (MethodDeclaration getter: getGetterMethods(component, methodName)) { + if ((getter.getParameters() == null && params == 0) || (getter.getParameters() != null && getter.getParameters().size() == params)) { + descendantGetter = getter; + } + } + if (descendantGetter != null) { + if (DataConstraintModel.typeList.isAncestorOf(parent.getResourceStateType())) { + Term newSelector = new Term(DataConstraintModel.get); + newSelector.addChild(selector); + newSelector.addChild(new Variable(descendantGetter.getParameters().get(descendantGetter.getParameters().size() - 1).getName())); + newSelector.setType(descendantGetter.getReturnType()); + selector = newSelector; + params++; + } else if (DataConstraintModel.typeMap.isAncestorOf(parent.getResourceStateType())) { + Term newSelector = new Term(DataConstraintModel.lookup); + newSelector.addChild(selector); + newSelector.addChild(new Variable(descendantGetter.getParameters().get(descendantGetter.getParameters().size() - 1).getName())); + newSelector.setType(descendantGetter.getReturnType()); + selector = newSelector; + params++; + } + 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("return " + returnValue + ";"); + } + } + if (JavaCodeGenerator.generatesComponent(descendant)) { + // If the descendant generates a component. + break; + } + parent = descendant; + children = descendant.getChildren(); + } while (children != null && children.size() == 1 && (descendant = children.iterator().next()) != null); } } } @@ -680,17 +726,34 @@ if (input != null) { // In each resource Expression updateExp = ch.deriveUpdateExpressionOf(out, JavaCodeGenerator.refAccessor).getKey(); - // Replace Json constructor with a constructor of the child resource. + // Replace Json constructor with a constructor of a descendant resource. ResourceHierarchy outRes = out.getResource().getResourceHierarchy(); if (outRes.getChildren().size() == 1 && outRes.getChildren().iterator().next().getNumParameters() > 0) { - ResourceHierarchy childRes = outRes.getChildren().iterator().next(); - Type childStateType = childRes.getResourceStateType(); - String childComponentName = JavaCodeGenerator.getComponentName(childRes); - TypeDeclaration childComponent = componentMap.get(childComponentName); - if (DataConstraintModel.typeJson.isAncestorOf(childStateType)) { - replaceJsonTermWithConstructorInvocation(updateExp, childStateType, childComponentName, childComponent); + ResourceHierarchy descendantRes = outRes.getChildren().iterator().next(); + Set children; + do { + if (JavaCodeGenerator.generatesComponent(descendantRes)) break; + children = descendantRes.getChildren(); + } while (children != null && children.size() == 1 && (descendantRes = children.iterator().next()) != null); + Type descendantStateType = descendantRes.getResourceStateType(); + String descendantComponentName = JavaCodeGenerator.getComponentName(descendantRes); + TypeDeclaration descendantComponent = componentMap.get(descendantComponentName); + if (DataConstraintModel.typeJson.isAncestorOf(descendantStateType)) { + replaceJsonTermWithConstructorInvocation(updateExp, descendantStateType, descendantComponentName, descendantComponent); } } + // Replace the type of the state field. + Type fieldType = JavaCodeGenerator.getImplStateType(outRes); + if (updateExp instanceof Term) { + ((Term) updateExp).setType(fieldType); + for (Map.Entry varEnt: ((Term) updateExp).getVariables().entrySet()) { + if (varEnt.getValue().getName().equals("value")) { + varEnt.getValue().setType(fieldType); + } + } + } else if (updateExp instanceof Variable) { + ((Variable) updateExp).setType(fieldType); + } // Add statements to the input method. String[] sideEffects = new String[] {""}; String newState = updateExp.toImplementation(sideEffects); @@ -826,41 +889,57 @@ return codes; } - private static void replaceJsonTermWithConstructorInvocation(Expression exp, Type replacedJsonType, String replacingClassName, TypeDeclaration childComponent) { + private static void replaceJsonTermWithConstructorInvocation(Expression exp, Type replacedJsonType, String replacingClassName, TypeDeclaration descendantComponent) { + Type descendantType = new Type(replacingClassName, replacingClassName); Map subTerms = ((Term) exp).getSubTerms(Term.class); Iterator> termEntItr = subTerms.entrySet().iterator(); while (termEntItr.hasNext()) { Entry termEnt = termEntItr.next(); Term jsonTerm = termEnt.getValue(); - if (jsonTerm.getType() != null && jsonTerm.getType().equals(replacedJsonType)) { - String constructorInvocation = "new " + replacingClassName + "("; - MethodDeclaration childConstructor = getConstructor(childComponent); - String delimiter = ""; - for (VariableDeclaration var: childConstructor.getParameters()) { - JsonAccessor jsonMember = new JsonAccessor(DataConstraintModel.dot); - jsonMember.addChild(jsonTerm); - jsonMember.addChild(new Constant("\"" + var.getName() + "\"")); - Expression param = jsonMember.reduce(); - if (param != null) { - if (param instanceof Term) { - if (((Term) param).getType() == null) { - ((Term) param).setType(var.getType()); + if (jsonTerm.getType() != null) { + if (jsonTerm.getType().equals(replacedJsonType)) { + if (jsonTerm instanceof JsonTerm || jsonTerm.getSymbol().equals(DataConstraintModel.addMember)) { + String constructorInvocation = "new " + replacingClassName + "("; + MethodDeclaration descendantConstructor = getConstructor(descendantComponent); + String delimiter = ""; + for (VariableDeclaration var: descendantConstructor.getParameters()) { + JsonAccessor jsonMember = new JsonAccessor(DataConstraintModel.dot); + jsonMember.addChild(jsonTerm); + jsonMember.addChild(new Constant(var.getName(), DataConstraintModel.typeString)); + Expression param = jsonMember.reduce(); + if (param != null) { + if (param instanceof Term) { + if (((Term) param).getType() == null) { + ((Term) param).setType(var.getType()); + } + } else if (param instanceof Variable) { + if (((Variable) param).getType() == null) { + ((Variable) param).setType(var.getType()); + } + } + constructorInvocation = constructorInvocation + delimiter + param.toImplementation(null); + } else { + constructorInvocation = constructorInvocation + delimiter + var.getName(); } - } else if (param instanceof Variable) { - if (((Variable) param).getType() == null) { - ((Variable) param).setType(var.getType()); - } + delimiter = ", "; } - constructorInvocation = constructorInvocation + delimiter + param.toImplementation(null); + constructorInvocation += ")"; + ((Term) exp).replaceSubTerm(termEnt.getKey(), new Constant(constructorInvocation, descendantType)); + subTerms = ((Term) exp).getSubTerms(Term.class); + termEntItr = subTerms.entrySet().iterator(); } else { - constructorInvocation = constructorInvocation + delimiter + var.getName(); + jsonTerm.setType(descendantType); } - delimiter = ", "; + } else { + Type oldType = jsonTerm.getType(); + Type newType = new Type(oldType.getTypeName(), + oldType.getImplementationTypeName().replace(replacedJsonType.getInterfaceTypeName(), replacingClassName), + oldType.getInterfaceTypeName().replace(replacedJsonType.getInterfaceTypeName(), replacingClassName)); + for (Type parent: oldType.getParentTypes()) { + newType.addParentType(parent); + } + jsonTerm.setType(newType); } - constructorInvocation += ")"; - ((Term) exp).replaceSubTerm(termEnt.getKey(), new Constant(constructorInvocation)); - subTerms = ((Term) exp).getSubTerms(Term.class); - termEntItr = subTerms.entrySet().iterator(); } } } @@ -906,6 +985,16 @@ return null; } + private static List getGetterMethods(TypeDeclaration component, String resourceName) { + List getters = new ArrayList<>(); + for (MethodDeclaration m: component.getMethods()) { + if (m.getName().equals("get" + resourceName)) { + getters.add(m); + } + } + return getters; + } + private static Map> getIOChannelsAndMembers(ResourceHierarchy resource, DataTransferModel model) { Map> ioChannelsAndMembers = new HashMap<>(); for (Channel c: model.getInputChannels()) { diff --git a/AlgebraicDataflowArchitectureModel/src/generators/JavaSpecific.java b/AlgebraicDataflowArchitectureModel/src/generators/JavaSpecific.java index 3070f23..72d79a9 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/JavaSpecific.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/JavaSpecific.java @@ -47,7 +47,7 @@ @Override public MethodDeclaration newMethodDeclaration(String methodName, boolean isConstructor, Type returnType, List parameters) { - if (returnType == null) { + if (returnType == null && !isConstructor) { returnType = typeVoid; } return new MethodDeclaration(methodName, isConstructor, returnType, parameters); diff --git a/AlgebraicDataflowArchitectureModel/src/generators/JerseyCodeGenerator.java b/AlgebraicDataflowArchitectureModel/src/generators/JerseyCodeGenerator.java index 33fae7a..0dc0551 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/JerseyCodeGenerator.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/JerseyCodeGenerator.java @@ -102,14 +102,14 @@ if (generatesComponent(child)) { return new Type("List", "ArrayList<>", "List<" + getComponentName(child) + ">", DataConstraintModel.typeList); } else { - return new Type("List", "ArrayList<>", "List<" + getImplStateType(child).getImplementationTypeName() + ">", DataConstraintModel.typeList); + return new Type("List", "ArrayList<>", "List<" + getImplStateType(child).getInterfaceTypeName() + ">", DataConstraintModel.typeList); } } else if (DataConstraintModel.typeMap.isAncestorOf(res.getResourceStateType())) { // map. if (generatesComponent(child)) { return new Type("Map", "HashMap<>", "Map", DataConstraintModel.typeMap); } else { - return new Type("Map", "HashMap<>", "Map", DataConstraintModel.typeMap); + return new Type("Map", "HashMap<>", "Map", DataConstraintModel.typeMap); } } return null; @@ -121,9 +121,11 @@ } public static boolean generatesComponent(ResourceHierarchy res) { - return res.getParent() == null || !(res.getChildren() == null || res.getChildren().size() == 0); -// Type resType = res.getResourceStateType(); -// return DataConstraintModel.typeJson.isAncestorOf(resType) || DataConstraintModel.typeList.isAncestorOf(resType) || DataConstraintModel.typeMap.isAncestorOf(resType); + 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); } static public ArrayList doGenerate(DataFlowGraph graph, DataTransferModel model) { @@ -136,7 +138,7 @@ Map> updates = new HashMap<>(); Map> inputs = new HashMap<>(); List> fields = new ArrayList<>(); - Map> childGetters = new HashMap<>(); + Map> descendantGetters = new HashMap<>(); Map getterAccessors = new HashMap<>(); Map inputAccessors = new HashMap<>(); Map> constructorParams = new HashMap<>(); @@ -204,7 +206,7 @@ // The child has a component. childType = new Type(childTypeName, childTypeName); String fieldName = toVariableName(childTypeName); - component.addField(new FieldDeclaration(childType, fieldName, "new " + childTypeName + "()")); + component.addField(new FieldDeclaration(childType, fieldName, "new " + childTypeName + "()")); } } } @@ -221,41 +223,48 @@ component.addMethod(stateGetter); } if (component != null) { - // Declare the getter methods to obtain the children resources. - Set children = childGetters.get(resourceNode.getResourceHierarchy()); - if (children == null) { - children = new HashSet<>(); - childGetters.put(resourceNode.getResourceHierarchy(), children); + // Declare the getter methods in this resource to obtain descendant resources. + Set descendants = descendantGetters.get(resourceNode.getResourceHierarchy()); + if (descendants == null) { + descendants = new HashSet<>(); + descendantGetters.put(resourceNode.getResourceHierarchy(), descendants); } for (ResourceNode child: resourceNode.getChildren()) { - if (generatesComponent(child.getResourceHierarchy())) { - // The child generates a component. - if (!children.contains(child.getResourceHierarchy())) { - children.add(child.getResourceHierarchy()); - List pathParams = new ArrayList<>(); - int v = 1; - Expression pathParam = child.getPrimaryResourcePath().getLastParam(); - if (pathParam != null) { - if (pathParam instanceof Variable) { - Variable var = (Variable) pathParam; - pathParams.add(new VariableDeclaration(var.getType(), var.getName())); - } else if (pathParam instanceof Term) { - Term var = (Term) pathParam; - pathParams.add(new VariableDeclaration(var.getType(), "v" + v)); - } - v++; + // A descendant of the child may generate a component. + List pathParams = new ArrayList<>(); + int v = 1; + ResourceNode descendant = child; + Set childNodes; + do { + Expression pathParam = descendant.getPrimaryResourcePath().getLastParam(); + if (pathParam != null) { + if (pathParam instanceof Variable) { + Variable var = (Variable) pathParam; + pathParams.add(new VariableDeclaration(var.getType(), var.getName())); + } else if (pathParam instanceof Term) { + Term var = (Term) pathParam; + pathParams.add(new VariableDeclaration(var.getType(), "v" + v)); } - String childCompName = getComponentName(child.getResourceHierarchy()); - Type childType = new Type(childCompName, childCompName); - MethodDeclaration childGetter = null; - if (pathParams.size() == 0) { - childGetter = new MethodDeclaration("get" + childCompName, childType); - } else { - childGetter = new MethodDeclaration("get" + childCompName, false, childType, pathParams); - } - component.addMethod(childGetter); + v++; } - } + if (generatesComponent(descendant.getResourceHierarchy())) { + // If the descendant generates a component. + if (!descendants.contains(descendant.getResourceHierarchy())) { + descendants.add(descendant.getResourceHierarchy()); + String descendantCompName = getComponentName(descendant.getResourceHierarchy()); + Type descendantType = new Type(descendantCompName, descendantCompName); + MethodDeclaration descendantGetter = null; + if (pathParams.size() == 0) { + descendantGetter = new MethodDeclaration("get" + descendantCompName, descendantType); + } else { + descendantGetter = new MethodDeclaration("get" + descendantCompName, false, descendantType, pathParams); + } + component.addMethod(descendantGetter); + } + break; + } + childNodes = descendant.getChildren(); + } while (childNodes != null && childNodes.size() == 1 && (descendant = childNodes.iterator().next()) != null); } } @@ -380,30 +389,40 @@ } } - // Declare the getter method to obtain the resource state in the parent component. + // Declare the getter method to obtain the resource state in an ancestor component. if (component == null) { // No component is created for this resource. + ResourceNode ancestorNode = resourceNode; + Stack ancestors = new Stack<>(); + do { + ancestors.push(ancestorNode); + ancestorNode = ancestorNode.getParent(); + } while (!generatesComponent(ancestorNode.getResourceHierarchy())); + List pathParams = new ArrayList<>(); + int v = 1; + while (ancestors.size() > 0) { + ResourceNode curAncestor = ancestors.pop(); + Expression pathParam = curAncestor.getPrimaryResourcePath().getLastParam(); + if (pathParam instanceof Variable) { + Variable var = (Variable) pathParam; + pathParams.add(new VariableDeclaration(var.getType(), var.getName())); + } else if (pathParam instanceof Term) { + Term var = (Term) pathParam; + pathParams.add(new VariableDeclaration(var.getType(), "v" + v)); + } + v++; + } String getterName = "get" + getComponentName(resourceNode.getResourceHierarchy()); boolean bExists = false; for (Map.Entry entry: getters) { - if (entry.getKey() == resourceNode.getParent().getResourceHierarchy() && entry.getValue().getName().equals(getterName)) { + ResourceHierarchy r = entry.getKey(); + MethodDeclaration m = entry.getValue(); + if (r == ancestorNode.getResourceHierarchy() && m.getName().equals(getterName) && m.getParameters().size() == pathParams.size()) { bExists = true; break; } } if (!bExists) { - List pathParams = new ArrayList<>(); - int v = 1; - for (Selector pathParam: resourceNode.getSelectors()) { - if (pathParam.getExpression() instanceof Variable) { - Variable var = (Variable) pathParam.getExpression(); - pathParams.add(new VariableDeclaration(var.getType(), var.getName())); - } else if (pathParam.getExpression() instanceof Term) { - Term var = (Term) pathParam.getExpression(); - pathParams.add(new VariableDeclaration(var.getType(), "v" + v)); - } - v++; - } Type resType = getImplStateType(resourceNode.getResourceHierarchy()); MethodDeclaration stateGetter = null; if (pathParams.size() == 0) { @@ -411,7 +430,7 @@ } else { stateGetter = new MethodDeclaration(getterName, false, resType, pathParams); } - getters.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), stateGetter)); + getters.add(new AbstractMap.SimpleEntry<>(ancestorNode.getResourceHierarchy(), stateGetter)); } } @@ -1288,6 +1307,7 @@ // iterate from the `from' resource Term getter = null; int v = 1; + int arity = 2; while (!pathStack.empty()) { curPath = pathStack.pop(); String typeName = getComponentName(curPath.getResourceHierarchy()); @@ -1296,23 +1316,65 @@ String fieldName = toVariableName(typeName); getter = new Field(fieldName, new Type(typeName, typeName)); } else { - Term newGetter = new Term(new Symbol("get" + 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 (generatesComponent(curPath.getResourceHierarchy())) { + if (arity == 2) { + Term newGetter = new Term(new Symbol("get" + 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++; + } } - if (var != null) { - newGetter.addChild(var); - newGetter.getSymbol().setArity(2); + arity = 2; + } else { + // to get a descendant resource directly. + if (arity == 2) { + Term newGetter = new Term(new Symbol("get" + typeName, -1, Symbol.Type.METHOD)); + newGetter.addChild(getter); + getter = newGetter; } - v++; + 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++; + } } - getter = newGetter; } } diff --git a/AlgebraicDataflowArchitectureModel/src/generators/JerseyMethodBodyGenerator.java b/AlgebraicDataflowArchitectureModel/src/generators/JerseyMethodBodyGenerator.java index b50a570..5f8615b 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/JerseyMethodBodyGenerator.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/JerseyMethodBodyGenerator.java @@ -34,6 +34,7 @@ import models.dataConstraintModel.ChannelMember; import models.dataConstraintModel.DataConstraintModel; import models.dataConstraintModel.JsonAccessor; +import models.dataConstraintModel.JsonTerm; import models.dataConstraintModel.ResourceHierarchy; import models.dataConstraintModel.ResourcePath; import models.dataConstraintModel.Selector; @@ -130,17 +131,34 @@ } updateExp = ch.deriveUpdateExpressionOf(out, JerseyCodeGenerator.pushAccessor, inputResourceToStateAccessor).getKey(); } - // Replace Json constructor with a constructor of the child resource. + // Replace Json constructor with a constructor of a descendant resource. ResourceHierarchy outRes = out.getResource().getResourceHierarchy(); if (outRes.getChildren().size() == 1 && outRes.getChildren().iterator().next().getNumParameters() > 0) { - ResourceHierarchy childRes = outRes.getChildren().iterator().next(); - Type childStateType = childRes.getResourceStateType(); - String childComponentName = JerseyCodeGenerator.getComponentName(childRes); - TypeDeclaration childComponent = componentMap.get(childComponentName); - if (DataConstraintModel.typeJson.isAncestorOf(childStateType)) { - replaceJsonTermWithConstructorInvocation(updateExp, childStateType, childComponentName, childComponent); + ResourceHierarchy descendantRes = outRes.getChildren().iterator().next(); + Set children; + do { + if (JerseyCodeGenerator.generatesComponent(descendantRes)) break; + children = descendantRes.getChildren(); + } while (children != null && children.size() == 1 && (descendantRes = children.iterator().next()) != null); + Type descendantStateType = descendantRes.getResourceStateType(); + String descendantComponentName = JerseyCodeGenerator.getComponentName(descendantRes); + TypeDeclaration descendantComponent = componentMap.get(descendantComponentName); + if (DataConstraintModel.typeJson.isAncestorOf(descendantStateType)) { + replaceJsonTermWithConstructorInvocation(updateExp, descendantStateType, descendantComponentName, descendantComponent); } } + // Replace the type of the state field. + Type fieldType = JerseyCodeGenerator.getImplStateType(outRes); + if (updateExp instanceof Term) { + ((Term) updateExp).setType(fieldType); + for (Map.Entry varEnt: ((Term) updateExp).getVariables().entrySet()) { + if (varEnt.getValue().getName().equals("value")) { + varEnt.getValue().setType(fieldType); + } + } + } else if (updateExp instanceof Variable) { + ((Variable) updateExp).setType(fieldType); + } // Add statements to the update method. String[] sideEffects = new String[] {""}; String newState = updateExp.toImplementation(sideEffects); @@ -219,7 +237,7 @@ } v++; } - String ifStatement = "if (" + conditions.toImplementation(new String[] {})+ ") {\n"; + String ifStatement = "if (" + conditions.toImplementation(new String[] {""})+ ") {\n"; update.addFirstStatement(ifStatement + "\t" + updateStatement.replace("\n", "\n\t") + "\n}"); } } @@ -263,7 +281,7 @@ } resExp = ((Term) resExp).getChild(0); } - String resourceAccess = resExp.toImplementation(new String[] {null}); + String resourceAccess = resExp.toImplementation(new String[] {""}); int v = 0; for (VariableDeclaration var: update2.getParameters()) { if (v < out.getResource().getPathParams().size()) { @@ -688,98 +706,127 @@ } } } + // for source nodes for (ResourceHierarchy resource: model.getResourceHierarchies()) { String resourceName = JerseyCodeGenerator.getComponentName(resource); TypeDeclaration component = componentMap.get(resourceName); - if (component != null) { - // state getter method - Type resourceType = JerseyCodeGenerator.getImplStateType(resource); - MethodDeclaration stateGetter = getMethod(component, "getValue"); - if (stateGetter.getBody() == null || stateGetter.getBody().getStatements().size() == 0) { - if (model.isPrimitiveType(resourceType)) { - // primitive type - stateGetter.addStatement("return value;"); - } else { - if (resource.getChildren() != null && resource.getChildren().size() == 1 && resource.getChildren().iterator().next().getNumParameters() > 0) { - // list or map - String implTypeName = resourceType.getImplementationTypeName(); - // copy the current state to be returned as a 'value' - stateGetter.addStatement("return new " + implTypeName + "(value);"); + if (JavaCodeGenerator.generatesComponent(resource)) { + if (component != null) { + // state getter method + Type resourceType = JerseyCodeGenerator.getImplStateType(resource); + MethodDeclaration stateGetter = getMethod(component, "getValue"); + if (stateGetter.getBody() == null || stateGetter.getBody().getStatements().size() == 0) { + if (model.isPrimitiveType(resourceType)) { + // primitive type + stateGetter.addStatement("return value;"); } else { - if (resource.getChildren() == null || resource.getChildren().size() == 0) { - // a leaf resource + if (resource.getChildren() != null && resource.getChildren().size() == 1 && resource.getChildren().iterator().next().getNumParameters() > 0) { + // list or map String implTypeName = resourceType.getImplementationTypeName(); + // copy the current state to be returned as a 'value' stateGetter.addStatement("return new " + implTypeName + "(value);"); } else { - Term composer = null; - Term composerSub = new Constant(DataConstraintModel.nil); - composerSub.setType(DataConstraintModel.typeMap); - for (ResourceHierarchy child: resource.getChildren()) { - String childTypeName = JerseyCodeGenerator.getComponentName(child); - String fieldName = JerseyCodeGenerator.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("getValue", 1, Symbol.Type.METHOD)); - childGetter.addChild(new Field(fieldName, JerseyCodeGenerator.getImplStateType(child))); - } - 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] + "return " + returnValue+ ";"); + if (resource.getChildren() == null || resource.getChildren().size() == 0) { + // a leaf resource + String implTypeName = resourceType.getImplementationTypeName(); + stateGetter.addStatement("return new " + implTypeName + "(value);"); } else { - stateGetter.addStatement("return " + returnValue+ ";"); + Term composer = null; + Term composerSub = new Constant(DataConstraintModel.nil); + composerSub.setType(DataConstraintModel.typeMap); + for (ResourceHierarchy child: resource.getChildren()) { + String childTypeName = JerseyCodeGenerator.getComponentName(child); + String fieldName = JerseyCodeGenerator.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("getValue", 1, Symbol.Type.METHOD)); + childGetter.addChild(new Field(fieldName, JerseyCodeGenerator.getImplStateType(child))); + } + 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] + "return " + returnValue+ ";"); + } else { + stateGetter.addStatement("return " + returnValue+ ";"); + } } } } } - } - - // child getter method - if (resource.getChildren().size() > 0) { - for (ResourceHierarchy child: resource.getChildren()) { - String methodName = "get" + JerseyCodeGenerator.getComponentName(child); - MethodDeclaration childGetter = getMethod(component, methodName); - if (childGetter != null && (childGetter.getBody() == null || childGetter.getBody().getStatements().size() == 0)) { - if (DataConstraintModel.typeList.isAncestorOf(resource.getResourceStateType())) { - Term selector = new Term(DataConstraintModel.get); - selector.addChild(new Field("value")); - selector.addChild(new Variable(childGetter.getParameters().get(childGetter.getParameters().size() - 1).getName())); - selector.setType(childGetter.getReturnType()); - String[] sideEffects = new String[] {null}; - String returnValue = selector.toImplementation(sideEffects); - if (sideEffects[0] != null) childGetter.addStatement(sideEffects[0]); - childGetter.addStatement("return " + returnValue + ";"); - } else if (DataConstraintModel.typeMap.isAncestorOf(resource.getResourceStateType())) { - Term selector = new Term(DataConstraintModel.lookup); - selector.addChild(new Field("value")); - selector.addChild(new Variable(childGetter.getParameters().get(childGetter.getParameters().size() - 1).getName())); - selector.setType(childGetter.getReturnType()); - String[] sideEffects = new String[] {null}; - String returnValue = selector.toImplementation(sideEffects); - if (sideEffects[0] != null) childGetter.addStatement(sideEffects[0]); - childGetter.addStatement("return " + returnValue+ ";"); + + // descendant getter method + if (resource.getChildren().size() > 0) { + for (ResourceHierarchy child: resource.getChildren()) { + ResourceHierarchy parent = resource; + ResourceHierarchy descendant = child; + Set children; + Expression selector; + int params = 0; + if (DataConstraintModel.typeList.isAncestorOf(parent.getResourceStateType())) { + selector = new Field("value"); + params++; + } else if (DataConstraintModel.typeMap.isAncestorOf(parent.getResourceStateType())) { + selector = new Field("value"); + params++; } else { - String fieldName = JerseyCodeGenerator.getComponentName(child); - String returnValue = JerseyCodeGenerator.toVariableName(fieldName); - childGetter.addStatement("return this." + returnValue + ";"); + String fieldName = JerseyCodeGenerator.getComponentName(descendant); + selector = new Field(JerseyCodeGenerator.toVariableName(fieldName)); } + do { + String methodName = JerseyCodeGenerator.getComponentName(descendant); + MethodDeclaration descendantGetter = null; + for (MethodDeclaration getter: getGetterMethods(component, methodName)) { + if ((getter.getParameters() == null && params == 0) || (getter.getParameters() != null && getter.getParameters().size() == params)) { + descendantGetter = getter; + } + } + if (descendantGetter != null) { + if (DataConstraintModel.typeList.isAncestorOf(parent.getResourceStateType())) { + Term newSelector = new Term(DataConstraintModel.get); + newSelector.addChild(selector); + newSelector.addChild(new Variable(descendantGetter.getParameters().get(descendantGetter.getParameters().size() - 1).getName())); + newSelector.setType(descendantGetter.getReturnType()); + selector = newSelector; + params++; + } else if (DataConstraintModel.typeMap.isAncestorOf(parent.getResourceStateType())) { + Term newSelector = new Term(DataConstraintModel.lookup); + newSelector.addChild(selector); + newSelector.addChild(new Variable(descendantGetter.getParameters().get(descendantGetter.getParameters().size() - 1).getName())); + newSelector.setType(descendantGetter.getReturnType()); + selector = newSelector; + params++; + } + if (descendantGetter != null && (descendantGetter.getBody() == null || descendantGetter.getBody().getStatements().size() == 0)) { + String[] sideEffects = new String[] {""}; + String returnValue = selector.toImplementation(sideEffects); + if (sideEffects[0] != null) descendantGetter.addStatement(sideEffects[0]); + descendantGetter.addStatement("return " + returnValue + ";"); + } + } + if (JerseyCodeGenerator.generatesComponent(descendant)) { + // If the descendant generates a component. + break; + } + parent = descendant; + children = descendant.getChildren(); + } while (children != null && children.size() == 1 && (descendant = children.iterator().next()) != null); } - } - } + } + } } // methods for input events @@ -836,17 +883,34 @@ } } Expression updateExp = ch.deriveUpdateExpressionOf(out, JerseyCodeGenerator.refAccessor).getKey(); - // Replace Json constructor with a constructor of the child resource. + // Replace Json constructor with a constructor of a descendant resource. ResourceHierarchy outRes = out.getResource().getResourceHierarchy(); if (outRes.getChildren().size() == 1 && outRes.getChildren().iterator().next().getNumParameters() > 0) { - ResourceHierarchy childRes = outRes.getChildren().iterator().next(); - Type childStateType = childRes.getResourceStateType(); - String childComponentName = JerseyCodeGenerator.getComponentName(childRes); - TypeDeclaration childComponent = componentMap.get(childComponentName); - if (DataConstraintModel.typeJson.isAncestorOf(childStateType)) { - replaceJsonTermWithConstructorInvocation(updateExp, childStateType, childComponentName, childComponent); + ResourceHierarchy descendantRes = outRes.getChildren().iterator().next(); + Set children; + do { + if (JerseyCodeGenerator.generatesComponent(descendantRes)) break; + children = descendantRes.getChildren(); + } while (children != null && children.size() == 1 && (descendantRes = children.iterator().next()) != null); + Type descendantStateType = descendantRes.getResourceStateType(); + String descendantComponentName = JerseyCodeGenerator.getComponentName(descendantRes); + TypeDeclaration descendantComponent = componentMap.get(descendantComponentName); + if (DataConstraintModel.typeJson.isAncestorOf(descendantStateType)) { + replaceJsonTermWithConstructorInvocation(updateExp, descendantStateType, descendantComponentName, descendantComponent); } } + // Replace the type of the state field. + Type fieldType = JerseyCodeGenerator.getImplStateType(outRes); + if (updateExp instanceof Term) { + ((Term) updateExp).setType(fieldType); + for (Map.Entry varEnt: ((Term) updateExp).getVariables().entrySet()) { + if (varEnt.getValue().getName().equals("value")) { + varEnt.getValue().setType(fieldType); + } + } + } else if (updateExp instanceof Variable) { + ((Variable) updateExp).setType(fieldType); + } // Add statements to the input method. String[] sideEffects = new String[] {""}; String newState = updateExp.toImplementation(sideEffects); @@ -913,7 +977,7 @@ } resExp = ((Term) resExp).getChild(0); } - String resourceAccess = resExp.toImplementation(new String[] {null}); + String resourceAccess = resExp.toImplementation(new String[] {""}); // Values of channel parameters. for (Selector selector: ch.getAllSelectors()) { if (selector.getExpression() instanceof Variable) { @@ -946,41 +1010,57 @@ return codes; } - private static void replaceJsonTermWithConstructorInvocation(Expression exp, Type replacedJsonType, String replacingClassName, TypeDeclaration childComponent) { + private static void replaceJsonTermWithConstructorInvocation(Expression exp, Type replacedJsonType, String replacingClassName, TypeDeclaration descendantComponent) { + Type descendantType = new Type(replacingClassName, replacingClassName); Map subTerms = ((Term) exp).getSubTerms(Term.class); Iterator> termEntItr = subTerms.entrySet().iterator(); while (termEntItr.hasNext()) { Entry termEnt = termEntItr.next(); Term jsonTerm = termEnt.getValue(); - if (jsonTerm.getType() != null && jsonTerm.getType().equals(replacedJsonType)) { - String constructorInvocation = "new " + replacingClassName + "("; - MethodDeclaration childConstructor = getConstructor(childComponent); - String delimiter = ""; - for (VariableDeclaration var: childConstructor.getParameters()) { - JsonAccessor jsonMember = new JsonAccessor(DataConstraintModel.dot); - jsonMember.addChild(jsonTerm); - jsonMember.addChild(new Constant("\"" + var.getName() + "\"")); - Expression param = jsonMember.reduce(); - if (param != null) { - if (param instanceof Term) { - if (((Term) param).getType() == null) { - ((Term) param).setType(var.getType()); + if (jsonTerm.getType() != null) { + if (jsonTerm.getType().equals(replacedJsonType)) { + if (jsonTerm instanceof JsonTerm || jsonTerm.getSymbol().equals(DataConstraintModel.addMember)) { + String constructorInvocation = "new " + replacingClassName + "("; + MethodDeclaration descendantConstructor = getConstructor(descendantComponent); + String delimiter = ""; + for (VariableDeclaration var: descendantConstructor.getParameters()) { + JsonAccessor jsonMember = new JsonAccessor(DataConstraintModel.dot); + jsonMember.addChild(jsonTerm); + jsonMember.addChild(new Constant(var.getName(), DataConstraintModel.typeString)); + Expression param = jsonMember.reduce(); + if (param != null) { + if (param instanceof Term) { + if (((Term) param).getType() == null) { + ((Term) param).setType(var.getType()); + } + } else if (param instanceof Variable) { + if (((Variable) param).getType() == null) { + ((Variable) param).setType(var.getType()); + } + } + constructorInvocation = constructorInvocation + delimiter + param.toImplementation(new String[] {""}); + } else { + constructorInvocation = constructorInvocation + delimiter + var.getName(); } - } else if (param instanceof Variable) { - if (((Variable) param).getType() == null) { - ((Variable) param).setType(var.getType()); - } + delimiter = ", "; } - constructorInvocation = constructorInvocation + delimiter + param.toImplementation(null); + constructorInvocation += ")"; + ((Term) exp).replaceSubTerm(termEnt.getKey(), new Constant(constructorInvocation)); + subTerms = ((Term) exp).getSubTerms(Term.class); + termEntItr = subTerms.entrySet().iterator(); } else { - constructorInvocation = constructorInvocation + delimiter + var.getName(); + jsonTerm.setType(descendantType); } - delimiter = ", "; + } else { + Type oldType = jsonTerm.getType(); + Type newType = new Type(oldType.getTypeName(), + oldType.getImplementationTypeName().replace(replacedJsonType.getInterfaceTypeName(), replacingClassName), + oldType.getInterfaceTypeName().replace(replacedJsonType.getInterfaceTypeName(), replacingClassName)); + for (Type parent: oldType.getParentTypes()) { + newType.addParentType(parent); + } + jsonTerm.setType(newType); } - constructorInvocation += ")"; - ((Term) exp).replaceSubTerm(termEnt.getKey(), new Constant(constructorInvocation)); - subTerms = ((Term) exp).getSubTerms(Term.class); - termEntItr = subTerms.entrySet().iterator(); } } } @@ -1185,13 +1265,6 @@ return null; } - private static MethodDeclaration getGetterMethod(TypeDeclaration component, String resourceName) { - for (MethodDeclaration m: component.getMethods()) { - if (m.getName().startsWith("get" + resourceName)) return m; - } - return null; - } - private static List getUpdateMethods(TypeDeclaration component, String resName) { List updates = new ArrayList<>(); for (MethodDeclaration m: component.getMethods()) { @@ -1208,6 +1281,23 @@ return updates; } + private static MethodDeclaration getGetterMethod(TypeDeclaration component, String resourceName) { + for (MethodDeclaration m: component.getMethods()) { + if (m.getName().startsWith("get" + resourceName)) return m; + } + return null; + } + + private static List getGetterMethods(TypeDeclaration component, String resourceName) { + List getters = new ArrayList<>(); + for (MethodDeclaration m: component.getMethods()) { + if (m.getName().equals("get" + resourceName)) { + getters.add(m); + } + } + return getters; + } + private static Map> getIOChannelsAndMembers(ResourceHierarchy resource, DataTransferModel model) { Map> ioChannelsAndMembers = new HashMap<>(); for (Channel c: model.getInputChannels()) { diff --git a/AlgebraicDataflowArchitectureModel/src/models/algebra/Field.java b/AlgebraicDataflowArchitectureModel/src/models/algebra/Field.java index f51b3c4..6702d3f 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/algebra/Field.java +++ b/AlgebraicDataflowArchitectureModel/src/models/algebra/Field.java @@ -14,7 +14,8 @@ } public Field(String name, Type type) { - super(name, type); + super(name); + symbol.setSignature(new Type[] {type}); } public Field(Symbol symbol) { @@ -22,7 +23,7 @@ } public Type getType() { - if (symbol.getSignature().length >= 1) { + if (symbol.getSignature() != null && symbol.getSignature().length >= 1) { return symbol.getSignature()[0]; } return null; diff --git a/AlgebraicDataflowArchitectureModel/src/models/algebra/Parameter.java b/AlgebraicDataflowArchitectureModel/src/models/algebra/Parameter.java index 739ab80..ab84998 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/algebra/Parameter.java +++ b/AlgebraicDataflowArchitectureModel/src/models/algebra/Parameter.java @@ -12,7 +12,8 @@ } public Parameter(String name, Type type) { - super(name, type); + super(name); + symbol.setSignature(new Type[] {type}); } public Parameter(Symbol symbol) { @@ -20,7 +21,7 @@ } public Type getType() { - if (symbol.getSignature().length >= 1) { + if (symbol.getSignature() != null && symbol.getSignature().length >= 1) { return symbol.getSignature()[0]; } return null; diff --git a/AlgebraicDataflowArchitectureModel/src/models/algebra/Term.java b/AlgebraicDataflowArchitectureModel/src/models/algebra/Term.java index 95c2b47..ac41269 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/algebra/Term.java +++ b/AlgebraicDataflowArchitectureModel/src/models/algebra/Term.java @@ -295,22 +295,23 @@ String component0 = components[0].replace("(", "").replace(")", ""); String[] params = component0.split(","); String exp = components[1]; + String receiver = ""; if (implParamOrder == null) { - for (int i = 0; i < params.length; i++) { + receiver = children.get(0).toImplementation(sideEffects); + exp = exp.replace(params[0], receiver); + for (int i = 1; i < params.length; i++) { exp = exp.replace(params[i], children.get(i).toImplementation(sideEffects)); } } else { - for (int i = 0; i < params.length; i++) { + receiver = children.get(implParamOrder[0]).toImplementation(sideEffects); + exp = exp.replace(params[0], receiver); + for (int i = 1; i < params.length; i++) { exp = exp.replace(params[i], children.get(implParamOrder[i]).toImplementation(sideEffects)); } } if (symbol.isImplWithSideEffect()) { sideEffects[0] = sideEffects[0] + exp + ";\n"; - if (implParamOrder == null) { - exp = children.get(0).toImplementation(new String[] {""}); - } else { - exp = children.get(implParamOrder[0]).toImplementation(new String[] {""}); - } + exp = receiver; } return exp; } @@ -333,7 +334,7 @@ String exp = symbol.generate(getType(), childrenTypes, childrenImpl, childrenSideEffects, sideEffects); if (symbol.isImplWithSideEffect()) { sideEffects[0] = sideEffects[0] + exp; - exp = children.get(0).toImplementation(new String[] {""}); // the value of this term + exp = childrenImpl[0]; // the value of this term } return exp; } else { @@ -351,7 +352,7 @@ String exp = symbol.generate(getType(), childrenTypes, childrenImpl, childrenSideEffects, sideEffects); if (symbol.isImplWithSideEffect()) { sideEffects[0] = sideEffects[0] + exp; - exp = children.get(implParamOrder[0]).toImplementation(new String[] {""}); // the value of this term + exp = childrenImpl[0]; // the value of this term } return exp; } @@ -360,14 +361,16 @@ if (implParamOrder == null) { return "(" + children.get(0).toImplementation(sideEffects) + symbol.toImplementation() + children.get(1).toImplementation(sideEffects) + ")"; } else { - return "(" + children.get(implParamOrder[0]).toImplementation(sideEffects) + symbol.toImplementation() + children.get(implParamOrder[1]).toImplementation(sideEffects) + ")"; + return "(" + children.get(implParamOrder[0]).toImplementation(sideEffects) + symbol.toImplementation() + children.get(implParamOrder[1]).toImplementation(sideEffects) + ")"; } } if ((getArity() >= 1 || getArity() == -1) && symbol.isImplMethod()) { if (implParamOrder == null) { String exp = null; + String receiver = ""; if (children.get(0) != null) { - exp = children.get(0).toImplementation(sideEffects) + "." + symbol.toImplementation() + "("; + receiver = children.get(0).toImplementation(sideEffects); + exp = receiver + "." + symbol.toImplementation() + "("; } else { exp = symbol.toImplementation() + "("; } @@ -380,15 +383,12 @@ exp += ")"; if (symbol.isImplWithSideEffect()) { sideEffects[0] = sideEffects[0] + exp + ";\n"; - if (children.get(0) != null) { - exp = children.get(0).toImplementation(new String[] {""}); - } else { - exp = ""; - } + exp = receiver; } return exp; } else { - String exp = children.get(implParamOrder[0]).toImplementation(sideEffects) + "." + symbol.toImplementation() + "("; + String receiver = children.get(implParamOrder[0]).toImplementation(sideEffects); + String exp = receiver + "." + symbol.toImplementation() + "("; String delimiter = ""; for (int i = 1; i < children.size(); i++) { Expression e = children.get(implParamOrder[i]); @@ -398,7 +398,7 @@ exp += ")"; if (symbol.isImplWithSideEffect()) { sideEffects[0] = sideEffects[0] + exp + ";\n"; - exp = children.get(implParamOrder[0]).toImplementation(new String[] {""}); + exp = receiver; } return exp; } diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/DataConstraintModel.java b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/DataConstraintModel.java index 2537a5b..903c152 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/DataConstraintModel.java +++ b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/DataConstraintModel.java @@ -233,7 +233,8 @@ for (String s: childrenSideEffects) { sideEffect[0] += s; } - if (childrenTypes[0].equals(typeString) && childrenTypes[1].equals(typeString)) { + if (childrenTypes[0] != null && childrenTypes[0].equals(typeString) + && childrenTypes[1] != null && childrenTypes[1].equals(typeString)) { return children[0] + ".equals(" + children[1] + ")"; } return "(" + children[0] + "==" + children[1] + ")"; @@ -753,6 +754,7 @@ } }); public static final Symbol nil = new Symbol("nil", 0, Symbol.Type.PREFIX, new Symbol.IImplGenerator() { + final int count[] = {0}; @Override public String generate(Type type, Type[] childrenTypes, String[] children, String[] childrenSideEffects, String[] sideEffect) { String compType = ""; @@ -768,14 +770,18 @@ if (sideEffect == null) { return "new " + implType + "<>()"; } else { - String temp = "temp_nil"; - sideEffect[0] = interfaceType + " " + temp + " = " + "new " + implType + "<" + compType + ">();\n"; + String temp = "temp_nil" + count[0]; + if (sideEffect[0] == null) { + sideEffect[0] = ""; + } + sideEffect[0] += interfaceType + " " + temp + " = " + "new " + implType + "<" + compType + ">();\n"; + count[0]++; return temp; } } return "new ArrayList<" + compType + ">()"; } - }); + }, true); public static final Symbol null_ = new Symbol("null", 0, Symbol.Type.PREFIX, "null", Symbol.Type.PREFIX); public static final Symbol true_ = new Symbol("true", 0, Symbol.Type.PREFIX, "true", Symbol.Type.PREFIX); public static final Symbol false_ = new Symbol("false", 0, Symbol.Type.PREFIX, "false", Symbol.Type.PREFIX); diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/ResourceNode.java b/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/ResourceNode.java index 6c2073c..d382534 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/ResourceNode.java +++ b/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/ResourceNode.java @@ -160,6 +160,10 @@ return selectors; } + public Selector getLastSelector() { + return selectors.get(resourceHierarchy.getTotalNumParameters() - 1); + } + public List getAllSelectors() { List selectors = new ArrayList<>(); if (parent != null) {