Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
TASTE
OpenGEODE
Commits
1522826f
Commit
1522826f
authored
Mar 29, 2014
by
Maxime Perrotin
Browse files
Partial support of nested states, with Sdl2010 syntax
parent
5141e1cf
Changes
15
Hide whitespace changes
Inline
Side-by-side
AdaGenerator.py
View file @
1522826f
...
...
@@ -124,6 +124,54 @@ def _process(process):
t
=
var_type
.
ReferencedTypeName
.
replace
(
'-'
,
'_'
),
default
=
' := '
+
dstr
if
def_value
else
''
))
# Flatten the nested states, add states to the process state list
# Requires renaming of nested states and setting chaining of transitions
def
update_terminator
(
context
,
term
,
process
):
'''Set next_id, identifying the next transition to run '''
if
term
.
inputString
.
lower
()
in
(
st
.
statename
.
lower
()
for
st
in
context
.
composite_states
):
if
not
term
.
via
:
term
.
next_id
=
context
.
mapping
\
[
term
.
inputString
.
lower
()
+
'_START'
]
else
:
term
.
next_id
=
context
.
mapping
[
term
.
inputString
.
lower
()
+
'_'
+
term
.
via
.
lower
()
+
'_START'
]
def
update_composite_state
(
state
,
process
):
''' Rename inner states, recursively, and add inner transitions
to process, updating indexes, and update terminators
'''
trans_idx
=
len
(
process
.
transitions
)
state
.
mapping
=
{
state
.
statename
+
'_'
+
key
:
state
.
mapping
.
pop
(
key
)
for
key
in
state
.
mapping
.
keys
()}
process
.
transitions
.
extend
(
state
.
transitions
)
for
key
,
value
in
state
.
mapping
.
viewitems
():
# Update transition indices
if
isinstance
(
value
,
int
):
state
.
mapping
[
key
]
=
value
+
trans_idx
else
:
for
inp
in
value
:
inp
.
transition_id
+=
trans_idx
process
.
mapping
.
update
(
state
.
mapping
)
for
inner
in
state
.
composite_states
:
inner
.
statename
=
state
.
statename
+
'_'
+
inner
.
statename
update_composite_state
(
inner
,
process
)
for
each
in
state
.
terminators
:
# Update state names in terminators and set next transition id
if
each
.
kind
==
'next_state'
:
each
.
inputString
=
state
.
statename
+
'_'
+
each
.
inputString
update_terminator
(
state
,
each
,
process
)
for
each
in
process
.
composite_states
:
update_composite_state
(
each
,
process
)
# Update terminators at process level
for
each
in
process
.
terminators
:
if
each
.
kind
==
'next_state'
:
update_terminator
(
process
,
each
,
process
)
# Add the process states list to the process-level variables
states_decl
=
'type states is ('
states_decl
+=
', '
.
join
(
process
.
mapping
.
iterkeys
())
+
');'
...
...
@@ -136,12 +184,13 @@ def _process(process):
.
format
(
process_name
))
# Add the declaration of the runTransition procedure
process_level_decl
.
append
(
'procedure runTransition(
tr
Id: Integer);'
)
process_level_decl
.
append
(
'procedure runTransition(Id: Integer);'
)
# Generate the code of the start transition:
start_transition
=
[
'begin'
]
start_transition
.
append
(
'runTransition(0);'
)
mapping
=
{}
# Generate the code for the transitions in a mapping input-state
input_signals
=
[
sig
[
'name'
]
for
sig
in
process
.
input_signals
]
...
...
@@ -150,7 +199,8 @@ def _process(process):
for
input_signal
in
input_signals
:
mapping
[
input_signal
]
=
{}
for
state_name
,
input_symbols
in
process
.
mapping
.
viewitems
():
if
state_name
!=
'START'
:
if
isinstance
(
input_symbols
,
list
):
# Start symbols have no list of inputs
for
i
in
input_symbols
:
if
input_signal
.
lower
()
in
(
inp
.
lower
()
for
inp
in
i
.
inputlist
):
...
...
@@ -224,7 +274,7 @@ package {process_name} is'''.format(process_name=process_name,
taste_template
.
append
(
'begin'
)
taste_template
.
append
(
'case state is'
)
for
state
in
process
.
mapping
.
viewkeys
():
if
state
==
'START'
:
if
state
.
endswith
(
'START'
)
:
continue
taste_template
.
append
(
'when {state} =>'
.
format
(
state
=
state
))
input_def
=
mapping
[
signal
[
'name'
]].
get
(
state
)
...
...
@@ -293,7 +343,9 @@ package {process_name} is'''.format(process_name=process_name,
'pragma import(C, RESET_{timer}, "{proc}_RI_reset_{timer}");'
.
format
(
timer
=
timer
,
proc
=
process_name
))
taste_template
.
append
(
'procedure runTransition(trId: Integer) is'
)
taste_template
.
append
(
'procedure runTransition(Id: Integer) is'
)
taste_template
.
append
(
'trId : Integer := Id;'
)
# Generate the code for all transitions
code_transitions
=
[]
...
...
@@ -327,6 +379,10 @@ package {process_name} is'''.format(process_name=process_name,
taste_template
.
extend
(
decl
)
taste_template
.
append
(
'begin'
)
# Generate a loop that ends when a next state is reached
# (there can be chained transition when entering a nested state)
taste_template
.
append
(
'while (trId /= -1) loop'
)
# Generate the switch-case on the transition id
taste_template
.
append
(
'case trId is'
)
...
...
@@ -342,10 +398,18 @@ package {process_name} is'''.format(process_name=process_name,
taste_template
.
append
(
'null;'
)
taste_template
.
append
(
'end case;'
)
if
code_labels
:
# Due to nested states (chained transitions) jump over label code
# (NEXTSTATEs do not return from runTransition)
taste_template
.
append
(
'goto next_transition;'
)
# Add the code for the floating labels
taste_template
.
extend
(
code_labels
)
if
code_labels
:
taste_template
.
append
(
'<<next_transition>>'
)
taste_template
.
append
(
'null;'
)
taste_template
.
append
(
'end loop;'
)
taste_template
.
append
(
'end runTransition;'
)
taste_template
.
append
(
'
\n
'
)
...
...
@@ -1233,12 +1297,12 @@ 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
(
'state := {nextState};'
.
format
(
if
tr
.
terminator
.
next_id
==
-
1
:
code
.
append
(
'state := {nextState};'
.
format
(
nextState
=
tr
.
terminator
.
inputString
))
# In any case, return to avoid code of floating labels
code
.
append
(
'return;'
)
elif
tr
.
terminator
.
kind
==
'join'
:
code
.
append
(
'goto {label};'
.
format
(
label
=
tr
.
terminator
.
inputString
))
...
...
@@ -1247,11 +1311,15 @@ def _transition(tr):
# TODO
elif
tr
.
terminator
.
kind
==
'return'
:
string
=
''
if
tr
.
terminator
.
return_expr
:
stmts
,
string
,
local
=
generate
(
tr
.
terminator
.
return_expr
)
code
.
extend
(
stmts
)
local_decl
.
extend
(
local
)
code
.
append
(
'return{};'
.
format
(
' '
+
string
if
string
else
''
))
if
tr
.
terminator
.
next_id
==
-
1
:
if
tr
.
terminator
.
return_expr
:
stmts
,
string
,
local
=
generate
\
(
tr
.
terminator
.
return_expr
)
code
.
extend
(
stmts
)
local_decl
.
extend
(
local
)
code
.
append
(
'return{};'
.
format
(
' '
+
string
if
string
else
''
))
else
:
code
.
append
(
'trId := '
+
str
(
tr
.
terminator
.
next_id
)
+
';'
)
if
empty_transition
:
# If transition does not have any statement, generate an Ada 'null;'
code
.
append
(
'null;'
)
...
...
@@ -1329,6 +1397,15 @@ def _inner_procedure(proc):
name
=
var_name
,
sort
=
typename
,
default
=
' := '
+
dstr
if
def_value
else
''
))
# Look for labels in the diagram and transform them in floating labels
for
idx
in
xrange
(
len
(
proc
.
content
.
floating_labels
)):
for
new_floating
in
find_labels
(
proc
.
content
.
floating_labels
[
idx
].
transition
):
proc
.
content
.
floating_labels
.
append
(
new_floating
)
for
new_floating
in
find_labels
(
proc
.
content
.
start
.
transition
):
proc
.
content
.
floating_labels
.
append
(
new_floating
)
tr_code
,
tr_decl
=
generate
(
proc
.
content
.
start
.
transition
)
# Generate code for the floating labels
code_labels
=
[]
...
...
Renderer.py
View file @
1522826f
...
...
@@ -91,6 +91,10 @@ def _automaton(ast, scene):
if
ast
.
start
:
top_level_symbols
.
append
(
render
(
ast
.
start
,
scene
,
ast
.
states
))
# Render named start symbols in nested states
for
each
in
ast
.
named_start
:
top_level_symbols
.
append
(
render
(
each
,
scene
,
ast
.
states
))
# Render floating labels
for
label
in
ast
.
floating_labels
:
top_level_symbols
.
append
(
render
(
label
,
scene
,
ast
.
states
))
...
...
@@ -128,6 +132,9 @@ def _state(ast, scene, states, terminators, parent=None):
for
inp
in
ast
.
inputs
:
render
(
inp
,
scene
=
scene
,
parent
=
new_state
,
states
=
states
)
new_state
.
nested_scene
=
ast
.
composite
or
ogAST
.
CompositeState
()
return
new_state
...
...
@@ -161,6 +168,18 @@ def _start(ast, scene, states, parent=None):
return
start_symbol
@
render
.
register
(
ogAST
.
CompositeState_start
)
def
_start
(
ast
,
scene
,
states
,
parent
=
None
):
''' Add an editable start symbol to a scene (in composite states) '''
_
=
parent
start_symbol
=
sdlSymbols
.
StateStart
(
ast
)
scene
.
addItem
(
start_symbol
)
if
ast
.
transition
:
render
(
ast
.
transition
,
scene
=
scene
,
parent
=
start_symbol
,
states
=
states
)
return
start_symbol
@
render
.
register
(
ogAST
.
Procedure_start
)
def
_procedure_start
(
ast
,
scene
,
states
,
parent
=
None
):
''' Add the procedure start symbol to a scene '''
...
...
genericSymbols.py
View file @
1522826f
...
...
@@ -561,6 +561,8 @@ class Symbol(QObject, QGraphicsPathItem, object):
redbold
=
()
# Specify if the symbol can be drawn with anti-aliasing
_antialiasing
=
True
# Specify if the symbol text can be edited
editable
=
True
def
__init__
(
self
,
parent
=
None
):
'''
...
...
@@ -1342,7 +1344,7 @@ class HorizontalSymbol(Symbol, object):
super
(
HorizontalSymbol
,
self
).
__init__
(
parent
)
self
.
minDistanceToSymbolAbove
=
20
self
.
connection
=
None
if
text
:
if
self
.
editable
:
self
.
text
=
EditableText
(
parent
=
self
,
text
=
text
,
hyperlink
=
hyperlink
)
if
parent
:
...
...
@@ -1506,7 +1508,10 @@ class VerticalSymbol(Symbol, object):
x
=
None
,
y
=
None
,
hyperlink
=
None
):
super
(
VerticalSymbol
,
self
).
__init__
(
parent
)
self
.
connection
=
None
self
.
text
=
EditableText
(
parent
=
self
,
text
=
text
,
hyperlink
=
hyperlink
)
if
self
.
editable
:
self
.
text
=
EditableText
(
parent
=
self
,
text
=
text
,
hyperlink
=
hyperlink
)
self
.
minDistanceToSymbolAbove
=
15
if
parent
:
local_pos
=
self
.
mapFromScene
(
0
,
y
or
0
)
...
...
icons.py
View file @
1522826f
...
...
@@ -2,8 +2,8 @@
# Resource object code
#
# Created: Fri
Feb 28 10:41:17
2014
# by: The Resource Compiler for PySide (Qt v4.8.
4
)
# Created: Fri
Mar 7 19:56:41
2014
# by: The Resource Compiler for PySide (Qt v4.8.
6
)
#
# WARNING! All changes made in this file will be lost!
icons/statestart.png
0 → 100644
View file @
1522826f
972 Bytes
ogAST.py
View file @
1522826f
...
...
@@ -268,7 +268,7 @@ class Answer(object):
''' AST Entry for a decision answer '''
def
__init__
(
self
):
''' One ANSWER of a DECISION '''
self
.
inputString
=
'
case
'
self
.
inputString
=
''
self
.
line
=
None
self
.
charPositionInLine
=
None
self
.
pos_x
=
0
...
...
@@ -303,7 +303,7 @@ class Task(object):
''' AST Entry for TASKS '''
def
__init__
(
self
):
''' Initialize TASK attributes (set of ASSIGN statements) '''
self
.
inputString
=
'
x := 1
'
self
.
inputString
=
''
self
.
line
=
None
self
.
charPositionInLine
=
None
self
.
pos_x
=
0
...
...
@@ -342,7 +342,7 @@ class TaskForLoop(Task):
class
Output
(
object
):
''' AST Entry for OUTPUT statements '''
def
__init__
(
self
,
defName
=
'
RI
'
):
def
__init__
(
self
,
defName
=
''
):
''' Set of OUTPUT statements '''
self
.
inputString
=
defName
self
.
pos_x
=
0
...
...
@@ -392,6 +392,8 @@ class Terminator(object):
self
.
return_expr
=
None
# via clause, used for entering nested state with an entry point
self
.
via
=
None
# some transitions can be chained, when entering/leaving nested states
self
.
next_id
=
-
1
def
__repr__
(
self
):
''' Debug output for terminators '''
...
...
@@ -406,7 +408,7 @@ class Label(object):
def
__init__
(
self
):
''' Initialize the label attributes '''
# inputString holds the label name
self
.
inputString
=
'
Here
'
self
.
inputString
=
''
self
.
pos_x
=
0
self
.
pos_y
=
0
self
.
width
=
70
...
...
@@ -475,7 +477,7 @@ class Input(object):
def
__init__
(
self
):
''' Initialize the Input attributes '''
# inputString is the user text, it can contain several inputs
self
.
inputString
=
'
PI
'
self
.
inputString
=
''
self
.
pos_x
=
0
self
.
pos_y
=
0
self
.
width
=
70
...
...
@@ -526,7 +528,7 @@ class Start(object):
def
__repr__
(
self
):
''' Debug output for a START symbol '''
return
'START
'
return
'START
{}'
.
format
(
self
.
inputString
)
class
Procedure_start
(
Start
):
...
...
@@ -534,6 +536,11 @@ class Procedure_start(Start):
pass
class
CompositeState_start
(
Start
):
''' Composite state start symbol - inherits from Start, can have a name '''
pass
class
Comment
(
object
):
''' AST Entry for COMMENT symbols '''
def
__init__
(
self
):
...
...
@@ -575,6 +582,8 @@ class State(object):
self
.
comment
=
None
# optional hyperlink
self
.
hyperlink
=
None
# optional composite state content (type CompositeState)
self
.
composite
=
None
def
__repr__
(
self
):
''' Debug output for a STATE symbol '''
...
...
@@ -588,7 +597,7 @@ class TextArea(object):
def
__init__
(
self
):
''' Text area (raw content for rendering only) '''
self
.
inputString
=
'-- Declare your variables
\n\n
'
\
'-- Syntax: DCL <variable name> <type name>;'
'-- Syntax: DCL <variable name> <type name>;
\n\n
'
# DCL variables in the text area {name: (sort, default_value), ...}
self
.
variables
=
{}
self
.
line
=
None
...
...
@@ -617,13 +626,14 @@ class Automaton(object):
self
.
start
=
None
self
.
floating_labels
=
[]
self
.
states
=
[]
self
.
named_start
=
[]
class
Procedure
(
object
):
''' Internal procedure definition '''
def
__init__
(
self
):
''' Procedure AST default value '''
self
.
inputString
=
'
Proc
'
self
.
inputString
=
''
self
.
line
=
None
self
.
charPositionInLine
=
None
# Set default coordinates and width/height
...
...
@@ -712,6 +722,9 @@ class Process(object):
# list of type Transition - use 'mapping' to map index to inputs/states
self
.
transitions
=
[]
# list of type CompositeState
self
.
composite_states
=
[]
# Set of symbols contained in the process (type Automaton)
# (Includes inner procedures)
self
.
content
=
Automaton
(
parent
=
self
)
...
...
@@ -720,6 +733,27 @@ class Process(object):
self
.
timers
=
[]
class
CompositeState
(
Process
):
'''
Composite states: the difference with Process is that they can have:
- several START elements, that correspond to state entry points,
- state exit points (with RETURN terminators)
- entry and exit procedures
'''
def
__init__
(
self
):
super
(
CompositeState
,
self
).
__init__
()
self
.
statename
=
''
self
.
state_entrypoints
=
[]
self
.
state_exitpoints
=
[]
# Special entry and exit procedures (named "entry" and "exit")
self
.
entry_procedure
=
None
self
.
exit_procedure
=
None
# Body can contain text areas, procedures, composite states,
# one nameless START, named START (one per entrypoint), states,
# and floating labels.
# XXX check what to do with local DCL and timers
class
Block
(
object
):
''' AST for a BLOCK entity '''
def
__init__
(
self
):
...
...
ogParser.py
View file @
1522826f
...
...
@@ -732,6 +732,159 @@ def find_type(path, context):
return
result
def
fix_expression_types
(
expr
,
context
):
''' Check/ensure type consistency in expressions having two sides '''
if
isinstance
(
expr
,
ogAST
.
Primary
):
return
for
side
in
(
'left'
,
'right'
):
# Determine if the expression is a variable
uk_expr
=
getattr
(
expr
,
side
)
if
uk_expr
.
exprType
==
UNKNOWN_TYPE
\
and
isinstance
(
uk_expr
,
ogAST
.
PrimPath
)
\
and
len
(
uk_expr
.
value
)
==
1
:
try
:
#exprType = find_variable(uk_expr.inputString, context)
exprType
=
find_variable
(
uk_expr
.
value
[
0
],
context
)
setattr
(
expr
,
side
,
ogAST
.
PrimVariable
(
primary
=
uk_expr
))
getattr
(
expr
,
side
).
exprType
=
exprType
except
AttributeError
:
pass
# 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'
)):
side_type
=
find_basic_type
(
getattr
(
expr
,
side
[
0
]).
exprType
).
kind
if
side_type
==
'EnumeratedType'
:
prim
=
ogAST
.
PrimEnumeratedValue
(
primary
=
getattr
(
expr
,
side
[
1
]))
elif
side_type
==
'ChoiceEnumeratedType'
:
prim
=
ogAST
.
PrimChoiceDeterminant
(
primary
=
getattr
(
expr
,
side
[
1
]))
try
:
check_type_compatibility
(
prim
,
getattr
(
expr
,
side
[
0
]).
exprType
,
context
)
setattr
(
expr
,
side
[
1
],
prim
)
getattr
(
expr
,
side
[
1
]).
exprType
=
getattr
(
expr
,
side
[
0
]).
exprType
except
(
UnboundLocalError
,
AttributeError
,
TypeError
):
pass
# If a side type remains unknown, check if it is an ASN.1 constant
for
side
in
((
'left'
,
'right'
),
(
'right'
,
'left'
)):
value
=
getattr
(
expr
,
side
[
0
])
if
value
.
exprType
==
UNKNOWN_TYPE
and
is_constant
(
value
):
setattr
(
expr
,
side
[
0
],
ogAST
.
PrimConstant
(
primary
=
value
))
getattr
(
expr
,
side
[
0
]).
exprType
=
getattr
(
expr
,
side
[
1
]).
exprType
for
side
in
(
expr
.
right
,
expr
.
left
):
if
side
.
is_raw
:
raw_expr
=
side
else
:
typed_expr
=
side
ref_type
=
typed_expr
.
exprType
# Type check that is specific to IN expressions
if
isinstance
(
expr
,
ogAST
.
ExprIn
):
# check that left part is a SEQUENCE OF or a string
container_basic_type
=
find_basic_type
(
expr
.
left
.
exprType
)
if
container_basic_type
.
kind
==
'SequenceOfType'
:
ref_type
=
container_basic_type
.
type
elif
container_basic_type
.
kind
.
endswith
(
'StringType'
):
ref_type
=
container_basic_type
else
:
raise
TypeError
(
'IN expression: right part must be a list'
)
compare_types
(
expr
.
right
.
exprType
,
ref_type
)
return
if
expr
.
right
.
is_raw
==
expr
.
left
.
is_raw
==
False
:
unknown
=
[
uk_expr
for
uk_expr
in
expr
.
right
,
expr
.
left
if
uk_expr
.
exprType
==
UNKNOWN_TYPE
]
if
unknown
:
raise
TypeError
(
'Cannot resolve type of "{}"'
.
format
(
unknown
[
0
].
inputString
))
# In Sequence, Choice, SEQUENCE OF, and IfThenElse expressions,
# we must fix missing inner types
# (due to similarities, the following should be refactored FIXME)
if
isinstance
(
expr
.
right
,
ogAST
.
PrimSequence
):
# left side must have a known type
asn_type
=
find_basic_type
(
expr
.
left
.
exprType
)
if
asn_type
.
kind
!=
'SequenceType'
:
raise
TypeError
(
'left side must be a SEQUENCE type'
)
for
field
,
fd_expr
in
expr
.
right
.
value
.
viewitems
():
if
fd_expr
.
exprType
==
UNKNOWN_TYPE
:
try
:
expected_type
=
asn_type
.
Children
.
get
(
field
.
replace
(
'_'
,
'-'
)).
type
except
AttributeError
:
raise
TypeError
(
'Field not found: '
+
field
)
check_expr
=
ogAST
.
ExprAssign
()
check_expr
.
left
=
ogAST
.
PrimPath
()
check_expr
.
left
.
exprType
=
expected_type
check_expr
.
right
=
fd_expr
fix_expression_types
(
check_expr
,
context
)
# Id of fd_expr may have changed (enumerated, choice)
expr
.
right
.
value
[
field
]
=
check_expr
.
right
elif
isinstance
(
expr
.
right
,
ogAST
.
PrimChoiceItem
):
asn_type
=
find_basic_type
(
expr
.
left
.
exprType
)
field
=
expr
.
right
.
value
[
'choice'
].
replace
(
'_'
,
'-'
)
if
asn_type
.
kind
!=
'ChoiceType'
\
or
field
.
lower
()
not
in
[
key
.
lower
()
for
key
in
asn_type
.
Children
.
viewkeys
()]:
raise
TypeError
(
'Field is not valid in CHOICE:'
+
field
)
key
,
=
[
key
for
key
in
asn_type
.
Children
.
viewkeys
()
if
key
.
lower
()
==
field
.
lower
()]
if
expr
.
right
.
value
[
'value'
].
exprType
==
UNKNOWN_TYPE
:
try
:
expected_type
=
asn_type
.
Children
.
get
(
key
).
type
except
AttributeError
:
raise
TypeError
(
'Field not found in CHOICE: '
+
field
)
check_expr
=
ogAST
.
ExprAssign
()
check_expr
.
left
=
ogAST
.
PrimPath
()
check_expr
.
left
.
exprType
=
expected_type
check_expr
.
right
=
expr
.
right
.
value
[
'value'
]
fix_expression_types
(
check_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
# Recursively fix possibly missing types in the expression
check_expr
=
ogAST
.
ExprAssign
()
check_expr
.
left
=
ogAST
.
PrimPath
()
check_expr
.
left
.
exprType
=
expr
.
left
.
exprType
check_expr
.
right
=
expr
.
right
.
value
[
det
]
fix_expression_types
(
check_expr
,
context
)
expr
.
right
.
value
[
det
]
=
check_expr
.
right
elif
isinstance
(
expr
.
right
,
ogAST
.
PrimSequenceOf
):
asn_type
=
find_basic_type
(
expr
.
left
.
exprType
).
type
for
idx
,
elem
in
enumerate
(
expr
.
right
.
value
):
check_expr
=
ogAST
.
ExprAssign
()
check_expr
.
left
=
ogAST
.
PrimPath
()
check_expr
.
left
.
exprType
=
asn_type
check_expr
.
right
=
elem
fix_expression_types
(
check_expr
,
context
)
expr
.
right
.
value
[
idx
]
=
check_expr
.
right
# the type of the raw PrimSequenceOf can be set now
expr
.
right
.
exprType
.
type
=
asn_type
if
isinstance
(
expr
,
(
ogAST
.
ExprAnd
,
ogAST
.
ExprOr
,
ogAST
.
ExprXor
)):
# Bitwise operators: check that both sides are booleans
for
side
in
expr
.
left
,
expr
.
right
:
basic_type
=
find_basic_type
(
side
.
exprType
)
if
basic_type
.
kind
in
(
'BooleanType'
,
'BitStringType'
):
continue
elif
basic_type
.
kind
==
'SequenceOfType'
:
if
find_basic_type
(
side
.
exprType
).
type
.
kind
==
'BooleanType'
:
continue
else
:
raise
TypeError
(
'Bitwise operators only work with '
'booleans and arrays of booleans'
)
if
expr
.
right
.
is_raw
!=
expr
.
left
.
is_raw
:
check_type_compatibility
(
raw_expr
,
ref_type
,
context
)
raw_expr
.
exprType
=
ref_type
else
:
compare_types
(
expr
.
left
.
exprType
,
expr
.
right
.
exprType
)
def
expression_list
(
root
,
context
):
''' Parse a list of expression parameters '''
errors
=
[]
...
...
@@ -1157,9 +1310,96 @@ def fpar(root):
str
(
child
.
type
))
return
params
,
errors
,
warnings
def
composite_state
(
root
,
parent
=
None
,
context
=
None
):
''' Parse a composite state definition '''
comp
=
ogAST
.
CompositeState
()
errors
,
warnings
=
[],
[]
# Create a list of all inherited data
try
:
comp
.
global_variables
=
dict
(
context
.
variables
)
comp
.
global_variables
.
update
(
context
.
global_variables
)
comp
.
input_signals
=
context
.
input_signals
comp
.
output_signals
=
context
.
output_signals
comp
.
procedures
=
context
.
procedures
comp
.
operators
=
dict
(
context
.
operators
)
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
comp
.
mapping
=
{
name
:
[]
for
name
in
get_state_list
(
root
)}
for
child
in
root
.
getChildren
():
if
child
.
type
==
lexer
.
ID
:
comp
.
line
=
child
.
getLine
()
comp
.
charPositionInLine
=
child
.
getCharPositionInLine
()
comp
.
statename
=
child
.
toString
().
lower
()
elif
child
.
type
==
lexer
.
COMMENT
:
comp
.
comment
,
_
,
_
=
end
(
child
)
elif
child
.
type
==
lexer
.
IN
:
# state entry point
for
point
in
child
.
getChildren
():
comp
.
state_entrypoints
.
append
(
point
.
toString
().
lower
())
elif
child
.
type
==
lexer
.
OUT
:
# state exit point
for
point
in
child
.
getChildren
():
comp
.
state_exitpoints
.
append
(
point
.
toString
().
lower
())
elif
child
.
type
==
lexer
.
TEXTAREA
:
textarea
,
err
,
warn
=
text_area
(
child
,
context
=
comp
)
errors
.
extend
(
err
)
warnings
.
extend
(
warn
)
comp
.
content
.
textAreas
.
append
(
textarea
)
elif
child
.
type
==
lexer
.
PROCEDURE
:
new_proc
,
err
,
warn
=
procedure
(
child
,
context
=
proc
)
errors
.
extend
(
err
)
warnings
.
extend
(
warn
)
if
new_proc
.
inputString
.
strip
().
lower
()
==
'entry'
:
comp
.
entry_procedure
=
new_proc
elif
new_proc
.
inputString
.
strip
().
lower
()
==
'exit'
:
comp
.
exit_procedure
=
new_proc
comp
.
content
.
inner_procedures
.
append
(
new_proc
)
elif
child
.
type
==
lexer
.
COMPOSITE_STATE
: