Commit 299496c6 authored by Maxime Perrotin's avatar Maxime Perrotin
Browse files

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

parents 9559e025 2c9f5c60
...@@ -58,7 +58,9 @@ full-install: update ...@@ -58,7 +58,9 @@ full-install: update
$(MAKE) install $(MAKE) install
publish: publish:
@python3 setup.py sdist upload @rm -f dist/*
@python3 setup.py sdist bdist_wheel
@twine upload dist/*
pytest: pytest:
# make sure you have installed pytest-qt: # make sure you have installed pytest-qt:
......
...@@ -53,50 +53,17 @@ Debian 10 (buster) is the baseline. Recent versions of Ubuntu (20.x) should work ...@@ -53,50 +53,17 @@ Debian 10 (buster) is the baseline. Recent versions of Ubuntu (20.x) should work
Using TASTE Using TASTE
----------- -----------
__Important: OpenGEODE is already installed in the TASTE Virtual Machine, and fully integrated with the toolset, however, the current TASTE VM is a bit old - it is based on Debian 9 which does not have important dependencies to support the latest version of OpenGEODE. It is missing Python 3.7+ and PySide2. An upgrade is in the works, but it's not ready yet. If you are familiar enough with Linux, you can manually upgrade by completing the following steps.__ __Important: OpenGEODE is already installed in the TASTE10 Virtual Machine (based on Debian Buster), and fully integrated with the toolset. It is the easiest way to get started with OpenGEODE__
_Install the [TASTE VM](https://taste.tools/#install). Once logged in, enter a new shell and:_ To start a new project run:
``` ```
# Switch to root $ taste
sudo su
# Make sure VM image is up to date
apt-get update
apt-get upgrade
apt-get dist-upgrade
# Point APT to Buster to prepare for upgrade
sed -i 's/stretch/buster/g' /etc/apt/sources.list
# Upgrade packages to Buster; when prompted allow services to be restarted automatically
apt-get upgrade
# Upgrade distribution to Buster
apt-get dist-upgrade
# Remove packages no longer needed
apt-get autoremove
# Return to taste user; exit root
exit
# Navigate to TASTE source; upgrade
cd ~/tool-src
git pull
git checkout feature_buster
./Update-TASTE.sh
``` ```
After this upgrade, you can work with the latest version of the tools, in particular the new Kazoo build system and Opengeode 3.xx (which you can update at any time). The Quick Reference Card has not been updated to reflect this yet. Select a project name and the graphical editor will pop-up shortly after. You can add functions to the system and specify the imnplementation language to __SDL__. When you edit the function, the OpenGEODE editor will start.
The main differences to create/edit a project is that you must just run `taste<` (and not `taste-create-project/taste-edit-project` anymore). To build, run `make`.
You can check an example of a system using Opengeode if you go in `~/tool-src/kazoo/tests/Demo_ABB_Opengeode` and run `make` to build it. Then `taste` to edit. You can check an example of a system using Opengeode if you go in `~/tool-src/kazoo/tests/Demo_ABB_Opengeode` and run `make` to build it. Then `taste` to edit.
In the interface view, select the SDL language for the implementation of the blocks you want to model using OpenGEODE.
Then when you right-click on the SDL block you can select the option "Open SDL Editor".
The code is automatically generated when you exit the tool. The code is automatically generated when you exit the tool.
Manual Manual
...@@ -138,7 +105,7 @@ Once you have the dependencies installed you can update the tool by running the ...@@ -138,7 +105,7 @@ Once you have the dependencies installed you can update the tool by running the
``` ```
$ git pull $ git pull
$ make install # alternatively: pip3 install --user --upgrade . $ make install # alternatively: pip3 install --user --upgrade opengeode
``` ```
OpenGEODE Website OpenGEODE Website
...@@ -175,6 +142,18 @@ The background pattern was downloaded from www.subtlepatterns.com ...@@ -175,6 +142,18 @@ The background pattern was downloaded from www.subtlepatterns.com
Changelog Changelog
========= =========
**3.3.2 (10/2020)**
- Fix reporting of semantic errors in procedures
**3.3.1 (09/2020)**
- Fix issue with type synonyms
- Update installation procedure
- Enable pip3 installations from PyPI
**3.3.0 (08/2020)**
- Save the state as an ASN.1 model instead of a native Ada type
- Ada backend basic support for "decision any"
**3.2.3 (09/2020) **3.2.3 (09/2020)
- Fix type checks when a type inherits another type with different constraints - Fix type checks when a type inherits another type with different constraints
......
This diff is collapsed.
...@@ -849,6 +849,8 @@ class Procedure: ...@@ -849,6 +849,8 @@ class Procedure:
# input/output signal lists - unused but for context information # input/output signal lists - unused but for context information
self.input_signals = [] self.input_signals = []
self.output_signals = [] self.output_signals = []
# The "DECISION ANY" construct requires random number generators
self.random_generator = set()
class Process: class Process:
...@@ -935,6 +937,9 @@ class Process: ...@@ -935,6 +937,9 @@ class Process:
# list of processes used for context management of the GUI # list of processes used for context management of the GUI
self.processes = [] self.processes = []
# The "DECISION ANY" construct requires random number generators
self.random_generator = set()
class CompositeState(Process): class CompositeState(Process):
''' '''
......
...@@ -1194,9 +1194,6 @@ def check_type_compatibility(primary, type_ref, context): ...@@ -1194,9 +1194,6 @@ def check_type_compatibility(primary, type_ref, context):
raise TypeError(f'Type of array element {primary.inputString} ' raise TypeError(f'Type of array element {primary.inputString} '
f'does not match expected type "{type_name(type_ref)}"') f'does not match expected type "{type_name(type_ref)}"')
else: else:
print( isinstance(primary, ogAST.PrimIndex))
print( primary.exprType != type_ref)
print (f"{primary} {primary.exprType} vs {type_ref}")
raise TypeError('{prim} does not match type {t1}' raise TypeError('{prim} does not match type {t1}'
.format(prim=primary.inputString, .format(prim=primary.inputString,
t1=type_name(type_ref))) t1=type_name(type_ref)))
...@@ -1864,7 +1861,7 @@ def arithmetic_expression(root, context): ...@@ -1864,7 +1861,7 @@ def arithmetic_expression(root, context):
if (not is_number(basic_left) if (not is_number(basic_left)
and basic_left.kind == 'Integer32Type') or (not is_number and basic_left.kind == 'Integer32Type') or (not is_number
(basic_right) and basic_right.kind == 'Integer32Type'): (basic_right) and basic_right.kind == 'Integer32Type'):
# One of the operand is a loop index (SIGNED) # One of the operands is a loop index (SIGNED)
kind = 'Integer32Type' kind = 'Integer32Type'
expr.exprType = type("Computed_Range", expr.exprType = type("Computed_Range",
(basic_right if not is_number(basic_right) (basic_right if not is_number(basic_right)
...@@ -1902,7 +1899,14 @@ def arithmetic_expression(root, context): ...@@ -1902,7 +1899,14 @@ def arithmetic_expression(root, context):
bound_max = str(float(bounds['Max'])) bound_max = str(float(bounds['Max']))
attrs = {'Min': bound_min, 'Max': bound_max} attrs = {'Min': bound_min, 'Max': bound_max}
expr.exprType = type('Computed_Range_2', (basic_right,), attrs) # If a side is an Integer32 and the other side a Integer64
# then the base type should be Integer64
if (basic_right.kind == basic_left.kind
or basic_right.kind == "IntegerType"):
base_type = basic_right # Any is ok
else:
base_type = basic_left
expr.exprType = type('Computed_Range_2', (base_type,), attrs)
if expr.exprType is not UNKNOWN_TYPE: if expr.exprType is not UNKNOWN_TYPE:
expr.expected_type = expr.exprType expr.expected_type = expr.exprType
...@@ -2284,6 +2288,7 @@ def primary_index(root, context, pos): ...@@ -2284,6 +2288,7 @@ def primary_index(root, context, pos):
expression(root.children[0], context, pos) expression(root.children[0], context, pos)
receiver_bty = find_basic_type(receiver.exprType) receiver_bty = find_basic_type(receiver.exprType)
errors.extend(receiver_err) errors.extend(receiver_err)
warnings.extend(receiver_warn) warnings.extend(receiver_warn)
...@@ -2921,7 +2926,9 @@ def procedure_pre(root, parent=None, context=None): ...@@ -2921,7 +2926,9 @@ def procedure_pre(root, parent=None, context=None):
elif child.type == lexer.TEXTAREA: elif child.type == lexer.TEXTAREA:
textarea, err, warn = text_area(child, context=proc) textarea, err, warn = text_area(child, context=proc)
if textarea.signals: if textarea.signals:
errors.append('Signals shall not be declared in a procedure') errors.append([f'In procedure {proc.inputString}:'
' signals shall not be declared in a procedure',
[textarea.pos_x or 0, textarea.pos_y or 0], []])
errors.extend(err) errors.extend(err)
warnings.extend(warn) warnings.extend(warn)
proc.content.textAreas.append(textarea) proc.content.textAreas.append(textarea)
...@@ -2933,10 +2940,15 @@ def procedure_pre(root, parent=None, context=None): ...@@ -2933,10 +2940,15 @@ def procedure_pre(root, parent=None, context=None):
warnings.extend(warn) warnings.extend(warn)
proc.fpar = params proc.fpar = params
elif child.type == lexer.RETURNS: elif child.type == lexer.RETURNS:
# Declaration not in a text area...
if proc.return_type is not None:
errors.append([f'In procedure {proc.inputString}: '
'duplicate "returns" statement', [0, 0], []])
try: try:
proc.return_type, proc.return_var = procedure_returns(child) proc.return_type, proc.return_var = procedure_returns(child)
except TypeError as err: except TypeError as err:
errors.append(str(err)) errors.append([f"In procdure {proc.inputString}: {str(err)}",
[0, 0], []])
if proc.return_var: if proc.return_var:
warnings.append('Procedure return variable not supported') warnings.append('Procedure return variable not supported')
elif child.type in (lexer.PROCEDURE, lexer.START, elif child.type in (lexer.PROCEDURE, lexer.START,
...@@ -2948,6 +2960,8 @@ def procedure_pre(root, parent=None, context=None): ...@@ -2948,6 +2960,8 @@ def procedure_pre(root, parent=None, context=None):
sdl92Parser.tokenNamesMap[child.type] + sdl92Parser.tokenNamesMap[child.type] +
' - line ' + str(child.getLine()) + ' - line ' + str(child.getLine()) +
' - in procedure ' + str(proc.inputString)) ' - in procedure ' + str(proc.inputString))
for each in chain(errors, warnings):
each[2].insert(0, f'PROCEDURE {proc.inputString}')
return proc, content, errors, warnings return proc, content, errors, warnings
...@@ -3033,18 +3047,17 @@ def procedure_post(proc, content, parent=None, context=None): ...@@ -3033,18 +3047,17 @@ def procedure_post(proc, content, parent=None, context=None):
try: try:
warnings.extend(fix_expression_types(check_expr, context)) warnings.extend(fix_expression_types(check_expr, context))
except (TypeError, AttributeError) as err: except (TypeError, AttributeError) as err:
errors.append(str(err)) errors.append([f"In procedure {proc.inputString}: {str(err)}",
[0, 0], []])
# Id of fd_expr may have changed (enumerated, choice) # Id of fd_expr may have changed (enumerated, choice)
each.return_expr = check_expr.right each.return_expr = check_expr.right
elif proc.return_type and not each.return_expr: elif proc.return_type and each.kind == 'return' and not each.return_expr:
errors.append(['Missing return value in procedure {}' errors.append([f'Missing return value in procedure {proc.inputString}',
.format(proc.inputString),
[0, 0], []]) [0, 0], []])
else: else:
continue continue
for each in chain(errors, warnings): for each in chain(errors, warnings):
each[2].insert(0, 'PROCEDURE {}'.format(proc.inputString)) each[2].insert(0, f'PROCEDURE {proc.inputString}')
return errors, warnings return errors, warnings
...@@ -3288,6 +3301,8 @@ def text_area_content(root, ta_ast, context): ...@@ -3288,6 +3301,8 @@ def text_area_content(root, ta_ast, context):
except AttributeError: except AttributeError:
errors.append('Entity cannot have an FPAR section') errors.append('Entity cannot have an FPAR section')
elif child.type == lexer.RETURNS: elif child.type == lexer.RETURNS:
if context.return_type is not None:
errors.append('Duplicate "returns" statement')
try: try:
context.return_type, context.return_var =\ context.return_type, context.return_var =\
procedure_returns(child) procedure_returns(child)
...@@ -4398,6 +4413,8 @@ def decision(root, parent, context): ...@@ -4398,6 +4413,8 @@ def decision(root, parent, context):
dec.tmpVar = tmp() dec.tmpVar = tmp()
has_else = False has_else = False
dec_x, dec_y = 0, 0 dec_x, dec_y = 0, 0
# To support the "decision any" construct:
need_random_generator = False
for child in root.getChildren(): for child in root.getChildren():
if child.type == lexer.CIF: if child.type == lexer.CIF:
# Get symbol coordinates # Get symbol coordinates
...@@ -4419,6 +4436,7 @@ def decision(root, parent, context): ...@@ -4419,6 +4436,7 @@ def decision(root, parent, context):
warnings.append(['Use of "ANY" introduces non-determinism ', warnings.append(['Use of "ANY" introduces non-determinism ',
[dec.pos_x, dec.pos_y], []]) [dec.pos_x, dec.pos_y], []])
dec.kind = 'any' dec.kind = 'any'
need_random_generator = True
dec.inputString = get_input_string(child) dec.inputString = get_input_string(child)
dec.question = ogAST.PrimStringLiteral() dec.question = ogAST.PrimStringLiteral()
dec.question.value = 'ANY' dec.question.value = 'ANY'
...@@ -4451,6 +4469,10 @@ def decision(root, parent, context): ...@@ -4451,6 +4469,10 @@ def decision(root, parent, context):
else: else:
warnings.append(['Unsupported DECISION child type: ' + warnings.append(['Unsupported DECISION child type: ' +
str(child.type), [dec.pos_x, dec.pos_y], []]) str(child.type), [dec.pos_x, dec.pos_y], []])
if need_random_generator:
# If there are N answers, code generators will need a random
# number from 0 to N.
context.random_generator.add(len(dec.answers))
# Make type checks to be sure that question and answers are compatible # Make type checks to be sure that question and answers are compatible
covered_ranges = defaultdict(list) covered_ranges = defaultdict(list)
qmin, qmax = 0, 0 qmin, qmax = 0, 0
...@@ -5128,8 +5150,16 @@ def for_loop(root, context): ...@@ -5128,8 +5150,16 @@ def for_loop(root, context):
r_min = '0' r_min = '0'
else: else:
basic = find_basic_type(start_expr.exprType) basic = find_basic_type(start_expr.exprType)
# ASN.1 constant -> use the constant value
if isinstance(start_expr, ogAST.PrimConstant):
basic.Min = \
get_asn1_constant_value(start_expr.constant_value)
r_min = basic.Min if basic != UNKNOWN_TYPE else '0' r_min = basic.Min if basic != UNKNOWN_TYPE else '0'
basic = find_basic_type(stop_expr.exprType) basic = find_basic_type(stop_expr.exprType)
# ASN.1 constant -> get the value in place of the type's Max
if isinstance(stop_expr, ogAST.PrimConstant):
basic.Max = \
get_asn1_constant_value(stop_expr.constant_value)
r_max = str(int(float(basic.Max) - 1)) \ r_max = str(int(float(basic.Max) - 1)) \
if basic != UNKNOWN_TYPE else '4294967295' if basic != UNKNOWN_TYPE else '4294967295'
result_type = type('for_range', (INT32,), {'Min': r_min, result_type = type('for_range', (INT32,), {'Min': r_min,
......
...@@ -140,7 +140,7 @@ except ImportError: ...@@ -140,7 +140,7 @@ except ImportError:
__all__ = ['opengeode', 'SDL_Scene', 'SDL_View', 'parse'] __all__ = ['opengeode', 'SDL_Scene', 'SDL_View', 'parse']
__version__ = '3.2.3' __version__ = '3.3.2'
if hasattr(sys, 'frozen'): if hasattr(sys, 'frozen'):
# Detect if we are running on Windows (py2exe-generated) # Detect if we are running on Windows (py2exe-generated)
......
...@@ -2,8 +2,8 @@ ...@@ -2,8 +2,8 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
''' '''
Setup file for Linux distribution Setup file for Linux distribution
Usage: python setup.py sdist --> to create a tarball Usage: python3 setup.py sdist bdist_wheel --> to create a tarball
python setup.py install --> to install in python directory pip3 install --user --upgrade . --> to install in ~/.local
''' '''
# from distutils.core import setup # from distutils.core import setup
...@@ -19,15 +19,17 @@ setup( ...@@ -19,15 +19,17 @@ setup(
author_email='maxime.perrotin@esa.int', author_email='maxime.perrotin@esa.int',
description='A free SDL editor for TASTE', description='A free SDL editor for TASTE',
long_description=open('README.md').read(), long_description=open('README.md').read(),
long_description_content_type="text/markdown",
install_requires=[], install_requires=[],
tests_require=['tabulate'], tests_require=['tabulate'],
include_package_data=True, include_package_data=True,
url='http://opengeode.net', url='http://opengeode.net',
python_requires='>=3.7',
classifiers=[ classifiers=[
'Programming Language :: Python', 'Programming Language :: Python',
'License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3)', 'License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3)',
'Operating System :: OS Independent', 'Operating System :: OS Independent',
'Programming Language :: Python :: 3.7' 'Programming Language :: Python :: 3'
], ],
entry_points={ entry_points={
'console_scripts': [ 'console_scripts': [
......
...@@ -52,14 +52,14 @@ endsystem; ...@@ -52,14 +52,14 @@ endsystem;
assert False assert False
def test_system_with_error_2(): def test_system_with_error_2():
''' Detect the syntax error (missing SEMI after "procedure entry") ''' ''' no error '''
string='''system huuh; string='''system huuh;
block huuh; block huuh;
process huuh; process huuh;
/* CIF START (171, 77), (70, 35) */ /* CIF START (171, 77), (70, 35) */
START; START;
/* CIF NEXTSTATE (171, 132), (70, 35) */ /* CIF NEXTSTATE (171, 132), (70, 35) */
NEXTSTATE a-; NEXTSTATE -;
/* CIF state (386, 90), (70, 35) */ /* CIF state (386, 90), (70, 35) */
state a; state a;
endstate; endstate;
...@@ -79,7 +79,7 @@ endsystem; ...@@ -79,7 +79,7 @@ endsystem;
err = "\n".join(test.error_list) err = "\n".join(test.error_list)
raise SyntaxError(err) raise SyntaxError(err)
else: else:
assert False pass
if __name__ == '__main__': if __name__ == '__main__':
for name, value in dict(globals()).viewitems(): for name, value in dict(globals()).viewitems():
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
**/tmp/ **/tmp/
**/build/ **/build/
logs/
*/code/ */code/
*/GPS_project.gpr */GPS_project.gpr
*/*generated */*generated
...@@ -28,3 +28,7 @@ ...@@ -28,3 +28,7 @@
**/*.log **/*.log
**actual **actual
*/*.xml */*.xml
**/*.pr.ini
**/asn1_x86.gpr
**/*_datamodel.asn
**/*_ada.gpr
project controller_Ada is
for Languages use ("Ada");
for Source_Dirs use (".") & External_As_List ("CODE_PATH", ":");
for Object_Dir use "../obj";
end controller_Ada;
\ No newline at end of file
...@@ -28,7 +28,7 @@ test-qgen-gt-c: ...@@ -28,7 +28,7 @@ test-qgen-gt-c:
test-ada: test-ada:
#make -f Makefile.og #make -f Makefile.og
$(OPENGEODE) og.pr --toAda $(OPENGEODE) og.pr --toAda
mono $(ASN1SCC) -Ada -typePrefix asn1Scc -equal dataview.asn mono $(ASN1SCC) -Ada -typePrefix asn1Scc -equal *.asn
gnat make titi gnat make titi
test-c: test-c:
......
project DataView_Ada is
for Languages use ("ASN1");
for Source_Dirs use (".");
for Source_Files use ("dataview.asn");
for Object_Dir use "code";
package Naming is
for Body_Suffix ("ASN1") use ".asn";
end Naming;
package Compiler is
for Driver ("ASN1") use "mono";
for Leading_Required_Switches ("ASN1") use
(external("ASN1SCC"),
"-Ada",
"-typePrefix",
"Asn1Scc");
end Compiler;
end DataView_Ada;
\ No newline at end of file
...@@ -13,11 +13,12 @@ TESTQGEN_GT_ADA=../testqgen.py test-qgen-gt-ada ...@@ -13,11 +13,12 @@ TESTQGEN_GT_ADA=../testqgen.py test-qgen-gt-ada
TESTQGEN_GT_C=../testqgen.py test-qgen-gt-c TESTQGEN_GT_C=../testqgen.py test-qgen-gt-c
clean: clean:
gnat clean *.adb
rm -rf *.adb *.ads *.pyc runSpark.sh spark.idx *.o *.so *.ali gnat.cfg \ rm -rf *.adb *.ads *.pyc runSpark.sh spark.idx *.o *.so *.ali gnat.cfg \
examiner bin *.wrn GPS_project.gpr *.ll *.s dataview-uniq.c dataview-uniq.h \ examiner bin *.wrn GPS_project.gpr *.ll *.s dataview-uniq.c dataview-uniq.h \
real.c xer.c ber.c acn.c asn1crt.c asn1crt.h test_ada test_llvm \ real.c xer.c ber.c acn.c asn1crt.c asn1crt.h test_ada test_llvm \
*.autosave *_simu.sh *_interface.aadl *.lst *.gcno *.gcda *.gcov \ *.autosave *_simu.sh *_interface.aadl *.lst *.gcno *.gcda *.gcov \
check obj src code check obj src code *_datamodel.asn asn1_x86.gpr *_ada.gpr
%.o: %.pr FORCE %.o: %.pr FORCE
$(OPENGEODE) $< system_structure.pr --llvm -O$(O) $(OPENGEODE) $< system_structure.pr --llvm -O$(O)
...@@ -30,8 +31,8 @@ clean: ...@@ -30,8 +31,8 @@ clean:
%.ali: %.pr FORCE %.ali: %.pr FORCE
$(OPENGEODE) $< system_structure.pr --toAda && \ $(OPENGEODE) $< system_structure.pr --toAda && \
mono $(ASN1SCC) -Ada -typePrefix asn1Scc -equal dataview-uniq.asn && \ mono $(ASN1SCC) -Ada -typePrefix asn1Scc -equal *.asn && \
$(GNATMAKE) -O$(O) -gnat2012 -c -g -fprofile-arcs -ftest-coverage *.adb $(GNATMAKE) -O$(O) -c -g -fprofile-arcs -ftest-coverage *.adb
%.o: %.asn FORCE %.o: %.asn FORCE
mono $(ASN1SCC) -c -typePrefix asn1Scc -equal $< mono $(ASN1SCC) -c -typePrefix asn1Scc -equal $<
......
...@@ -27,7 +27,7 @@ test-qgen-gt-c: ...@@ -27,7 +27,7 @@ test-qgen-gt-c:
test-ada: test-ada:
$(OPENGEODE) og.pr --toAda $(OPENGEODE) og.pr --toAda
mono $(ASN1SCC) -Ada -typePrefix asn1Scc -equal dataview-uniq.asn mono $(ASN1SCC) -Ada -typePrefix asn1Scc -equal *.asn
$(GNATMAKE) -O$(O) -c *.adb $(GNATMAKE) -O$(O) -c *.adb
$(GNATBIND) -n og.ali $(GNATBIND) -n og.ali
......