Commit e7046b04 authored by Maxime Perrotin's avatar Maxime Perrotin
Browse files

Synchronize parall states when they return

parent d6e5d09a
...@@ -205,6 +205,9 @@ LD_LIBRARY_PATH=. taste-gui -l ...@@ -205,6 +205,9 @@ LD_LIBRARY_PATH=. taste-gui -l
(name for name in process.mapping.iterkeys() (name for name in process.mapping.iterkeys()
if not name.endswith(u'START')))) if not name.endswith(u'START'))))
reduced_statelist = {s for s in full_statelist if s not in parallel_states} reduced_statelist = {s for s in full_statelist if s not in parallel_states}
if parallel_states:
# Parallel states in a state aggregation may terminate
full_statelist.add(u'{}finished'.format(UNICODE_SEP))
if full_statelist: if full_statelist:
process_level_decl.append(u'type States is ({});' process_level_decl.append(u'type States is ({});'
...@@ -2015,17 +2018,42 @@ def _transition(tr, **kwargs): ...@@ -2015,17 +2018,42 @@ def _transition(tr, **kwargs):
# TODO # TODO
elif tr.terminator.kind == 'return': elif tr.terminator.kind == 'return':
string = '' string = ''
aggregate = False
if tr.terminator.substate: # XXX add to C generator
aggregate = True
# within a state aggregation, a return means that one
# of the parallel states becomes disabled, but it does
# not mean that the whole state aggregation can be
# exited. We must set this substate to a "finished"
# state until all the substates are returned. Then only
# call the overall state aggregation exit procedures.
code.append(u'{ctxt}.{sub}{sep}state := {sep}finished;'
.format(ctxt=LPREFIX,
sub=tr.terminator.substate,
sep=UNICODE_SEP))
cond = u'{ctxt}.{sib}{sep}state = {sep}finished'
conds = [cond.format(sib=sib,
ctxt=LPREFIX,
sep=UNICODE_SEP)
for sib in tr.terminator.siblings
if sib.lower() != tr.terminator.substate.lower()]
code.append(u'if {} then'.format(' and '.join(conds)))
if tr.terminator.next_id == -1: if tr.terminator.next_id == -1:
if tr.terminator.return_expr: if tr.terminator.return_expr:
stmts, string, local = expression( stmts, string, local = expression(
tr.terminator.return_expr) tr.terminator.return_expr)
code.extend(stmts) code.extend(stmts)
local_decl.extend(local) local_decl.extend(local)
code.append('return{};' code.append(u'return{};'
.format(' ' + string if string else '')) .format(' ' + string if string else ''))
else: else:
code.append('trId := ' + str(tr.terminator.next_id) + ';') code.append(u'trId := ' + str(tr.terminator.next_id) + ';')
code.append('goto next_transition;') code.append(u'goto next_transition;')
if aggregate:
code.append(u'else')
code.append(u'trId := -1;')
code.append(u'goto next_transition;')
code.append(u'end if;')
if empty_transition: if empty_transition:
# If transition does not have any statement, generate an Ada 'null;' # If transition does not have any statement, generate an Ada 'null;'
code.append('null;') code.append('null;')
......
...@@ -49,13 +49,15 @@ def state_aggregations(process): ...@@ -49,13 +49,15 @@ def state_aggregations(process):
# { aggregate_name : [list of parallel states] } # { aggregate_name : [list of parallel states] }
aggregates = defaultdict(list) aggregates = defaultdict(list)
def do_composite(comp, aggregate=''): def do_composite(comp, aggregate=''):
''' Recursively find all state aggregations in order to create ''' Recursively find all state aggregations in order to allow code
variables to store the state of each parallel state ''' generator backends to store the state of each parallel state '''
for each in comp.composite_states: # CHECKME pre = comp.statename if isinstance(comp, ogAST.StateAggregation) \
pre = comp.statename if isinstance(comp, ogAST.StateAggregation) \
else '' else ''
for each in comp.composite_states:
do_composite(each, pre) do_composite(each, pre)
if isinstance(each, ogAST.StateAggregation): if isinstance(each, ogAST.StateAggregation):
# substate of the current state is a state aggregation
# -> set a flag in each terminator of the current state
for term in comp.terminators: for term in comp.terminators:
if term.inputString.lower() == each.statename.lower(): if term.inputString.lower() == each.statename.lower():
term.next_is_aggregation = True term.next_is_aggregation = True
...@@ -73,6 +75,14 @@ def state_aggregations(process): ...@@ -73,6 +75,14 @@ def state_aggregations(process):
for each in process.terminators: for each in process.terminators:
if each.inputString.lower() in aggregates: if each.inputString.lower() in aggregates:
each.next_is_aggregation = True each.next_is_aggregation = True
for name, comp in aggregates.viewitems():
# for each state aggregation. update the terminators
# of each parallel state with the name of all sibling states
# useful for backends to handle parallel state termination (return)
# since they have to synchronize with the sibling states
siblings = [sib.statename for sib in comp]
for term in [terms for sib in comp for terms in sib.terminators]:
term.siblings = siblings
return aggregates return aggregates
......
...@@ -466,6 +466,10 @@ class Terminator(object): ...@@ -466,6 +466,10 @@ class Terminator(object):
self.composite = None self.composite = None
# Flag to indicate if the nextstate is a state aggregation # Flag to indicate if the nextstate is a state aggregation
self.next_is_aggregation = False self.next_is_aggregation = False
# List of sibling states if terminator is within a state aggregation
# (list of strings with all parallel states of the aggregation)
# Used by backend to synchronise parallel state terminations
self.siblings = []
# If this terminator is within a state aggregation, store the name # If this terminator is within a state aggregation, store the name
# of the parallel substate (set by Helper.state_aggregations) # of the parallel substate (set by Helper.state_aggregations)
self.substate = '' self.substate = ''
......
...@@ -2996,7 +2996,7 @@ def connect_part(root, parent, context): ...@@ -2996,7 +2996,7 @@ def connect_part(root, parent, context):
# Ignore missing parent/statelist to allow local syntax check # Ignore missing parent/statelist to allow local syntax check
statename = '' statename = ''
id_token = [] id_token = []
# Keep track of the number of terminator statements follow the input # Keep track of the number of terminator statements following the input
# useful if we want to render graphs from the SDL model # useful if we want to render graphs from the SDL model
terms = len(context.terminators) terms = len(context.terminators)
# Retrieve composite state # Retrieve composite state
...@@ -3046,16 +3046,34 @@ def connect_part(root, parent, context): ...@@ -3046,16 +3046,34 @@ def connect_part(root, parent, context):
id_token[-1].getTokenStopIndex()) id_token[-1].getTokenStopIndex())
for exitp in conn.connect_list: for exitp in conn.connect_list:
if exitp != '' and not exitp in nested.state_exitpoints: if exitp != '' and not exitp in nested.state_exitpoints:
errors.append(['Exit point {ep} not defined in state {st}' errors.append([u'Exit point {ep} not defined in state {st}'
.format(ep=exitp, st=statename), .format(ep=exitp, st=statename),
[conn.pos_x or 0, conn.pos_y or 0], []]) [conn.pos_x or 0, conn.pos_y or 0], []])
terminators = [term for term in nested.terminators def check_terminators(comp):
if term.kind == 'return' terminators = [term for term in comp.terminators
and term.inputString.lower() == exitp] if term.kind == 'return'
if not terminators: and term.inputString.lower() == exitp]
errors.append(['No {rs} return statement in nested state {st}' if not terminators:
.format(rs=exitp, st=statename), errors.append([u'No {rs} return statement in nested state {st}'
[conn.pos_x or 0, conn.pos_y or 0], []]) .format(rs=exitp, st=comp.statename.lower()),
[conn.pos_x or 0, conn.pos_y or 0], []])
return terminators
if not isinstance(nested, ogAST.StateAggregation):
terminators = check_terminators(nested)
else:
# State aggregation: we must check that all parallel states
# contain indeed a return statement of the given name
def siblings(aggregate):
for comp in aggregate.composite_states:
if not isinstance(comp, ogAST.StateAggregation):
yield comp
else:
for each in siblings(comp()):
yield each
all_terms = map(check_terminators, siblings(nested))
terminators = []
map(terminators.extend, all_terms)
for each in terminators: for each in terminators:
# Set next transition, exact id to be found in postprocessing # Set next transition, exact id to be found in postprocessing
each.next_trans = trans each.next_trans = trans
......
...@@ -27,33 +27,6 @@ exit_aggreg; ...@@ -27,33 +27,6 @@ exit_aggreg;
PROCESS og; PROCESS og;
STATE AGGREGATION wait; STATE AGGREGATION wait;
SUBSTRUCTURE SUBSTRUCTURE
STATE b;
SUBSTRUCTURE
/* CIF START (146, 55), (70, 35) */
START;
/* CIF PROCEDURECALL (77, 105), (208, 35) */
CALL writeln('[b] startup');
/* CIF NEXTSTATE (146, 155), (70, 35) */
NEXTSTATE b1;
/* CIF STATE (392, 144), (70, 35) */
STATE b2;
/* CIF INPUT (388, 199), (79, 35) */
INPUT for_b;
/* CIF PROCEDURECALL (308, 249), (239, 35) */
CALL writeln('[b] Going to b1');
/* CIF NEXTSTATE (392, 299), (70, 35) */
NEXTSTATE b1;
ENDSTATE;
/* CIF STATE (146, 155), (70, 35) */
STATE b1;
/* CIF INPUT (138, 210), (80, 35) */
INPUT for_b;
/* CIF PROCEDURECALL (58, 260), (239, 35) */
CALL writeln('[b] Going to b2');
/* CIF NEXTSTATE (143, 310), (70, 35) */
NEXTSTATE b2;
ENDSTATE;
ENDSUBSTRUCTURE;
STATE a; STATE a;
SUBSTRUCTURE SUBSTRUCTURE
in (hehe); in (hehe);
...@@ -88,8 +61,8 @@ exit_aggreg; ...@@ -88,8 +61,8 @@ exit_aggreg;
INPUT reset_all(x); INPUT reset_all(x);
/* CIF PROCEDURECALL (407, 158), (260, 35) */ /* CIF PROCEDURECALL (407, 158), (260, 35) */
CALL writeln('Reset_all from substate a2'); CALL writeln('Reset_all from substate a2');
/* CIF NEXTSTATE (503, 208), (70, 35) */ /* CIF RETURN (520, 208), (35, 35) */
NEXTSTATE a2; RETURN ;
ENDSTATE; ENDSTATE;
/* CIF STATE (0, 157), (70, 35) */ /* CIF STATE (0, 157), (70, 35) */
STATE a1; STATE a1;
...@@ -101,12 +74,39 @@ exit_aggreg; ...@@ -101,12 +74,39 @@ exit_aggreg;
NEXTSTATE a2; NEXTSTATE a2;
ENDSTATE; ENDSTATE;
ENDSUBSTRUCTURE; ENDSUBSTRUCTURE;
/* CIF STATE (170, 50), (70, 35) */ STATE b;
STATE a; SUBSTRUCTURE
ENDSTATE; /* CIF START (85, 55), (70, 35) */
START;
/* CIF PROCEDURECALL (16, 105), (208, 35) */
CALL writeln('[b] startup');
/* CIF NEXTSTATE (85, 155), (70, 35) */
NEXTSTATE b1;
/* CIF STATE (392, 144), (70, 35) */
STATE b2;
/* CIF INPUT (388, 199), (79, 35) */
INPUT for_b;
/* CIF PROCEDURECALL (267, 249), (321, 35) */
CALL writeln('[b] got for_b in b2, exiting state b...');
/* CIF RETURN (410, 299), (35, 35) */
RETURN ;
ENDSTATE;
/* CIF STATE (85, 155), (70, 35) */
STATE b1;
/* CIF INPUT (77, 210), (80, 35) */
INPUT for_b;
/* CIF PROCEDURECALL (-1, 260), (239, 35) */
CALL writeln('[b] Going to b2');
/* CIF NEXTSTATE (82, 310), (70, 35) */
NEXTSTATE b2;
ENDSTATE;
ENDSUBSTRUCTURE;
/* CIF STATE (170, 160), (70, 35) */ /* CIF STATE (170, 160), (70, 35) */
STATE b; STATE b;
ENDSTATE; ENDSTATE;
/* CIF STATE (170, 50), (70, 35) */
STATE a;
ENDSTATE;
ENDSUBSTRUCTURE; ENDSUBSTRUCTURE;
/* CIF TEXT (997, 328), (289, 140) */ /* CIF TEXT (997, 328), (289, 140) */
-- Text area for declarations and comments -- Text area for declarations and comments
...@@ -117,23 +117,29 @@ dcl x myInteger; ...@@ -117,23 +117,29 @@ dcl x myInteger;
START; START;
/* CIF NEXTSTATE (0, 299), (70, 35) */ /* CIF NEXTSTATE (0, 299), (70, 35) */
NEXTSTATE wait; NEXTSTATE wait;
/* CIF STATE (649, 303), (87, 35) */
STATE the_end;
/* CIF INPUT (640, 358), (107, 35) */
INPUT reset_all(x);
/* CIF PROCEDURECALL (543, 408), (300, 35) */
CALL writeln('Entering again aggregation');
/* CIF NEXTSTATE (658, 458), (70, 35) */
NEXTSTATE wait;
ENDSTATE;
/* CIF STATE (390, 307), (67, 35) */ /* CIF STATE (390, 307), (67, 35) */
STATE wait; STATE wait;
/* CIF INPUT (368, 362), (110, 35) */ /* CIF INPUT (202, 362), (110, 35) */
INPUT exit_aggreg; INPUT exit_aggreg;
/* CIF PROCEDURECALL (325, 412), (195, 34) */ /* CIF PROCEDURECALL (159, 412), (195, 34) */
CALL writeln('got exit_aggreg'); CALL writeln('got exit_aggreg');
/* CIF NEXTSTATE (379, 461), (87, 35) */ /* CIF NEXTSTATE (213, 461), (87, 35) */
NEXTSTATE the_end; NEXTSTATE the_end;
/* CIF CONNECT (506, 362), (0, 35) */
CONNECT ;
/* CIF PROCEDURECALL (365, 412), (281, 34) */
CALL writeln('Synchronous return from wait');
/* CIF NEXTSTATE (462, 461), (87, 35) */
NEXTSTATE the_end;
ENDSTATE;
/* CIF STATE (781, 303), (87, 35) */
STATE the_end;
/* CIF INPUT (772, 358), (107, 35) */
INPUT reset_all(x);
/* CIF PROCEDURECALL (676, 408), (300, 35) */
CALL writeln('Entering again aggregation');
/* CIF NEXTSTATE (791, 458), (70, 35) */
NEXTSTATE wait;
ENDSTATE; ENDSTATE;
ENDPROCESS og; ENDPROCESS og;
ENDBLOCK; ENDBLOCK;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment