Skip to content

Commit

Permalink
Update with nested
Browse files Browse the repository at this point in the history
  • Loading branch information
pwang347 committed Oct 8, 2018
1 parent d7bf736 commit 3d4cf9b
Show file tree
Hide file tree
Showing 12 changed files with 182 additions and 93 deletions.
4 changes: 2 additions & 2 deletions UmpleToJava/UmpleTLTemplates/JavaClassGenerator.ump
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use queued_state_machine_removalThread_run.ump;
use state_machine_Events_All.ump;
use state_machine_Get_All.ump;
use state_machine_Set_All.ump;
use state_machine_StatefulMethods_All.ump;
use state_machine_StateDependentMethods_All.ump;
use state_machine_doActivity_All.ump;
use state_machine_timedEvent_All.ump;
use toString_declare.ump;
Expand Down Expand Up @@ -317,7 +317,7 @@ for (StateMachine smq : uClass.getStateMachines())
}
private String getStateMachine1Code(StringBuilder realSb, UmpleModel model,UmpleClass uClass, GeneratedClass gClass, JavaGenerator gen, boolean isFirst, boolean isFake)
{
Integer baseJavaLine = realSb.toString().split("\\n").length;#>><<@ UmpleToJava.state_machine_Get_All >><<@ UmpleToJava.state_machine_StatefulMethods_All >><<@ UmpleToJava.state_machine_Events_All >><<@ UmpleToJava.state_machine_Set_All >><<#
Integer baseJavaLine = realSb.toString().split("\\n").length;#>><<@ UmpleToJava.state_machine_Get_All >><<@ UmpleToJava.state_machine_StateDependentMethods_All >><<@ UmpleToJava.state_machine_Events_All >><<@ UmpleToJava.state_machine_Set_All >><<#
return realSb.toString();
}
private String getAssociationCode(StringBuilder realSb, UmpleModel model,UmpleClass uClass, GeneratedClass gClass, JavaGenerator gen, boolean isFirst, boolean isFake)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
class UmpleToJava {
state_machine_StateDependentMethods_All <<!<</*state_machine_StateDependentMethods_All*/>><<#
// Issue #1351
if (!uClass.getStateDependentMethods().isEmpty()) {

// Effectively a lambda function below, so that we can keep code related
// to state-dependent method generation all in one space
abstract class StateDependentTreeTraversal {
public abstract void traverse(Method method);
}

StateDependentTreeTraversal t = new StateDependentTreeTraversal() {

// Prints the signature for the state-dependent method
private void printBefore(Method method) {
String methodModifier = method.getModifier().equals("") ? "public" : method.getModifier();
String methodType = method.getType();
String methodName = method.getName();
StringBuilder parameters = new StringBuilder();
String finalParams = "";
if (method.hasMethodParameters())
{
for (MethodParameter aMethodParam : method.getMethodParameters())
{
String paramName = aMethodParam.getName();
String paramType = aMethodParam.getType();
String isList = aMethodParam.getIsList() ? " [] " : " ";
String aSingleParameter = paramType + isList + paramName;
parameters.append(aSingleParameter + ", ");
}

finalParams = parameters.toString().substring(0, parameters.toString().length()-2);
}

StringBuilder methodExceptionsBuilder = new StringBuilder();
if(method.getExceptions()!=null&&method.numberOfExceptions()>0)
{
methodExceptionsBuilder.append(" throws ");
String exceptioncomma = "";
for(String methodException:method.getExceptions())
{
if(!"".equals(methodException))
{
methodExceptionsBuilder.append(exceptioncomma);
methodExceptionsBuilder.append(methodException);
exceptioncomma = ",";
}
}
}

String methodExceptions = methodExceptionsBuilder.toString();
append(realSb, "\n {0} {1} {2}({3}){4}", methodModifier, methodType, methodName, finalParams, methodExceptions);
}

// Prints the state-dependent method as defined within the UmpleClass
public void traverse(Method method)
{
printBefore(method);
Map<State, MethodBody> stateMap = uClass.stateDependentMethodBodyMap.get(method);
MethodBody defaultBody = stateMap.getOrDefault(null, null);
for (StateMachine sm : uClass.getStateMachines())
{
StringBuilder smBuilder = new StringBuilder();
boolean foundMethod = traverse(method, sm, null, defaultBody, stateMap, smBuilder, 1);
if (foundMethod) realSb.append(smBuilder.toString());
}

realSb.append("\n }\n }\n");
}

// Returns true if methods were found. Do not use results of StringBuilder otherwise.
private boolean traverse(Method method, StateMachine sm, State fromState, MethodBody defaultBody, Map<State, MethodBody> stateMap, StringBuilder builder, int depth) {
boolean foundMethod = false;

// Handle leaf node
if (fromState != null && fromState.getNestedStateMachines().isEmpty())
{
MethodBody body = stateMap.getOrDefault(fromState, null);
foundMethod = body != null;
if (foundMethod) append(realSb, "\n {0}", method.getMethodBody().getCodeblock().getCode());
return foundMethod;
}

// Repeat spacing based on depth
String spacing = new String(new char[depth]).replace("\0", " ");

// Non-trivial states should have a switch case:
append(builder, "\n{0}{ switch({1})\n{0} {\n", spacing, gen.translate("stateMachineOne", sm));

// Loop over states and recurse
for (State state : sm.getStates())
{
// Hierarchically set the default body based on state
MethodBody childDefaultBody = stateMap.getOrDefault(state, defaultBody);
for (StateMachine nestedSm : children)
{
foundMethod = traverse(method, nestedSm, state, childDefaultBody, stateMap, builder, depth + 1)
|| foundMethod;
}
}

// Output the default value and close brace
String defaultValue = (defaultBody == null) ?
gen.translate(method.getType()) : defaultBody.getCodeblock().getCode();
append(builder, "{0} default:\n{1}", spacing, defaultValue);
return foundMethod;
}
};

// Generate state-dependent methods
for (Method method : uClass.stateDependentMethods)
{
t.traverse(method);
}
}
#>>
!>>
}
56 changes: 0 additions & 56 deletions UmpleToJava/UmpleTLTemplates/state_machine_StatefulMethods_All.ump

This file was deleted.

22 changes: 22 additions & 0 deletions cruise.umple/src/StateDependentMethods.ump
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
namespace cruise.umple.compiler;

class UmpleClass {
depend java.util.*;
0..1 -- * Method stateDependentMethods;
public Map<Method, Map<State, MethodBody>> stateDependentMethodBodyMap = new HashMap<Method, Map<State, MethodBody>>();

// See issue #1351. Adds a state-dependent method mapping for the current Umple class.
public boolean addStateDependentMethod(Method method, State state)
{
boolean wasAdded = false;
if (!stateDependentMethods.contains(method))
{
stateDependentMethods.add(method);
}
Map<State, MethodBody> stateMap = stateDependentMethodBodyMap
.computeIfAbsent(method, k -> new HashMap<State, MethodBody>());
stateMap.put(state, method.getMethodBody());
return wasAdded;
}
}

3 changes: 1 addition & 2 deletions cruise.umple/src/StateMachine.ump
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,7 @@ class StateMachine
name;
Boolean containsHistoryState = false;
Boolean containsDeepHistoryState = false;
Map<Integer, Map<State, Method>> stateMethodsMap = new HashMap<Integer, Map<State, Method>>();


* -- 0..1 UmpleClass;

* -- 0..1 UmpleTrait;
Expand Down
23 changes: 0 additions & 23 deletions cruise.umple/src/StateMachine_Code.ump
Original file line number Diff line number Diff line change
Expand Up @@ -477,29 +477,6 @@ class StateMachine
return superStateMachine;
}
}

depend java.util.stream.Collectors;

// Issue # 1351
public int getStateMethodId(Method stateMethod) {
String name = stateMethod.getName();
String returnType = stateMethod.getType();
String params = String.join("@DELIM1@", stateMethod.getMethodParameters().stream().map(p ->
p.getName() + "@DELIM2@" + p.getFullType()).collect(Collectors.toList()));
return Arrays.asList(name, returnType, params).hashCode();
}

// Issue # 1351
public boolean addStateMethod(State state, Method stateMethod)
{
boolean wasAdded = false;
Integer key = getStateMethodId(stateMethod);
Map<State, Method> stateMethodsMapInner =
stateMethodsMap.computeIfAbsent(key, (k) -> new HashMap<State, Method>());
stateMethodsMapInner.put(state, stateMethod);
wasAdded = true;
return wasAdded;
}
}

class State
Expand Down
12 changes: 10 additions & 2 deletions cruise.umple/src/UmpleInternalParser_CodeClass.ump
Original file line number Diff line number Diff line change
Expand Up @@ -3285,8 +3285,16 @@ private Boolean checkIsDistributed(UmpleInterface uInterface)
if ((!uClass.hasMethod(aMethod) || uClass.getMethod(aMethod).getIsConstructor()) && shouldAddMethod)
//if (!uClass.hasMethod(aMethod) && shouldAddMethod)
{
uClass.addMethod(aMethod);
}
// See issue #1351. Convert regular methods to default bodies for state-dependent methods
// if they exist.
if (uClass.getStateDependentMethods().contains(aMethod) && !aMethod.isIsAbstract()) {
uClass.addStateDependentMethod(aMethod, null);
}
else
{
uClass.addMethod(aMethod);
}
}

// Make class abstract if an abstract method was added
if(uClass.hasMethod(aMethod) && aMethod.getIsAbstract())
Expand Down
21 changes: 16 additions & 5 deletions cruise.umple/src/UmpleInternalParser_CodeStateMachine.ump
Original file line number Diff line number Diff line change
Expand Up @@ -1067,7 +1067,7 @@ class UmpleInternalParser
}
else if (subToken.is("concreteMethodDeclaration"))
{
analyzeStatefulMethod(subToken, fromState);
analyzeStateDependentMethod(subToken, fromState);
}
else if (subToken.is("activity"))
{
Expand Down Expand Up @@ -1983,10 +1983,21 @@ class UmpleInternalParser

}

private void analyzeStatefulMethod(Token methodToken, State fromState){
private void analyzeStateDependentMethod(Token methodToken, State fromState){
StateMachine sm = fromState.getStateMachine();
Method method = analyzeMethod(methodToken, null, true);
sm.addStateMethod(fromState, method);
}
UmpleClass uClass = sm.getUmpleClass();

// Retrieve method analyzed using the method token
Method analyzedMethod = analyzeMethod(methodToken, null, true);

// Strip off existing method if it exists, and make it the default implementation
Method classMethod = uClass.getMethod(analyzedMethod);
if (classMethod != null) {
uClass.addStateDependentMethod(classMethod, null);
uClass.removeMethod(classMethod);
}

// Add current state-dependent method body to the Umple class
uClass.addStateDependentMethod(analyzedMethod, fromState);
}
}
12 changes: 11 additions & 1 deletion cruise.umple/src/Umple_Code.ump
Original file line number Diff line number Diff line change
Expand Up @@ -963,7 +963,17 @@ class Method

return false;
}


public int hashCode() {
// Note: this uses roughly the same rules as used above to generate a hashCode
// so the two methods should be roughly kept in sync.
String name = getName();
String returnType = getType();
String params = String.join("@DELIM1@", getMethodParameters().stream().map(p ->
p.getName() + "@DELIM2@" + p.getFullType()).collect(Collectors.toList()));
String isConstructor = String.valueOf(isIsConstructor());
return Arrays.asList(name, returnType, params, isConstructor).hashCode();
}
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -310,9 +310,9 @@ public void nestedStates()

// Issue #1351
@Test
public void statefulMethodDeclaration()
public void stateDependentMethodDeclaration()
{
assertUmpleTemplateFor("statefulMethodDeclaration.ump",languagePath + "/statefulMethodDeclaration."+ languagePath +".txt","Portal");
assertUmpleTemplateFor("stateDependentMethodDeclaration.ump",languagePath + "/stateDependentMethodDeclaration."+ languagePath +".txt","Portal");
}

@Test
Expand Down

0 comments on commit 3d4cf9b

Please sign in to comment.