Commit 39c9516f authored by Maxime Perrotin's avatar Maxime Perrotin
Browse files

Minor fixes on the handling of scopes when using composite states

parent 533f4d8a
......@@ -140,21 +140,25 @@ def _process(process):
process_level_decl.append(states_decl)
process_level_decl.append('state : states;')
for name, val in process.mapping.viewitems():
if name.endswith('START') and name != 'START':
process_level_decl.append('{name} : constant := {val};'
.format(name=name, val=str(val)))
# Add function allowing to trace current state as a string
process_level_decl.append('function get_state return String;')
process_level_decl.append('pragma export(C, get_state, "{}_state");'
.format(process_name))
#process_level_decl.append('function get_state return String;')
#process_level_decl.append('pragma export(C, get_state, "{}_state");'
# .format(process_name))
# Add the declaration of the runTransition procedure
process_level_decl.append('procedure runTransition(Id: Integer);')
process_level_decl.append('procedure start;')
process_level_decl.append('pragma export(C, start, "{}_start");'
.format(process_name))
process_level_decl.append('procedure state_start;')
#process_level_decl.append('pragma export(C, start, "{}_start");'
# .format(process_name))
# Generate the code of the start transition:
start_transition = ['begin']
start_transition.append('start;')
start_transition = ['begin',
'runTransition(0);']
mapping = {}
# Generate the code for the transitions in a mapping input-state
......@@ -216,10 +220,10 @@ package {process_name} is'''.format(process_name=process_name,
# Generate the code for the start procedure
taste_template.extend([
'procedure start is',
'procedure state_start is',
'begin',
'runTransition(0);',
'end start;', ''])
'null;',
'end state_start;', ''])
# Add the code of the procedures definitions
taste_template.extend(inner_procedures_code)
......@@ -380,11 +384,11 @@ package {process_name} is'''.format(process_name=process_name,
taste_template.append('\n')
# Code of the function allowing to trace current state
taste_template.append('function get_state return String is')
taste_template.append('begin')
taste_template.append("return states'Image(state);")
taste_template.append('end get_state;')
taste_template.append('\n')
#taste_template.append('function get_state return String is')
#taste_template.append('begin')
#taste_template.append("return states'Image(state);")
#taste_template.append('end get_state;')
#taste_template.append('\n')
taste_template.extend(start_transition)
......@@ -1273,12 +1277,27 @@ def _transition(tr):
code.append('<<{label}>>'.format(
label=tr.terminator.label.inputString))
if tr.terminator.kind == 'next_state':
code.append('trId := ' + str(tr.terminator.next_id) + ';')
if tr.terminator.inputString.strip() != '-':
# discard the dash state (remain in the same state)
code.append('trId := ' + str(tr.terminator.next_id) + ';')
if tr.terminator.next_id == -1:
code.append('state := {nextState};'.format(
nextState=tr.terminator.inputString))
else:
if any(next_id
for next_id in tr.terminator.candidate_id.viewkeys()
if next_id != -1):
code.append('case state is')
for nid, sta in tr.terminator.candidate_id.viewitems():
if nid != -1:
for each in sta:
code.extend(['when {} =>'.format(each),
'trId := {};'.format(nid)])
code.extend(['when others =>',
'trId := -1;',
'end case;'])
else:
code.append('trId := -1;')
code.append('goto next_transition;')
elif tr.terminator.kind == 'join':
code.append('goto {label};'.format(
......
......@@ -19,6 +19,7 @@
import logging
from itertools import chain
from collections import defaultdict
from singledispatch import singledispatch
......@@ -59,13 +60,26 @@ def flatten(process):
if term.inputString.lower() in (st.statename.lower()
for st in context.composite_states):
if not term.via:
term.next_id = process.mapping \
[term.inputString.lower() + '_START']
term.next_id = term.inputString.lower() + '_START'
#process.mapping \
# [term.inputString.lower() + '_START']
else:
term.next_id = process.mapping[term.inputString.lower()
+ '_'
+ term.entrypoint.lower()
+ '_START']
term.next_id = '{term}_{entry}_START'.format(
term=term.inputString, entry=term.entrypoint)
#process.mapping[term.inputString.lower()
# + '_'
# + term.entrypoint.lower()
# + '_START']
elif term.inputString.strip() == '-':
term.candidate_id = defaultdict(list)
for each in term.possible_states:
if each in (st.statename.lower()
for st in context.composite_states):
term.candidate_id[each + '_START'] = \
[st for st in process.mapping.viewkeys()
if st.startswith(each) and not st.endswith('_START')]
else:
term.candidate_id[-1].append(each)
def update_composite_state(state, process):
''' Rename inner states, recursively, and add inner transitions
......@@ -73,6 +87,7 @@ def flatten(process):
'''
trans_idx = len(process.transitions)
prefix = state.statename + '_'
set_terminator_states(state, prefix)
state.mapping = {prefix + key:state.mapping.pop(key)
for key in state.mapping.keys()}
process.transitions.extend(state.transitions)
......@@ -118,14 +133,15 @@ def flatten(process):
# Go recursively in inner composite states
inner.statename = prefix + inner.statename
update_composite_state(inner, process)
propagate_inputs(inner, process.mapping[inner.statename]) # TESTME
propagate_inputs(inner, process.mapping[inner.statename])
del process.mapping[inner.statename]
for each in state.terminators:
# Give prefix to terminators
if each.label:
each.label.inputString = prefix + each.label.inputString
if each.kind == 'next_state':
each.inputString = prefix + each.inputString
if each.inputString.strip() != '-':
each.inputString = prefix + each.inputString
# Set next transition id
update_terminator(context=state, term=each, process=process)
elif each.kind == 'join':
......@@ -162,6 +178,17 @@ def flatten(process):
propagate_inputs(each, nested_state.mapping[each.statename])
#del nested_state.mapping[each.statename]
def set_terminator_states(context, prefix=''):
''' Associate state to terminators, needed to process properly
a history nextstates (dash nextstate) in code generators '''
for each in context.content.states:
for inp in each.inputs:
for term in inp.terminators:
term.possible_states.extend(prefix + name.lower()
for name in each.statelist)
set_terminator_states(process)
for each in process.composite_states:
update_composite_state(each, process)
propagate_inputs(each, process.mapping[each.statename])
......@@ -198,7 +225,7 @@ def _rename_automaton(ast, from_name, to_name):
rename_everything(inp.transition, from_name, to_name)
for idx, param in enumerate(inp.parameters):
if param.lower() == from_name.lower():
inp.parameter[idx] = to_name
inp.parameters[idx] = to_name
if each.composite:
rename_everything(each.composite.content, from_name, to_name)
for each in ast.inner_procedures:
......@@ -310,6 +337,11 @@ def _rename_path(ast, from_name, to_name):
if ast.value[0].lower() == from_name.lower():
ast.value[0] = to_name
@rename_everything.register(ogAST.PrimIfThenElse)
def _rename_ifhthenelse(ast, from_name, to_name):
''' Rename expressions in If-Then-Else-Fi construct '''
for expr in ('if', 'then', 'else'):
rename_everything(ast.value[expr], from_name, to_name)
def find_labels(trans):
'''
......
......@@ -398,6 +398,9 @@ class Terminator(object):
self.entrypoint = None
# some transitions can be chained, when entering/leaving nested states
self.next_id = -1
# List of State that can contain the current state
# There can be several if terminator follows a floating label
self.possible_states = []
def __repr__(self):
''' Debug output for terminators '''
......@@ -467,7 +470,6 @@ class Transition(object):
# All Terminators of this transition
self.terminators = []
def __repr__(self):
''' Debug output: display all actions '''
data = [repr(action) for action in self.actions]
......
......@@ -31,7 +31,7 @@ import os
import importlib
import logging
import traceback
from itertools import chain
from itertools import chain, permutations
import antlr3
import antlr3.tree
......@@ -437,7 +437,7 @@ def check_type_compatibility(primary, typeRef, context):
if corr_type:
return
else:
err = ('Value "' + primary.value[0] +
err = ('Value "' + primary.inputString +
'" not in this enumeration: ' +
str(actual_type.EnumValues.keys()))
raise TypeError(err)
......@@ -781,7 +781,7 @@ def fix_expression_types(expr, context):
# If a side of the expression is of Enumerated of Choice type, check if
# the other side is a literal of that sort, and change type accordingly
for side in (('left', 'right'), ('right', 'left')):
for side in permutations(('left', 'right')):
side_type = find_basic_type(getattr(expr, side[0]).exprType).kind
if side_type == 'EnumeratedType':
prim = ogAST.PrimEnumeratedValue(primary=getattr(expr, side[1]))
......@@ -796,7 +796,7 @@ def fix_expression_types(expr, context):
pass
# If a side type remains unknown, check if it is an ASN.1 constant
for side in (('left', 'right'), ('right', 'left')):
for side in permutations(('left', 'right')):
value = getattr(expr, side[0])
if value.exprType == UNKNOWN_TYPE and is_constant(value):
setattr(expr, side[0], ogAST.PrimConstant(primary=value))
......@@ -873,8 +873,8 @@ def fix_expression_types(expr, context):
expr.right.value['value'] = check_expr.right
elif isinstance(expr.right, ogAST.PrimIfThenElse):
for det in ('then', 'else'):
if expr.right.value[det].exprType == UNKNOWN_TYPE:
expr.right.value[det].exprType = expr.left.exprType
#if expr.right.value[det].exprType == UNKNOWN_TYPE:
# expr.right.value[det].exprType = expr.left.exprType
# Recursively fix possibly missing types in the expression
check_expr = ogAST.ExprAssign()
check_expr.left = ogAST.PrimPath()
......@@ -1356,8 +1356,10 @@ def composite_state(root, parent=None, context=None):
except AttributeError:
LOG.debug('Procedure context is undefined')
# Gather the list of states defined in the composite state
# and map a list of transitions to each state
# and map a list of transitionsi to each state
comp.mapping = {name: [] for name in get_state_list(root)}
inner_composite = []
states = []
for child in root.getChildren():
if child.type == lexer.ID:
comp.line = child.getLine()
......@@ -1388,18 +1390,9 @@ def composite_state(root, parent=None, context=None):
comp.exit_procedure = new_proc
comp.content.inner_procedures.append(new_proc)
elif child.type == lexer.COMPOSITE_STATE:
inner_comp, err, warn = composite_state(child,
parent=None,
context=comp)
errors.extend(err)
warnings.extend(warn)
comp.composite_states.append(inner_comp)
inner_composite.append(child)
elif child.type == lexer.STATE:
# STATE - fills up the 'mapping' structure.
newstate, err, warn = state(child, parent=None, context=comp)
errors.extend(err)
warnings.extend(warn)
comp.content.states.append(newstate)
states.append(child)
elif child.type == lexer.FLOATING_LABEL:
lab, err, warn = floating_label(child, parent=None, context=comp)
errors.extend(err)
......@@ -1421,6 +1414,22 @@ def composite_state(root, parent=None, context=None):
'Unsupported construct in nested state, type: ' +
str(child.type) + ' - line ' + str(child.getLine()) +
' - state name: ' + str(comp.statename))
for each in inner_composite:
# Parse inner composite states after the text areas to make sure
# that all variables are propagated to the the inner scope
inner, err, warn = composite_state(each, parent=None,
context=comp)
errors.extend(err)
warnings.extend(warn)
comp.composite_states.append(inner)
for each in states:
# And parse the states after inner states to make sure all CONNECTS
# are properly defined.
# Fill up the 'mapping' structure.
newstate, err, warn = state(each, parent=None, context=comp)
errors.extend(err)
warnings.extend(warn)
comp.content.states.append(newstate)
return comp, errors, warnings
......@@ -2347,9 +2356,8 @@ def decision(root, parent, context):
warnings.extend(warn)
dec.answers.append(ans)
elif child.type == lexer.ELSE:
dec.kind = child.toString()
a = ogAST.Answer()
a.inputString = 'ELSE'
a.inputString = child.toString()
for c in child.getChildren():
if c.type == lexer.CIF:
a.pos_x, a.pos_y, a.width, a.height = cif(c)
......
EXAMPLES=test1 test2 test3 test4 test5 test6 test7 test8 test9 test10 test11
EXAMPLES=test1 test2 test3 test4 test5 test6 test7 test8 test9 test10 test11 test12
all:
for v in $(EXAMPLES) ; do make -C $$v clean all || exit 1 ; done
......
......@@ -8,8 +8,9 @@ compile: generate-code
asn1.exe -Ada dataview-uniq.asn -typePrefix asn1Scc -equal
gnatmake -c *.adb
gcc -c test.c
gcc -o test test.o og.o taste_dataview.o -lgnat
./test > result
gnatbind -n og.ali
gnatlink -o testcase test.o og.ali -lgnat
./testcase > result
diff result expected && echo 'All OK!'
......
......@@ -6,3 +6,5 @@
5
6
end of test
All done
bonjour entry
/* CIF PROCESS (252, 216), (150, 75) */
PROCESS og;
/* CIF TEXT (0, 0), (229, 98) */
STATE all_done;
SUBSTRUCTURE
STATE Bonjour;
SUBSTRUCTURE
/* CIF PROCEDURE (72, 110), (73, 35) */
PROCEDURE entry;
/* CIF START (258, 113), (70, 35) */
START;
/* CIF PROCEDURECALL (202, 163), (181, 35) */
CALL writeln('bonjour entry');
/* CIF RETURN (275, 213), (35, 35) */
RETURN ;
ENDPROCEDURE;
/* CIF START (190, 52), (70, 35) */
START;
/* CIF NEXTSTATE (189, 102), (72, 35) */
NEXTSTATE dumb;
/* CIF STATE (312, 42), (72, 35) */
STATE dumb;
ENDSTATE;
ENDSUBSTRUCTURE;
/* CIF TEXT (118, 110), (298, 140) */
-- Declare your variables
-- Syntax: DCL <variable name> <type name>;
dcl tmp my_OctStr;
/* CIF ENDTEXT */
/* CIF PROCEDURE (298, 308), (73, 35) */
PROCEDURE entry;
/* CIF START (171, 108), (70, 35) */
START;
/* CIF PROCEDURECALL (131, 158), (149, 35) */
CALL writeln('All done');
/* CIF RETURN (188, 208), (35, 35) */
RETURN ;
ENDPROCEDURE;
/* CIF START (473, 144), (70, 35) */
START;
/* CIF NEXTSTATE (466, 194), (84, 35) */
NEXTSTATE Bonjour;
/* CIF STATE (564, 193), (125, 35) */
STATE Dumb, Bonjour;
/* CIF INPUT (583, 248), (87, 35) */
INPUT go(tmp);
/* CIF NEXTSTATE (592, 298), (70, 35) */
NEXTSTATE -;
ENDSTATE;
/* CIF STATE (459, 366), (84, 35) */
STATE Bonjour;
ENDSTATE;
ENDSUBSTRUCTURE;
/* CIF TEXT (0, 0), (229, 98) */
-- Testing decisions
dcl test myInteger := 3;
/* CIF ENDTEXT */
/* CIF START (482, 35), (70, 35) */
/* CIF START (342, 35), (70, 35) */
START;
/* CIF LABEL (474, 85), (85, 35) */
/* CIF LABEL (334, 85), (85, 35) */
again:
/* CIF DECISION (482, 135), (70, 50) */
/* CIF DECISION (342, 135), (70, 50) */
DECISION test;
/* CIF ANSWER (85, 205), (70, 23) */
/* CIF ANSWER (-6, 205), (70, 23) */
(3):
/* CIF PROCEDURECALL (67, 243), (106, 35) */
/* CIF PROCEDURECALL (-24, 243), (106, 35) */
CALL writeln('1');
/* CIF TASK (77, 293), (87, 35) */
/* CIF TASK (-14, 293), (87, 35) */
TASK test := 5;
/* CIF JOIN (103, 343), (35, 35) */
/* CIF JOIN (11, 343), (35, 35) */
JOIN again;
/* CIF ANSWER (582, 205), (70, 23) */
/* CIF ANSWER (486, 205), (70, 23) */
(>5):
/* CIF PROCEDURECALL (561, 243), (113, 35) */
/* CIF PROCEDURECALL (465, 243), (113, 35) */
CALL writeln('4');
/* CIF TASK (574, 293), (87, 35) */
/* CIF TASK (478, 293), (87, 35) */
TASK test := 7;
/* CIF LABEL (568, 343), (98, 35) */
/* CIF LABEL (472, 343), (98, 35) */
and_again:
/* CIF DECISION (582, 393), (70, 50) */
/* CIF DECISION (486, 393), (70, 50) */
DECISION test;
/* CIF ANSWER (681, 463), (70, 23) */
/* CIF ANSWER (585, 463), (70, 23) */
(<=5):
/* CIF DECISION (681, 501), (70, 50) */
/* CIF DECISION (585, 501), (70, 50) */
DECISION test;
/* CIF ANSWER (576, 571), (70, 23) */
/* CIF ANSWER (480, 571), (70, 23) */
(>=5):
/* CIF PROCEDURECALL (545, 609), (132, 35) */
/* CIF PROCEDURECALL (449, 609), (132, 35) */
CALL writeln('6');
/* CIF ANSWER (746, 571), (70, 23) */
/* CIF ANSWER (650, 571), (70, 23) */
else:
/* CIF PROCEDURECALL (707, 609), (148, 35) */
/* CIF PROCEDURECALL (611, 609), (148, 35) */
CALL writeln('[ERROR]');
ENDDECISION;
/* CIF ANSWER (444, 463), (70, 23) */
/* CIF ANSWER (348, 463), (70, 23) */
(/=5):
/* CIF PROCEDURECALL (422, 501), (113, 35) */
/* CIF PROCEDURECALL (327, 501), (113, 35) */
CALL writeln('5');
/* CIF TASK (435, 551), (87, 35) */
/* CIF TASK (340, 551), (87, 35) */
TASK test := 5;
/* CIF JOIN (461, 601), (35, 35) */
/* CIF JOIN (366, 601), (35, 35) */
JOIN and_again;
ENDDECISION;
/* CIF ANSWER (321, 205), (70, 23) */
/* CIF ANSWER (225, 205), (70, 23) */
(<5):
/* CIF PROCEDURECALL (299, 243), (113, 35) */
/* CIF PROCEDURECALL (204, 243), (113, 35) */
CALL writeln('3');
/* CIF TASK (309, 293), (94, 35) */
/* CIF TASK (213, 293), (94, 35) */
TASK test := 6;
/* CIF JOIN (338, 343), (35, 35) */
/* CIF JOIN (243, 343), (35, 35) */
JOIN again;
/* CIF ANSWER (201, 205), (70, 23) */
/* CIF ANSWER (106, 205), (70, 23) */
(=5):
/* CIF PROCEDURECALL (183, 243), (106, 35) */
/* CIF PROCEDURECALL (88, 243), (106, 35) */
CALL writeln('2');
/* CIF TASK (189, 293), (94, 35) */
/* CIF TASK (94, 293), (94, 35) */
TASK test := 4;
/* CIF JOIN (219, 343), (35, 35) */
/* CIF JOIN (123, 343), (35, 35) */
JOIN again;
/* CIF ANSWER (904, 205), (70, 23) */
/* CIF ANSWER (808, 205), (70, 23) */
else:
/* CIF PROCEDURECALL (865, 243), (148, 35) */
/* CIF PROCEDURECALL (769, 243), (148, 35) */
CALL writeln('[ERROR]');
ENDDECISION;
/* CIF PROCEDURECALL (433, 689), (167, 35) */
/* CIF PROCEDURECALL (293, 689), (167, 35) */
CALL writeln('end of test');
/* CIF NEXTSTATE (472, 739), (90, 35) */
/* CIF NEXTSTATE (332, 739), (90, 35) */
NEXTSTATE all_done;
/* CIF STATE (1078, 167), (90, 35) */
/* CIF STATE (927, 81), (124, 35) */
STATE toto, all_done;
/* CIF INPUT (954, 136), (70, 35) */
INPUT bye;
/* CIF PROCEDURECALL (928, 186), (122, 35) */
CALL writeln('Bye');
/* CIF NEXTSTATE (954, 236), (70, 35) */
NEXTSTATE -;
ENDSTATE;
/* CIF STATE (1061, 79), (90, 35) */
STATE all_done;
ENDSTATE;
......
......@@ -4,19 +4,20 @@ SYSTEM og;
/* CIF Keep Specific Geode PARAMNAMES ze_param */
SIGNAL go (My_OctStr);
SIGNAL bye;
/* CIF Keep Specific Geode PARAMNAMES ze_rezult */
SIGNAL rezult (My_OctStr);
CHANNEL c
FROM ENV TO og WITH go;
FROM ENV TO og WITH go, bye;
FROM og TO ENV WITH rezult;
ENDCHANNEL;
BLOCK og;
SIGNALROUTE r
FROM ENV TO og WITH go;
FROM ENV TO og WITH go, bye;
FROM og TO ENV WITH rezult;
CONNECT c and r;
......@@ -25,4 +26,4 @@ SYSTEM og;
ENDBLOCK;
ENDSYSTEM;
\ No newline at end of file
ENDSYSTEM;
#include <math.h>
#include <stdio.h>
/* Ada code external interface */
extern void og_start();
extern void adainit();
int main()
{
printf("[C Code] Running test\n");
og_start();
adainit();
return 0;
}
......
Datamodel DEFINITIONS ::= BEGIN
-- ./dataview-uniq.asn
T_Int32 ::= INTEGER (-2147483648 .. 2147483647)
-- ./dataview-uniq.asn
T_UInt32 ::= INTEGER (0 .. 4294967295)
-- ./dataview-uniq.asn
T_Int8 ::= INTEGER (-128 .. 127)
-- ./dataview-uniq.asn
T_UInt8 ::= INTEGER (0 .. 255)
-- ./dataview-uniq.asn
T_Boolean ::= BOOLEAN
-- ./dataview-uniq.asn
Light ::= ENUMERATED {
red(0),
yellow(1),
green(2),
all_off(3)
}
END
#!/usr/bin/env python
# ASN.1 Data model
asn1Files = []