Skip to content

Commit

Permalink
Merge pull request #987 from jblang94/resolve_issue_925
Browse files Browse the repository at this point in the history
Resolve issue 925
  • Loading branch information
vahdat-ab committed Feb 3, 2017
2 parents dc6201e + d056b7e commit 56a6305
Show file tree
Hide file tree
Showing 26 changed files with 1,457 additions and 0 deletions.
24 changes: 24 additions & 0 deletions build/reference/9072RefactoredFinalState.txt
@@ -0,0 +1,24 @@
W072 Refactored Final State
Errors and Warnings
noreferences

@@description

<h2>Umple sematic warning when do activities, exit actions, outgoing transitions, and/or nested state machines are removed by the compiler from final states.</h2>

<p>
In Umple, final states are allowed to be empty, or they can contain entry actions.
</p>


@@example
@@source manualexamples/W072RefactoredFinalState1.ump
@@endexample

@@example
@@source manualexamples/W072RefactoredFinalState2.ump
@@endexample

@@example
@@source manualexamples/W072RefactoredFinalState3.ump
@@endexample
59 changes: 59 additions & 0 deletions cruise.umple/src/UmpleInternalParser_CodeStateMachine.ump
Expand Up @@ -948,6 +948,52 @@ class UmpleInternalParser
}

}

/* Issue 925 - Final states cannot have do activities, exit actions, transitions,
nor nested state machines
*/
private boolean analyzeFinalState(Token finalStateToken, State finalState)
{
boolean foundInvalidElement = false;

for (Token subToken : finalStateToken.getSubTokens())
{
// Final states are only allowed to contain entry actions
if (isEntryActionToken(subToken))
{
finalState.addAction(analyzeAction(subToken, finalState));
} else if(subToken.is("final"))
{
finalState.setFinalState(true);
} else if(!foundInvalidElement && isInvalidFinalStateElement(subToken))
{
foundInvalidElement = true;
}
}

return foundInvalidElement;
}

// Helper function for issue 925
private boolean isEntryActionToken(Token stateToken)
{
return stateToken.is("entryOrExitAction") && (stateToken.getValue("type").equals("entry"));
}

// Helper function for issue 925
private boolean isExitActionToken(Token stateToken)
{
return stateToken.is("entryOrExitAction") && (stateToken.getValue("type").equals("exit"));
}

// Helper function for issue 925
private boolean isInvalidFinalStateElement(Token stateToken)
{
return stateToken.is("activity") || stateToken.is("transition") || stateToken.is("state") || isExitActionToken(stateToken);
}




private void analyzeState(Token stateToken, State fromState)
{
Expand All @@ -956,6 +1002,19 @@ class UmpleInternalParser
boolean isFinalState = false;
String changeType = null;

if (stateToken.getSubToken("final") != null)
{
boolean foundInvalidElement = analyzeFinalState(stateToken, fromState);
if (foundInvalidElement)
{
getParseResult().addErrorMessage(new ErrorMessage(72,
fromState.getPosition(),
fromState.getName(),
fromState.getStateMachine().getName()));
}
return;
}

for(Token subToken : stateToken.getSubTokens())
{

Expand Down
1 change: 1 addition & 0 deletions cruise.umple/src/en.error
Expand Up @@ -76,6 +76,7 @@
69: 4, "http://cruise.eecs.uottawa.ca/umple/PageBeingDeveloped.html", Auto-Transition to '{0}' on line '{1}' conflicts with a previous exisiting transition. This transition is being disconsidered;
70: 4, "http://cruise.eecs.uottawa.ca/umple/W054DuplicateEvents.html", Guarded Transition {0} will be ignored due to a duplicate event with an equivalent guard;
71: 4, "http://cruise.eecs.uottawa.ca/umple/W071DuplicateMethodDifferentType.html", A {6} implementation of Method '{0}' in class '{1}' is already defined at line {2} of '{3}' file, which returns a different type. New definition at line {4} of '{5}' file is being disconsidered;
72: 4, "http://cruise.eecs.uottawa.ca/umple/PageBeingDeveloped.html", Removed do activities, exit actions, transitions, and/or nested state machines from final State '{0}' of StateMachine '{1}';

80: 4, "http://cruise.eecs.uottawa.ca/umple/PageBeingDeveloped.html", State '{0}' was not found in state machine '{1}'. Processed as if the state exists ;

Expand Down
@@ -0,0 +1,14 @@
class X {
status{
on{
turnoff -> off;
powerOff-> FINAL;
}
off{
turnOn -> on;
}
final FINAL{
do{exe();}
}
}
}
@@ -0,0 +1,14 @@
class X {
status{
on{
turnoff -> off;
powerOff-> FINAL;
}
off{
turnOn -> on;
}
final FINAL{
entry/{entry();}
}
}
}
@@ -0,0 +1,14 @@
class X {
status{
on{
turnoff -> off;
powerOff-> FINAL;
}
off{
turnOn -> on;
}
final FINAL{
exit/{exit();}
}
}
}
@@ -0,0 +1,21 @@
class X {
status{
on{
turnoff -> off;
powerOff-> FINAL;
}
off{
turnOn -> on;
}
final FINAL{
nestedSm {
s1 {
-> s2;
}
s2 {

}
}
}
}
}
@@ -0,0 +1,14 @@
class X {
status{
on{
turnoff -> off;
powerOff-> FINAL;
}
off{
turnOn -> on;
}
final FINAL{
reboot -> on;
}
}
}
14 changes: 14 additions & 0 deletions cruise.umple/test/cruise/umple/compiler/486_finalState_isEmpty.ump
@@ -0,0 +1,14 @@
class X {
status{
on{
turnoff -> off;
powerOff-> FINAL;
}
off{
turnOn -> on;
}
final FINAL{

}
}
}
Expand Up @@ -2632,6 +2632,25 @@ public void walkGraphTwice_StateMachineGraph_ClearNodes()

Assert.assertEquals(expectedStates, returnedStates);
}

@Test
public void refactorFinalState()
{
assertHasWarning("486_finalState_hasDoActivity.ump", 0, 72, new Position("486_finalState_hasDoActivity.ump", 5, 17, 67));
for (ErrorMessage er : parser.getParseResult().getErrorMessages())
System.out.println(er.getFormattedMessage());
assertHasWarning("486_finalState_hasExitAction.ump", 0, 72, new Position("486_finalState_hasExitAction.ump", 5, 17, 67));
for (ErrorMessage er : parser.getParseResult().getErrorMessages())
System.out.println(er.getFormattedMessage());
assertHasWarning("486_finalState_hasTransition.ump", 0, 72, new Position("486_finalState_hasTransition.ump", 5, 17, 67));
for (ErrorMessage er : parser.getParseResult().getErrorMessages())
System.out.println(er.getFormattedMessage());
assertHasWarning("486_finalState_hasNestedStateMachine.ump", 0, 72, new Position("486_finalState_hasNestedStateMachine.ump", 5, 17, 67));
for (ErrorMessage er : parser.getParseResult().getErrorMessages())
System.out.println(er.getFormattedMessage());
assertNoWarnings("486_finalState_hasEntryAction.ump");
assertNoWarnings("486_finalState_isEmpty.ump");
}

public void walkGraphTwiceNested_StateMachineGraph_ClearNodes()
{
Expand Down
Expand Up @@ -714,4 +714,28 @@ public void equivalentGuards()
assertUmpleTemplateFor("equivalentGuards.ump",languagePath + "/equivalentGuards."+ languagePath +".txt","A");
}

@Test
public void refactorFinalState_hasAllInvalidElements()
{
assertUmpleTemplateFor("refactorFinalState_hasAllInvalidElements.ump",languagePath + "/refactorFinalState_hasAllInvalidElements."+ languagePath +".txt","X");
}

@Test
public void refactorFinalState_onlyEntryAction()
{
assertUmpleTemplateFor("refactorFinalState_onlyEntryAction.ump",languagePath + "/refactorFinalState_onlyEntryAction."+ languagePath +".txt","X");
}

@Test
public void refactorFinalState_empty()
{
assertUmpleTemplateFor("refactorFinalState_empty.ump",languagePath + "/refactorFinalState_empty."+ languagePath +".txt","X");
}

@Test
public void refactorFinalState_invalidElementsInNestedFinalState()
{
assertUmpleTemplateFor("refactorFinalState_invalidElementsInNestedFinalState.ump",languagePath + "/refactorFinalState_invalidElementsInNestedFinalState."+ languagePath +".txt","X");
}

}
@@ -0,0 +1,111 @@
/*PLEASE DO NOT EDIT THIS CODE*/
/*This code was generated using the UMPLE @UMPLE_VERSION@ modeling language!*/

package example;

public class X
{

//------------------------
// MEMBER VARIABLES
//------------------------

//X State Machines
public enum Status { on, off, FINAL }
private Status status;

//------------------------
// CONSTRUCTOR
//------------------------

public X()
{
setStatus(Status.on);
}

//------------------------
// INTERFACE
//------------------------

public String getStatusFullName()
{
String answer = status.toString();
return answer;
}

public Status getStatus()
{
return status;
}

public boolean turnoff()
{
boolean wasEventProcessed = false;

Status aStatus = status;
switch (aStatus)
{
case on:
setStatus(Status.off);
wasEventProcessed = true;
break;
default:
// Other states do respond to this event
}

return wasEventProcessed;
}

public boolean powerOff()
{
boolean wasEventProcessed = false;

Status aStatus = status;
switch (aStatus)
{
case on:
setStatus(Status.FINAL);
wasEventProcessed = true;
break;
default:
// Other states do respond to this event
}

return wasEventProcessed;
}

public boolean turnOn()
{
boolean wasEventProcessed = false;

Status aStatus = status;
switch (aStatus)
{
case off:
setStatus(Status.on);
wasEventProcessed = true;
break;
default:
// Other states do respond to this event
}

return wasEventProcessed;
}

private void setStatus(Status aStatus)
{
status = aStatus;

// entry actions and do activities
switch(status)
{
case FINAL:
delete();
break;
}
}

public void delete()
{}

}

0 comments on commit 56a6305

Please sign in to comment.