Commit 914047ca authored by Maxime Perrotin's avatar Maxime Perrotin
Browse files

Merge branch 'python3-pyside2' of https://github.com/esa/opengeode into python3-pyside2

parents 8b7d1b85 f79e60bf
![alt tag](icons/opengeode3.png)
OpenGEODE
=========
......@@ -19,7 +21,7 @@ Features
--------
- Graphical editor of SDL processes and procedures.
- Includes support for state composition and state aggregation (parallel/nested states)
- Support for state composition and state aggregation (parallel/nested states)
- Works on pure PR+CIF files (textual SDL notation)
- Supports ASN.1 data types using ESA Space Certified compiler (www.github.com/ttsiodras/asn1scc)
- Generates Ada code
......@@ -31,6 +33,14 @@ Features
- Undo/Redo, Copy-Paste
- (Limited) VIM mode - You can use :wq or :%s,search,replace,g, and /search pattern
- Python API to parse and render SDL from other Python modules
- Simulator (prototype)
Main limitations
-----------
- Supports only one process at a time (use [TASTE](https://taste.tools) to connect processes to form a complete system)
- Minimal support of legacy SDL datatypes (newtypes/synonyms..): use ASN.1 instead
Installation
============
......@@ -39,34 +49,21 @@ OpenGEODE is made primarily for Linux.
It is part of the [TASTE project](https://taste.tools)
It is installed with all dependencies in the TASTE virtual machine that you can download from this link.
Linux Pre-requisites
--------------------
It is installed with all dependencies in the TASTE virtual machine that you can download from this link. Manual installation is possible in a native Linux environment.
Debian 10 (buster) is the baseline. Recent versions of Ubuntu (20.x) should work as well.
To install OpenGEODE on Linux you need to install some system-level dependencies:
The following commands should automate the installation:
- Python 2.7 with pip
- PySide
- Graphviz
- [ASN1SCC V4](https://github.com/ttsiodras/asn1scc)
- GNAT
On Debian, Ubuntu, and probably other distributions:
```bash
$ sudo apt install pkg-config python-pyside pyside-tools graphviz python-ply \
graphviz-dev libgraphviz-dev python-pip gnat \
libmono-system-runtime4.0-cil libmono-corlib4.0-cil \
libmono-system-runtime-serialization-formatters-soap4.0-cil \
libmono-system-web4.0-cil libmono-system-xml4.0-cil \
libmono-system4.0-cil mono-runtime libmono-system-numerics4.0-cil \
libmono-system-data-linq4.0-cil libmono-corlib2.0-cil libmono-system2.0-cil
```
$ git clone https://github.com/esa/opengeode
$ cd opengeode
$ sudo make full-install # it will use apt to get dependencies
```
Some of these packages may be more recent on your distribution.
OpenGEODE uses the ASN1 [ASN1SCC](https://github.com/ttsiodras/asn1scc) for the datatypes. You must install it manually:
To install the ASN.1 compiler, you must get the latest binary release of the version 4 from [here](https://github.com/ttsiodras/asn1scc/releases)
Get the latest binary release from [here](https://github.com/ttsiodras/asn1scc/releases)
Then run (possibly as root):
......@@ -82,16 +79,11 @@ Open a new terminal and check that it works:
$ mono /opt/asn1scc/asn1.exe
```
OpenGEODE installation
----------------------
Once all dependencies are installed, run:
Once you have the dependencies installed you can update the tool by running the following commands:
```bash
$ git clone https://github.com/esa/opengeode.git
$ cd opengeode
$ make full-install
```
$ git pull
$ make install # alternatively: pip3 install --user --upgrade .
```
......@@ -107,9 +99,7 @@ The LLVM backend was designed and implemented by Diego Barbera during the ESA
Summer of Code 2014. This component is not maintained.
Some parts implemented by Laurent Meyer (native SDL type support in the parser)
The ASN.1 compiler (ASN1Scc) that OpenGEODE is based on was
developed by George Mamais and Thanassis Tsiodras for the European
Space Agency. Information at https://github.com/ttsiodras/asn1scc
The ASN.1 compiler (ASN1SCC) that OpenGEODE is based on was developed by George Mamais and Thanassis Tsiodras for the European Space Agency.
Licence
=======
......@@ -122,6 +112,10 @@ The background pattern was downloaded from www.subtlepatterns.com
Changelog
=========
3.0.3 (05/2020)
- Replace the unicode separator when flattening the model for code generation
- Fix calls to the exit procedure in nested states
3.0.2 (05/2020)
- Fix API change in Pyside2
......
This diff is collapsed.
......@@ -19,7 +19,7 @@
statenames: return a list of properly-formatted state names
rec_findstates: recursively find parallel/composite statenames
Copyright (c) 2012-2015 European Space Agency
Copyright (c) 2012-2020 European Space Agency
Designed and implemented by Maxime Perrotin
......@@ -36,13 +36,15 @@ from functools import singledispatch
from . import ogAST
LOG = logging.getLogger(__name__)
#DEFAULT_SEPARATOR=u'\00dc'
DEFAULT_SEPARATOR='_0_'
__all__ = ['flatten', 'rename_everything', 'inner_labels_to_floating',
'map_input_state', 'sorted_fields', 'state_aggregations',
'parallel_states', 'statenames', 'rec_findstates']
def statenames(context, sep=u'\u00dc'):
def statenames(context, sep=DEFAULT_SEPARATOR):
''' Return the list of states (just the names) of a given context
Format the output by replacing unicode separator symbol with a dot '''
# note: if model has been flattened, all contexts are already merged
......@@ -196,12 +198,12 @@ def flatten(process, sep=u'_'):
set_terminator_states(state, prefix)
set_transition_states(state, prefix)
keys = list (state.mapping.keys())
state.mapping = {prefix + key: state.mapping.pop(key)
for key in list(state.mapping.keys())}
# Continuous signal mappings
state.cs_mapping = {prefix + key: state.cs_mapping.pop(key)
for key in list(state.cs_mapping.keys())}
process.transitions.extend(state.transitions)
# Add prefix to local variable names and push them at process level
......@@ -253,17 +255,35 @@ def flatten(process, sep=u'_'):
'params': [], 'tmpVars': []}]
process.transitions[each].actions.insert(0, call_entry)
# If composite state has exit procedure, add the call
# If composite state has exit procedure, add an call to this
# procedure if the transition ends up existing the state with
# a return statement. There are other calls to the exit procedure
# that the code generation backend must add when the state is exited
# from a transition trigger in the super state. See AdaGenerator.py
if state.exit_procedure:
# Build up a list of transitions that contain a return statement
trans_with_return = []
for each in chain(state.transitions, (lab.transition for lab in
state.content.floating_labels)):
if each.terminator.kind == 'return':
call_exit = ogAST.ProcedureCall()
call_exit.inputString = 'exit'
exitproc = u'{pre}exit'.format(pre=prefix)
call_exit.output = [{'outputName': exitproc,
'params': [], 'tmpVars': []}]
each.actions.append(call_exit)
def rec_transition(trans : ogAST.Transition):
if trans.terminator:
if trans.terminator.kind == 'return':
trans_with_return.append (trans)
elif isinstance(trans.actions[-1], ogAST.Decision):
# There is no terminator, so the transition may finish
# with a DECISION, we must check it recursively
for answer in trans.actions[-1].answers:
rec_transition (answer.transition)
rec_transition (each)
for trans in trans_with_return:
call_exit = ogAST.ProcedureCall()
call_exit.inputString = 'exit'
exitproc = u'{pre}exit'.format(pre=prefix)
call_exit.output = [{'outputName': exitproc,
'params': [], 'tmpVars': []}]
trans.actions.append(call_exit)
for inner in state.composite_states:
# Go recursively in inner composite states
......@@ -306,19 +326,27 @@ def flatten(process, sep=u'_'):
processed by each of the substates.
'''
if not isinstance(nested_state, ogAST.StateAggregation):
for _, val in nested_state.mapping.items():
for val in nested_state.mapping.values():
try:
inputlist = context.mapping[nested_state.statename]
val.extend(inputlist)
except (AttributeError, KeyError):
# KeyError in case of StateAggregation
pass
for val in nested_state.cs_mapping.values():
try:
inputlist = context.cs_mapping[nested_state.statename]
val.extend(inputlist)
except (AttributeError, KeyError):
# KeyError in case of StateAggregation
pass
for each in nested_state.composite_states:
# do the same recursively
propagate_inputs(each, nested_state)
#del nested_state.mapping[each.statename]
if not isinstance(nested_state, ogAST.StateAggregation):
del context.mapping[nested_state.statename]
del context.cs_mapping[nested_state.statename]
def set_terminator_states(context, prefix=''):
''' Associate state to terminators, needed to process properly
......
......@@ -27,7 +27,7 @@
See AdaGenerator.py for an example of use.
Copyright (c) 2012-2019 European Space Agency
Copyright (c) 2012-2020 European Space Agency
Designed and implemented by Maxime Perrotin
......@@ -369,7 +369,7 @@ class Answer(object):
# one of ExprEq, ExprNeq, ExprGt, ExprGe, ExprLt, ExprLe (types)
self.openRangeOp = None
# transition is of type Transition
self.transition = None
self.transition : Transition = None
# optional comment symbol
self.comment = None
# optional hyperlink
......
......@@ -2462,12 +2462,6 @@ def primary(root, context):
prim.value = []
prim.exprType = UNKNOWN_TYPE
# Let fix_expression_type resolve this type
# prim.exprType = type('PrES', (object,), {
# 'kind': 'SequenceOfType',
# 'Min': '0',
# 'Max': '0',
# 'type': UNKNOWN_TYPE
# })
elif root.type == lexer.CHOICE:
prim = ogAST.PrimChoiceItem()
choice = root.getChild(0).toString()
......@@ -2506,7 +2500,6 @@ def primary(root, context):
'type': prim_elem.exprType
})
elif root.type == lexer.STATE:
LOG.debug("Primary is state")
prim = ogAST.PrimStateReference()
prim.exprType = type ("StateEnumeratedType", (ENUMERATED,), {})
prim.exprType.kind = 'StateEnumeratedType'
......@@ -2673,6 +2666,8 @@ def composite_state(root, parent=None, context=None):
# 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)}
# Same for continuous signal mapping
comp.cs_mapping = {name: [] for name in get_state_list(root)}
inner_composite, states, floatings, starts = [], [], [], []
for child in root.getChildren():
if child.type == lexer.ID:
......@@ -2749,6 +2744,7 @@ def composite_state(root, parent=None, context=None):
# State aggregation contain only composite states, so we must
# add empty mapping information since there are no transitions
comp.mapping[inner.statename.lower()] = []
comp.cs_mapping[inner.statename.lower()] = []
errors.extend(err)
warnings.extend(warn)
comp.composite_states.append(inner)
......@@ -3494,6 +3490,7 @@ def process_definition(root, parent=None, context=None):
# Prepare the transition/state mapping
process.mapping = {name: [] for name in get_state_list(root)}
process.cs_mapping = {name: [] for name in get_state_list(root)}
for child in root.getChildren():
if child.type == lexer.CIF:
# Get symbol coordinates
......
......@@ -140,7 +140,7 @@ except ImportError:
__all__ = ['opengeode', 'SDL_Scene', 'SDL_View', 'parse']
__version__ = '3.0.2'
__version__ = '3.0.3'
if hasattr(sys, 'frozen'):
# Detect if we are running on Windows (py2exe-generated)
......@@ -2016,11 +2016,11 @@ end DataView_{lang};'''
template_makefile = '''export ASN1SCC=$(shell which asn1.exe)
all:
\tgprbuild -p -P {pr}.gpr # generate Ada code from the SDL model
\tgprbuild -p -P {prFile}.gpr # generate Ada code from the SDL model
\tgprbuild -p -P dataview_ada.gpr # generate Ada code from the ASN.1 model
\tgprbuild -p -P code/{pr}_ada.gpr # build the Ada code
\tgprbuild -p -P code/{processName}_ada.gpr # build the Ada code
clean:
\trm -rf obj code'''.format(pr=prj_name)
\trm -rf obj code'''
# If the current scene is a nested one, save the top parent
scene = self.top_scene()
......@@ -2092,6 +2092,12 @@ clean:
pr_raw = Pr.parse_scene(scene, full_model=True
if not self.readonly_pr else False)
# Read the processs name for the Makefile
for each in scene.processes:
if not isinstance(each, ProcessType):
process_name = str(each.text)
break
# Move items back to original place to avoid scrollbar jumps
for item in self.scene().floating_symb:
item.pos_x -= delta_x
......@@ -2152,7 +2158,9 @@ clean:
# and generate a Makefile.project to build everything
with open(pr_path + '/Makefile.{}'.format(prj_name), 'w') as f:
f.write(template_makefile)
f.write(template_makefile
.format(prFile=prj_name,
processName=process_name.lower()))
self.scene().clear_focus()
for each in chain([scene], scene.all_nested_scenes):
......
Supports Markdown
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