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
(name for name in process.mapping.iterkeys()
if not name.endswith(u'START'))))
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:
process_level_decl.append(u'type States is ({});'
......@@ -2015,17 +2018,42 @@ def _transition(tr, **kwargs):
# TODO
elif tr.terminator.kind == 'return':
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.return_expr:
stmts, string, local = expression(
tr.terminator.return_expr)
code.extend(stmts)
local_decl.extend(local)
code.append('return{};'
code.append(u'return{};'
.format(' ' + string if string else ''))
else:
code.append('trId := ' + str(tr.terminator.next_id) + ';')
code.append('goto next_transition;')
code.append(u'trId := ' + str(tr.terminator.next_id) + ';')
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 transition does not have any statement, generate an Ada 'null;'
code.append('null;')
......
......@@ -49,13 +49,15 @@ def state_aggregations(process):
# { aggregate_name : [list of parallel states] }
aggregates = defaultdict(list)
def do_composite(comp, aggregate=''):
''' Recursively find all state aggregations in order to create
variables to store the state of each parallel state '''
for each in comp.composite_states: # CHECKME
''' Recursively find all state aggregations in order to allow code
generator backends to store the state of each parallel state '''
pre = comp.statename if isinstance(comp, ogAST.StateAggregation) \
else ''
for each in comp.composite_states:
do_composite(each, pre)
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:
if term.inputString.lower() == each.statename.lower():
term.next_is_aggregation = True
......@@ -73,6 +75,14 @@ def state_aggregations(process):
for each in process.terminators:
if each.inputString.lower() in aggregates:
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
......
......@@ -466,6 +466,10 @@ class Terminator(object):
self.composite = None
# Flag to indicate if the nextstate is a state aggregation
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
# of the parallel substate (set by Helper.state_aggregations)
self.substate = ''
......
......@@ -2996,7 +2996,7 @@ def connect_part(root, parent, context):
# Ignore missing parent/statelist to allow local syntax check
statename = ''
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
terms = len(context.terminators)
# Retrieve composite state
......@@ -3046,16 +3046,34 @@ def connect_part(root, parent, context):
id_token[-1].getTokenStopIndex())
for exitp in conn.connect_list:
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),
[conn.pos_x or 0, conn.pos_y or 0], []])
terminators = [term for term in nested.terminators
def check_terminators(comp):
terminators = [term for term in comp.terminators
if term.kind == 'return'
and term.inputString.lower() == exitp]
if not terminators:
errors.append(['No {rs} return statement in nested state {st}'
.format(rs=exitp, st=statename),
errors.append([u'No {rs} return statement in nested state {st}'
.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:
# Set next transition, exact id to be found in postprocessing
each.next_trans = trans
......
......@@ -27,33 +27,6 @@ exit_aggreg;
PROCESS og;
STATE AGGREGATION wait;
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;
SUBSTRUCTURE
in (hehe);
......@@ -88,8 +61,8 @@ exit_aggreg;
INPUT reset_all(x);
/* CIF PROCEDURECALL (407, 158), (260, 35) */
CALL writeln('Reset_all from substate a2');
/* CIF NEXTSTATE (503, 208), (70, 35) */
NEXTSTATE a2;
/* CIF RETURN (520, 208), (35, 35) */
RETURN ;
ENDSTATE;
/* CIF STATE (0, 157), (70, 35) */
STATE a1;
......@@ -101,12 +74,39 @@ exit_aggreg;
NEXTSTATE a2;
ENDSTATE;
ENDSUBSTRUCTURE;
/* CIF STATE (170, 50), (70, 35) */
STATE a;
STATE b;
SUBSTRUCTURE
/* 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) */
STATE b;
ENDSTATE;
/* CIF STATE (170, 50), (70, 35) */
STATE a;
ENDSTATE;
ENDSUBSTRUCTURE;
/* CIF TEXT (997, 328), (289, 140) */
-- Text area for declarations and comments
......@@ -117,23 +117,29 @@ dcl x myInteger;
START;
/* CIF NEXTSTATE (0, 299), (70, 35) */
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) */
STATE wait;
/* CIF INPUT (368, 362), (110, 35) */
/* CIF INPUT (202, 362), (110, 35) */
INPUT exit_aggreg;
/* CIF PROCEDURECALL (325, 412), (195, 34) */
/* CIF PROCEDURECALL (159, 412), (195, 34) */
CALL writeln('got exit_aggreg');
/* CIF NEXTSTATE (379, 461), (87, 35) */
/* CIF NEXTSTATE (213, 461), (87, 35) */
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;
ENDPROCESS og;
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