Commit d0508f89 authored by Maxime Perrotin's avatar Maxime Perrotin
Browse files
parents da20e4a5 08b99c71
......@@ -141,9 +141,10 @@ The background pattern was downloaded from www.subtlepatterns.com
Changelog
=========
1.5.30 (04/2017)
1.5.32 (04/2017)
- Unicode bugfixes in Ada backend
- Bugfix with SEQUENCE OF literals in Ada backend
- Various bugfixes with mixed int32/64 bits
1.5.28 (03/2017)
- Added preliminary support for PROCESS TYPE and instances
......
......@@ -1352,14 +1352,33 @@ def _task_forloop(task, **kwargs):
for loop in task.elems:
if loop['range']:
start_str, stop_str = '0', ''
if loop['range']['start']:
start_stmt, start_str, start_local = expression(
loop['range']['start'])
basic = find_basic_type(loop['range']['start'].exprType)
start_stmt, start_str, start_local = \
expression(loop['range']['start'])
#if basic.kind == "IntegerType" \
# and loop['range']['start'].exprType.__name__ != 'PrInt':
# start_str = u"Integer({})".format(start_str)
if basic.kind == "Integer32Type":
start_str = u"Asn1Int({})".format(start_str)
local_decl.extend(start_local)
stmt.extend(start_stmt)
if loop['range']['step'] == 1:
start_str += '..'
start_str += ' .. '
basic = find_basic_type(loop['range']['stop'].exprType)
stop_stmt, stop_str, stop_local = expression(loop['range']['stop'])
#if basic.kind == "IntegerType" \
# and loop['range']['stop'].exprType.__name__ != 'PrInt':
# stop_str = u"Integer({})".format(stop_str)
if basic.kind == "Integer32Type":
stop_str = u"Asn1Int({})".format(stop_str)
local_decl.extend(stop_local)
stmt.extend(stop_stmt)
if loop['range']['step'] == 1:
......@@ -1367,9 +1386,10 @@ def _task_forloop(task, **kwargs):
stop_str = unicode(int(stop_str) - 1)
else:
stop_str = u'{} - 1'.format(stop_str)
stmt.append(
u'for {it} in {start}{stop} loop'
.format(it=loop['var'], start=start_str, stop=stop_str))
stmt.append(u'for {it} in Asn1Int range {start}{stop} loop'
.format(it=loop['var'],
start=start_str,
stop=stop_str))
else:
# Step is not directly supported in Ada, we need to use 'while'
stmt.extend(['declare',
......@@ -1378,8 +1398,10 @@ def _task_forloop(task, **kwargs):
start=start_str),
'',
'begin',
u'while {it} < {stop} loop'.format(it=loop['var'],
stop=stop_str)])
u'while {it} < {stop} loop'
.format(it=loop['var'], stop=stop_str)])
# Add iterator to the list of local variables
LOCAL_VAR.update({loop['var']: (loop['type'], None)})
else:
# case of form: FOR x in SEQUENCE OF
# Add iterator to the list of local variables
......@@ -1443,16 +1465,16 @@ def expression(expr):
def _primary_variable(prim):
''' Single variable reference '''
var = find_var(prim.value[0])
if not var or is_local(var):
if (not var) or is_local(var):
sep = ''
else:
sep = LPREFIX + '.'
ada_string = u'{sep}{name}'.format(sep=sep, name=prim.value[0])
if prim.exprType.__name__ == 'for_range':
# Ada iterator in FOR loops is an Integer - we must cast to 64 bits
ada_string = u'Asn1Int({})'.format(ada_string)
# if prim.exprType.__name__ == 'for_range':
# # Ada iterator in FOR loops is an Integer - we must cast to 64 bits
# ada_string = u'Asn1Int({})'.format(ada_string)
return [], unicode(ada_string), []
......@@ -1722,10 +1744,47 @@ def _primary_state_reference(prim):
def _basic_operators(expr):
''' Expressions with two sides '''
code, local_decl = [], []
left_stmts, left_str, left_local = expression(expr.left)
left_stmts, left_str, left_local = expression(expr.left)
right_stmts, right_str, right_local = expression(expr.right)
ada_string = u'({left} {op} {right})'.format(
left=left_str, op=expr.operand, right=right_str)
##
#print expr.inputString, " ==> ", left_str, ' and ', right_str,
right_is_numeric, left_is_numeric = True, True
try:
float(left_str)
except ValueError:
left_is_numeric = False
try:
float(right_str)
except ValueError:
right_is_numeric = False
lbty = find_basic_type(expr.left.exprType)
rbty = find_basic_type(expr.right.exprType)
#print lbty.kind, rbty.kind
if rbty.kind != lbty.kind and 'Integer32Type' in (lbty.kind, rbty.kind):# \
# and "PrInt" not in (expr.left.exprType.__name__,
# expr.right.exprType.__name__):
if lbty.kind == 'IntegerType' and not right_is_numeric:
right_str = u'Asn1Int({})'.format(right_str)
elif not left_is_numeric:
left_str = u'Asn1Int({})'.format(left_str)
##
if left_is_numeric == right_is_numeric == True:
ada_string = u"{}".format(eval(u"{left} {op} {right}"
.format(left=left_str,
op=expr.operand,
right=right_str)))
else:
ada_string = u'({left} {op} {right})'.format(left=left_str,
op=expr.operand,
right=right_str)
code.extend(left_stmts)
code.extend(right_stmts)
local_decl.extend(left_local)
......@@ -2305,7 +2364,7 @@ def _decision(dec, branch_to=None, sep='if ', last='end if;', **kwargs):
code.extend(q_stmts)
if not basic:
code.append('tmp{idx} := {q};'.format(idx=dec.tmpVar, q=q_str))
code.append(u'tmp{idx} := {q};'.format(idx=dec.tmpVar, q=q_str))
for a in dec.answers:
code.extend(traceability(a))
......@@ -2773,7 +2832,7 @@ def find_var(var):
def is_local(var):
''' Check if a variable is in the global context or in a local scope
Typically needed to select the right prefix to use '''
return var in LOCAL_VAR.viewkeys()
return var.lower() in (loc.lower() for loc in LOCAL_VAR.viewkeys())
def path_type(path):
......
......@@ -367,7 +367,12 @@ def rename_everything(ast, from_name, to_name):
in the scope of a composite state, so that they do not overwrite
a variable with the same name declared at a higher scope.
'''
LOG.debug ('rename_everything - ' + str(ast))
# LOG.debug ('rename_everything - ' + str(ast) + " - ")
# try:
# LOG.debug(ast.inputString)
# except:
# pass
_, _, _ = ast, from_name, to_name
......@@ -503,10 +508,19 @@ def _rename_expr(ast, from_name, to_name):
@rename_everything.register(ogAST.PrimIndex)
def _rename_index(ast, from_name, to_name):
''' Index of an array '''
rename_everything(ast.value[0], from_name, to_name)
for each in ast.value[1]['index']:
rename_everything(each, from_name, to_name)
@rename_everything.register(ogAST.PrimSubstring)
def _rename_substring(ast, from_name, to_name):
''' Substrings '''
rename_everything(ast.value[0], from_name, to_name)
for each in ast.value[1]['substring']:
rename_everything(each, from_name, to_name)
@rename_everything.register(ogAST.PrimVariable)
def _rename_path(ast, from_name, to_name):
''' Ultimate seek point for the renaming: primary path/variables '''
......@@ -514,6 +528,13 @@ def _rename_path(ast, from_name, to_name):
ast.value[0] = to_name
@rename_everything.register(ogAST.PrimCall)
def _rename_primcall(ast, from_name, to_name):
''' PrimCall is used e.g. by function "length" (special operators) '''
for each in ast.value[1]['procParams']:
rename_everything(each, from_name, to_name)
@rename_everything.register(ogAST.PrimConditional)
def _rename_ifhthenelse(ast, from_name, to_name):
''' Rename expressions in Conditional expression construct '''
......
......@@ -919,8 +919,8 @@ def compare_types(type_a, type_b): # type -> [warnings]
else:
raise TypeError('Incompatible sizes - size of {} can vary'
.format(type_name(type_b)))
elif(int(type_b.Min) >= int(type_a.Min)
and int(type_b.Max) <= int(type_a.Max)):
elif(float(type_b.Min) >= float(type_a.Min)
and float(type_b.Max) <= float(type_a.Max)):
warnings.extend(compare_types(type_a.type, type_b.type))
return warnings
else:
......@@ -1140,6 +1140,11 @@ def primary_variable(root, context):
''' Primary Variable analysis '''
name = getattr(root.getChild(0), 'text', 'error')
errors, warnings = [], []
# Detect reserved keywords
if name.lower() in ('integer', 'real', 'procedure', 'begin', 'end',
'for', 'in', 'out', 'loop'):
errors.append(u"Use of forbidden keyword for a variable name : {}"
.format(name))
possible_constant = is_asn1constant(name)
if possible_constant:
......@@ -1316,9 +1321,14 @@ def arithmetic_expression(root, context):
# Expressions returning a numerical type must have their range defined
# accordingly with the kind of opration used between operand:
basic = find_basic_type(expr.left.exprType)
left = find_basic_type(expr.left.exprType)
right = find_basic_type(expr.right.exprType)
# Type of the resulting expression depends on whether there are raw numbers
# on one side of the expression (PrInt). By default when they are parsed,
# they are set to 64 bits integers ; but if they are in an expression where
# the other side is 32 bits (Length or for loop range) then the resulting
# expression is 32 bits.
basic = right if left.__name__ == 'PrInt' else left
try:
if isinstance(expr, ogAST.ExprPlus):
attrs = {'Min': str(float(left.Min) + float(right.Min)),
......@@ -1528,6 +1538,7 @@ def conditional_expression(root, context):
warnings.extend(fix_expression_types(expr, context))
expr.exprType = then_expr.exprType
except (AttributeError, TypeError) as err:
#print str(err), expr.inputString
if UNKNOWN_TYPE not in (then_expr.exprType, else_expr.exprType):
errors.append(error(root, str(err)))
......@@ -4175,6 +4186,12 @@ def for_range(root, context):
result['stop'] = expr[0]
else:
errors.append('Incorrect range expression')
# Basic check that range element basic types are all integers
for each in expr:
basic = find_basic_type(each.exprType)
if not basic.kind.startswith("Integer"):
errors.append(u"Expression {} is not evaluated to integer"
.format(each.inputString))
return result, errors, warnings
......@@ -4190,6 +4207,12 @@ def for_loop(root, context):
forloop['var'] = child.text
# Implicit variable declaration for the iterator
context_scope = dict(context.variables)
if child.text.lower() in (var.lower()
for var in chain (context.variables.viewkeys(),
context.global_variables.viewkeys())):
errors.append("FOR variable '{}' is already declared in the"
" scope (shadow variable). Please rename it."
.format(child.text))
elif child.type == lexer.VARIABLE:
forloop['list'], err, warn = primary_variable(child, context)
warnings.extend(warn)
......@@ -4234,6 +4257,7 @@ def for_loop(root, context):
# currently visible to the SDL parser
result_type = type('for_range', (INTEGER,), {'Min': r_min,
'Max': r_max})
forloop['type'] = result_type
context.variables[forloop['var']] = (result_type, 0)
forloop['transition'], err, warn = transition(
......
......@@ -138,7 +138,7 @@ except ImportError:
__all__ = ['opengeode', 'SDL_Scene', 'SDL_View', 'parse']
__version__ = '1.5.30'
__version__ = '1.5.32'
if hasattr(sys, 'frozen'):
# Detect if we are running on Windows (py2exe-generated)
......
......@@ -54,7 +54,8 @@ SDL_BLACKBOLD = ['\\b{word}\\b'.format(word=word) for word in (
'NEWTYPE', 'ENDNEWTYPE', 'ARRAY', 'STRUCT', 'SYNONYM')]
SDL_REDBOLD = ['\\b{word}\\b'.format(word=word) for word in (
'INPUT', 'OUTPUT', 'STATE', 'DECISION', 'NEXTSTATE',
'INPUT', 'OUTPUT', 'STATE', 'DECISION', 'NEXTSTATE', 'INTEGER',
'CHARACTER', 'ASN1INT',
'TASK', 'PROCESS', 'LABEL', 'JOIN', 'CONNECTION', 'CONNECT')]
......
......@@ -2,18 +2,42 @@
import pytest
from PySide import QtCore
from opengeode.opengeode import SDL_Scene, SDL_View
from opengeode.opengeode import SDL_Scene, SDL_View, G_SYMBOLS
from opengeode.sdlSymbols import Label, Decision
from opengeode.ogParser import parseSingleElement
from opengeode.ogAST import Process, Automaton
TEST_DATA = '''
/* CIF label (275, 194), (70, 35) */
connection p0:
/* CIF decision (275, 249), (70, 50) */
decision d;
/* CIF ANSWER (230, 319), (70, 23) */
(a):
/* CIF ANSWER (320, 319), (70, 23) */
(b):
enddecision;
/* CIF End Label */
endconnection;
'''
def test_1(qtbot):
''' Test the parsing of numbers '''
''' Test objective is to check the Paste function on horizontal items
Render a floating label followed by a decision and 2 answers
Check the relative position of the answers
then Copy-Paste the floating labels (including children)
and verify that the relative position of the children is kept
'''
# Need an Automaton to render the scene with "render_everything"
ast = Automaton()
floating, _, _, _, _ = parseSingleElement('floating_label', TEST_DATA)
ast.floating_labels = [floating]
ast.parent = Process()
scene = SDL_Scene(context="process")
scene.add_symbol(Label)
view = SDL_View (scene)
view.show()
qtbot.addWidget(view)
qtbot.keyClick(view,25)
# assert(not isinstance(res.tree, antlr3.tree.CommonErrorNode))
scene.render_everything(ast)
assert (len(list(scene.floating_symb)) == 1)
if __name__ == '__main__':
......
include ../shared.mk
all: test-ada test-llvm
edit:
$(OPENGEODE) packetmanager.pr system_structure.pr
test-parse:
$(OPENGEODE) packetmanager.pr system_structure.pr --check
test-ada: packetmanager.ali
test-c: packetmanager.c
$(CC) -c packetmanager.c
test-llvm: packetmanager.o
coverage:
coverage run -p $(OPENGEODE) packetmanager.pr system_structure.pr --toAda
.PHONY: all edit test-parse test-ada test-llvm coverage
TASTE-Dataview DEFINITIONS ::=
BEGIN
-- Boolean
MyBoolean ::= BOOLEAN
-- 4 bit array
My4BitArray ::= SEQUENCE (SIZE (4)) OF BOOLEAN
-- 8 bit array
My8BitArray ::= SEQUENCE (SIZE (8)) OF BOOLEAN
-- Integer for 8 bit array numbering
My8BitArrayInteger ::= INTEGER (0..7)
-- Integer for 8 bit array value numbering
My8BitArrayValueInteger ::= INTEGER (0..255)
-- 16 bit array
My16BitArray ::= SEQUENCE (SIZE (16)) OF BOOLEAN
-- Integer for 16 bit array numbering
My16BitArrayInteger ::= INTEGER (0..15)
-- Integer for 16 bit array value numbering
My16BitArrayValueInteger ::= INTEGER (0..65535)
-- Packet structure
MyPacket ::= SEQUENCE (SIZE (0..255)) OF MyFrame
-- Stack for data in bits
MyDataStack ::= SEQUENCE (SIZE (40..2000)) OF BOOLEAN
-- Stack for data of FCS calculation
MyFcsStack ::= SEQUENCE (SIZE (224..2192)) OF BOOLEAN -- Frame has empty info or is full
-- Integer for data of FCS calculation
MyFcsStackInteger ::= INTEGER (0..2175)
-- Polynomial for FCS calculation
MyFcsPolynomial ::= SEQUENCE (SIZE (17)) OF BOOLEAN
-- Integer for polynomial numbering
MyFcsPolynomialInteger ::= INTEGER (0..16)
-- Frame structure
MyFrame ::= SEQUENCE {
startFlag MyFlag,
addr MyAddr,
control MyControl,
pid MyPid,
info MyInfo,
fcs MyFcs,
endFlag MyFlag
}
-- FRAME: Frame delimiter
MyFlag ::= My8BitArray -- Fixed value 0x7E
-- FRAME: Source of frame and destination
MyAddr ::= SEQUENCE {
destinationAddress MyDestinationAddress,
sourceAddress MySourceAddress
}
-- ADDR: Destination address
MyDestinationAddress ::= SEQUENCE (SIZE (7)) OF My8BitArray
-- ADDR: Source address
MySourceAddress ::= SEQUENCE (SIZE (7)) OF My8BitArray
-- FRAME: Type of frame
MyControl ::= My8BitArray
-- FRAME: Protocol of info
MyPid ::= My8BitArray -- Fixed value 0xF0
-- FRAME: Info structure
MyInfo ::= SEQUENCE {
ba MyBa,
cntrl MyCntrl,
code MyCode,
operationData MyOperationData,
ifcs MyIfcs,
auth MyAuth OPTIONAL
}
-- INFO: Bus address
MyBa ::= SEQUENCE {
srcAddr MySrcAddr,
dstAddr MyDstAddr
}
-- BA: Source address
MySrcAddr ::= My4BitArray
-- BA: Destination address
MyDstAddr ::= My4BitArray
-- INFO: Control - frame type
MyCntrl ::= My8BitArray -- Fixed value 0x03
-- INFO: Code - operation
MyCode ::= My8BitArray
-- INFO: Operation data
MyOperationData ::= SEQUENCE (SIZE (0..250)) OF My8BitArray
-- INFO: Info Frame check sequence
MyIfcs ::= My16BitArray
-- INFO: Authentication
MyAuth ::= My16BitArray
-- FRAME: Frame check sequence
MyFcs ::= My16BitArray
-- Stack of L3 frames
MyL3Stack ::= SEQUENCE (SIZE (0..255)) OF MyL3Data
-- Stack of L3 frame numbers
MyL3StackNumbers ::= SEQUENCE (SIZE (0..255)) OF BOOLEAN
-- Integer for L3 frame stack numbering
MyL3StackInteger ::= INTEGER (0..254)
-- Stack of L3 missing frame numbers in octets
MyL3MissingStack ::= SEQUENCE (SIZE (0..255)) OF My8BitArray
-- Stack for L3 data in bits
MyL3DataStack ::= SEQUENCE (SIZE (0..1960)) OF BOOLEAN
-- Stack for data of L3 FCS calculation
MyL3FcsStack ::= SEQUENCE (SIZE (80..2040)) OF BOOLEAN -- L3 frame is empty or full
-- Integer for data of L3 FCS calculation
MyL3FcsStackInteger ::= INTEGER (0..2023)
-- Polynomial for L3 FCS calculation
MyL3FcsPolynomial ::= SEQUENCE (SIZE (17)) OF BOOLEAN
-- L3 frame structure
MyL3Frame ::= SEQUENCE {
l3Ba MyL3Ba,
l3Cntrl MyL3Cntrl,
l3Code MyL3Code,
l3Tte MyL3Tte,
l3Mrt MyL3Mrt,
l3Fnum MyL3Fnum,
l3Data MyL3Data,
l3Fcs MyL3Fcs
}
-- L3 FRAME: Bus address
MyL3Ba ::= SEQUENCE {
l3SrcAddr MyL3SrcAddr,
l3DstAddr MyL3DstAddr
}
-- L3BA: Source address
MyL3SrcAddr ::= My4BitArray
-- L3BA: Destination address
MyL3DstAddr ::= My4BitArray
-- L3 FRAME: Control - frame type
MyL3Cntrl ::= My8BitArray -- Fixed value 0x03
-- L3 FRAME: Code - data frame identificator
MyL3Code ::= My8BitArray
-- L3 FRAME: Time to end
MyL3Tte ::= My16BitArray
-- L3 FRAME: Maximum response time
MyL3Mrt ::= My16BitArray
-- L3 FRAME: Frame counter
MyL3Fnum ::= My8BitArray
-- L3 FRAME: Data
MyL3Data ::= SEQUENCE (SIZE (0..245)) OF My8BitArray
-- Integer for L3 data
MyL3DataInteger ::= INTEGER (0..244)
-- Stack for L3 acknowledgement data in bits
MyL3AckDataStack ::= SEQUENCE (SIZE (0..1952)) OF BOOLEAN
-- Stack for data of L3 acknowledgement FCS calculation
MyL3AckFcsStack ::= SEQUENCE (SIZE (88..2040)) OF BOOLEAN -- L3 acknowledgement frame is empty or full
-- Stack of L3 missing frame numbers
MyL3AckMissingStack ::= SEQUENCE (SIZE (0..244)) OF INTEGER (0..255)
-- Integer for stack of L3 missing frame stack numbering
MyL3AckMissingStackInteger ::= INTEGER (0..243)
-- L3 FRAME: Frame check sequence
MyL3Fcs ::= My16BitArray
-- L3 acknowledgement frame structure
MyL3AckFrame ::= SEQUENCE {
l3Ba MyL3Ba,
l3Cntrl MyL3Cntrl,
l3Code MyL3Code,
l3Tte MyL3Tte,
l3Mrt MyL3Mrt,
l3Lfn MyL3Lfn,
l3Hfn MyL3Hfn,
l3Rrq MyL3Rrq,
l3Fcs MyL3Fcs
}
-- L3 ACKNOWLEDGEMENT FRAME: Lowest sequential frame number
MyL3Lfn ::= My8BitArray
-- L3 ACKNOWLEDGEMENT FRAME: Highest frame sequence number
MyL3Hfn ::= My8BitArray
-- L3 ACKNOWLEDGEMENT FRAME: Frame numbers missing
MyL3Rrq ::= SEQUENCE (SIZE (0..244)) OF My8BitArray
-- Integer for L3 frame numbers missing
MyL3RrqInteger ::= INTEGER (0..243)
-- Input data structure
MyInputData ::= SEQUENCE {
ba MyBa,
code MyCode,
rawData MyRawData OPTIONAL,
l3Mrt MyL3Mrt OPTIONAL,
l3AckMissingStack MyL3AckMissingStack OPTIONAL
}
-- INPUT DATA: Raw data