Commit b3055210 authored by Maxime Perrotin's avatar Maxime Perrotin
Browse files

Proper range check when using OCTET STRINGs/SEQUENCE OF

parent ef5cbe44
...@@ -125,6 +125,9 @@ def _process(process): ...@@ -125,6 +125,9 @@ def _process(process):
# Expression must be a ground expression, i.e. must not # Expression must be a ground expression, i.e. must not
# require temporary variable to store computed result # require temporary variable to store computed result
dst, dstr, dlocal = expression(def_value) dst, dstr, dlocal = expression(def_value)
varbty = find_basic_type(var_type)
if varbty.kind in ('SequenceOfType', 'OctetStringType'):
dstr = array_content(def_value, dstr, varbty)
assert not dst and not dlocal, 'DCL: Expecting a ground expression' assert not dst and not dlocal, 'DCL: Expecting a ground expression'
process_level_decl.append( process_level_decl.append(
u'l_{n} : aliased asn1Scc{t}{default};'.format( u'l_{n} : aliased asn1Scc{t}{default};'.format(
...@@ -152,9 +155,6 @@ def _process(process): ...@@ -152,9 +155,6 @@ def _process(process):
# Add the declaration of the runTransition procedure # Add the declaration of the runTransition procedure
process_level_decl.append('procedure runTransition(Id: Integer);') process_level_decl.append('procedure runTransition(Id: Integer);')
#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: # Generate the code of the start transition:
start_transition = ['begin', start_transition = ['begin',
...@@ -419,31 +419,43 @@ def write_statement(param, newline): ...@@ -419,31 +419,43 @@ def write_statement(param, newline):
local = [] local = []
basic_type = find_basic_type(param.exprType) or {} basic_type = find_basic_type(param.exprType) or {}
type_kind = basic_type.kind type_kind = basic_type.kind
if type_kind.endswith('StringType'): if isinstance(param, ogAST.ExprAppend):
# Append: call Put_Line separately for each side of the expression
st1, _, lcl1= write_statement(param.left, newline = False)
st2, _, lcl2 = write_statement(param.right, newline = False)
code.extend(st1)
code.extend(st2)
local.extend(lcl1)
local.extend(lcl2)
elif type_kind.endswith('StringType'):
if isinstance(param, ogAST.PrimStringLiteral): if isinstance(param, ogAST.PrimStringLiteral):
# Raw string # Raw string
string = '"' + param.value[1:-1].replace('"', "'") + '"' code.append(u'Put("{}");'
.format(param.value[1:-1].replace('"', "'")))
else: else:
code, string, local = expression(param) code, string, local = expression(param)
if type_kind == 'OctetStringType': if type_kind == 'OctetStringType':
# Octet string -> convert to Ada string # Octet string -> convert to Ada string
sep = u'\u00dc' sep = u'\u00dc'
localstr = u'tmp{}{}str'.format(str(param.tmpVar), sep) last_it = u""
local.append(u'{} : String(1 .. {});'
.format(localstr, basic_type.Max))
if isinstance(param, ogAST.PrimSubstring): if isinstance(param, ogAST.PrimSubstring):
range_str = u"{}'Range".format(string) range_str = u"{}'Range".format(string)
iterator = u"i - {}'First + 1".format(string)
elif basic_type.Min == basic_type.Max: elif basic_type.Min == basic_type.Max:
range_str = u"{}.Data'Range".format(string) range_str = u"{}.Data'Range".format(string)
string += u".Data" string += u".Data"
iterator = u"i"
else: else:
range_str = u"1 .. {}.Length".format(string) range_str = u"1 .. {}.Length".format(string)
string += u".Data" string += u".Data"
iterator = u"i"
last_it = u"({})".format(range_str)
code.extend([u"for i in {} loop".format(range_str), code.extend([u"for i in {} loop".format(range_str),
u"{tmp}(i) := Character'Val({st}(i));" u"Put(Character'Val({st}(i)));"
.format(tmp=localstr, st=string, sep=sep), .format(st=string, sep=sep, it=iterator),
u"end loop;"]) u"end loop;"])
string = u'{}({})'.format(localstr, range_str) else:
code.append("Put({});".format(string))
elif type_kind in ('IntegerType', 'RealType', elif type_kind in ('IntegerType', 'RealType',
'BooleanType', 'Integer32Type'): 'BooleanType', 'Integer32Type'):
code, string, local = expression(param) code, string, local = expression(param)
...@@ -453,15 +465,14 @@ def write_statement(param, newline): ...@@ -453,15 +465,14 @@ def write_statement(param, newline):
cast = 'Long_Float' cast = 'Long_Float'
elif type_kind == 'BooleanType': elif type_kind == 'BooleanType':
cast = 'Boolean' cast = 'Boolean'
string = u"{cast}'Image({s})".format(cast=cast, s=string) code.append(u"Put({cast}'Image({s}));".format(cast=cast, s=string))
else: else:
error = (u'Unsupported parameter in write call ' + error = (u'Unsupported parameter in write call ' +
param.inputString) param.inputString)
LOG.error(error) LOG.error(error)
raise TypeError(error) raise TypeError(error)
code.append(u'Put{line}({string});'.format( if newline:
line=u'_Line' if newline else u'', code.append(u"New_Line;")
string=string))
return code, string, local return code, string, local
...@@ -551,11 +562,16 @@ def _call_external_function(output): ...@@ -551,11 +562,16 @@ def _call_external_function(output):
# Create a temporary variable for input parameters only # Create a temporary variable for input parameters only
# (If needed, i.e. if argument is not a local variable) # (If needed, i.e. if argument is not a local variable)
if param_direction == 'in' \ if param_direction == 'in' \
and (not (isinstance(param, ogAST.PrimVariable) and and (not (isinstance(param, ogAST.PrimVariable)
p_id.startswith('l_')) or isinstance(param, ogAST.PrimFPAR)): and p_id.startswith('l_'))
or isinstance(param, ogAST.PrimFPAR)):
tmp_id = out['tmpVars'][idx] tmp_id = out['tmpVars'][idx]
local_decl.append('tmp{idx} : aliased asn1Scc{oType};' local_decl.append('tmp{idx} : aliased asn1Scc{oType};'
.format(idx=tmp_id, oType=typename)) .format(idx=tmp_id, oType=typename))
if isinstance(param,
(ogAST.PrimSequenceOf, ogAST.PrimStringLiteral)):
p_id = array_content(param, p_id,
find_basic_type(param_type))
code.append('tmp{idx} := {p_id};' code.append('tmp{idx} := {p_id};'
.format(idx=tmp_id, p_id=p_id)) .format(idx=tmp_id, p_id=p_id))
list_of_params.append("tmp{idx}'access" list_of_params.append("tmp{idx}'access"
...@@ -597,7 +613,6 @@ def _task_assign(task): ...@@ -597,7 +613,6 @@ def _task_assign(task):
# ExprAssign only returns code statements, no string # ExprAssign only returns code statements, no string
code_assign, _, decl_assign = expression(expr) code_assign, _, decl_assign = expression(expr)
code.extend(code_assign) code.extend(code_assign)
# code.append(ada_string[1:-1] + ';')
local_decl.extend(decl_assign) local_decl.extend(decl_assign)
return code, local_decl return code, local_decl
...@@ -790,7 +805,6 @@ def _prim_call(prim): ...@@ -790,7 +805,6 @@ def _prim_call(prim):
elif ident == 'num': elif ident == 'num':
# User wants to get an enumerated corresponding integer value # User wants to get an enumerated corresponding integer value
exp = params[0] exp = params[0]
#exp_type = find_basic_type(exp.exprType)
# Get the ASN.1 type name as it is needed to build the Ada expression # Get the ASN.1 type name as it is needed to build the Ada expression
exp_typename = \ exp_typename = \
(getattr(exp.exprType, 'ReferencedTypeName', None) (getattr(exp.exprType, 'ReferencedTypeName', None)
...@@ -956,8 +970,10 @@ def _prim_selector(prim): ...@@ -956,8 +970,10 @@ def _prim_selector(prim):
receiver_ty_name = receiver.exprType.ReferencedTypeName.replace('-', '_') receiver_ty_name = receiver.exprType.ReferencedTypeName.replace('-', '_')
if receiver_bty.kind == 'ChoiceType': if receiver_bty.kind == 'ChoiceType':
ada_string = ('asn1Scc{typename}_{field_name}_get({ada_string})'.format( ada_string = ('asn1Scc{typename}_{field_name}_get({ada_string})'
typename=receiver_ty_name, field_name=field_name, ada_string=ada_string)) .format(typename=receiver_ty_name,
field_name=field_name,
ada_string=ada_string))
else: else:
ada_string += '.' + field_name ada_string += '.' + field_name
...@@ -995,22 +1011,27 @@ def _equality(expr): ...@@ -995,22 +1011,27 @@ def _equality(expr):
right_stmts, right_str, right_local = expression(expr.right) right_stmts, right_str, right_local = expression(expr.right)
code.extend(right_stmts) code.extend(right_stmts)
local_decl.extend(right_local) local_decl.extend(right_local)
actual_type = getattr(expr.left.exprType, asn1_type = getattr(expr.left.exprType,
'ReferencedTypeName', 'ReferencedTypeName',
None) or expr.left.exprType.kind None) or expr.left.exprType.kind
actual_type = actual_type.replace('-', '_') actual_type = asn1_type.replace('-', '_')
basic = find_basic_type(expr.left.exprType).kind in ('IntegerType', lbty = find_basic_type(expr.left.exprType)
'Integer32Type', basic = lbty.kind in ('IntegerType', 'Integer32Type', 'BooleanType',
'BooleanType', 'RealType', 'EnumeratedType', 'ChoiceEnumeratedType')
'RealType',
'EnumeratedType',
'ChoiceEnumeratedType')
if basic: if basic:
ada_string = u'({left} {op} {right})'.format( ada_string = u'({left} {op} {right})'.format(
left=left_str, op=expr.operand, right=right_str) left=left_str, op=expr.operand, right=right_str)
else: else:
ada_string = u'asn1Scc{asn1}_Equal({left}, {right})'.format( if asn1_type in TYPES:
asn1=actual_type, left=left_str, right=right_str) if isinstance(expr.right,
(ogAST.PrimSequenceOf, ogAST.PrimStringLiteral)):
right_str = array_content(expr.right, right_str, lbty)
ada_string = u'asn1Scc{asn1}_Equal({left}, {right})'.format(
asn1=actual_type, left=left_str, right=right_str)
else:
# Raw types on both left and right.... use simple operator
ada_string = u"({left}) {op} ({right})".format(left=left_str,
op=expr.operand, right=right_str)
if isinstance(expr, ogAST.ExprNeq): if isinstance(expr, ogAST.ExprNeq):
ada_string = u'not {}'.format(ada_string) ada_string = u'not {}'.format(ada_string)
return code, unicode(ada_string), local_decl return code, unicode(ada_string), local_decl
...@@ -1026,13 +1047,33 @@ def _assign_expression(expr): ...@@ -1026,13 +1047,33 @@ def _assign_expression(expr):
# If left side is a string/seqOf and right side is a substring, we must # If left side is a string/seqOf and right side is a substring, we must
# assign the .Data and .Length parts properly # assign the .Data and .Length parts properly
basic_left = find_basic_type(expr.left.exprType) basic_left = find_basic_type(expr.left.exprType)
if basic_left.kind in ('SequenceOfType', 'OctetStringType') \ if basic_left.kind in ('SequenceOfType', 'OctetStringType'):
and isinstance(expr.right, ogAST.PrimSubstring): rlen = "{}'Length".format(right_str)
strings.append(u"{lvar}.Data(1..{rvar}'Length) := {rvar};" if isinstance(expr.right, ogAST.PrimSubstring):
strings.append(u"{lvar}.Data(1..{rvar}'Length) := {rvar};"
.format(lvar=left_str, rvar=right_str)) .format(lvar=left_str, rvar=right_str))
if basic_left.Min != basic_left.Max: elif isinstance(expr.right, ogAST.ExprAppend):
strings.append(u"{lvar}.Length := {rvar}'Length;" basic_right = find_basic_type(expr.right.exprType)
.format(lvar=left_str, rvar=right_str)) rlen = append_size(expr.right)
strings.append(u"{lvar}.Data(1..{lstr}) := {rvar};"
.format(lvar=left_str,
rvar=right_str,
lstr=rlen))
elif isinstance(expr.right, (ogAST.PrimSequenceOf,
ogAST.PrimStringLiteral)):
strings.append(u"{lvar} := {value};"
.format(lvar=left_str,
value=array_content(expr.right,
right_str,
basic_left)))
rlen = None
else:
# Right part is a variable
strings.append(u"{} := {};".format(left_str, right_str))
rlen = None
if rlen and basic_left.Min != basic_left.Max:
strings.append(u"{lvar}.Length := {rlen};"
.format(lvar=left_str, rlen=rlen))
else: else:
strings.append(u"{} := {};".format(left_str, right_str)) strings.append(u"{} := {};".format(left_str, right_str))
code.extend(left_stmts) code.extend(left_stmts)
...@@ -1134,60 +1175,16 @@ def _append(expr): ...@@ -1134,60 +1175,16 @@ def _append(expr):
stmts.extend(right_stmts) stmts.extend(right_stmts)
local_decl.extend(left_local) local_decl.extend(left_local)
local_decl.extend(right_local) local_decl.extend(right_local)
# Declare a temporary variable to hold the result of the append
ada_string = 'tmp{}'.format(expr.tmpVar) left = '{}{}'.format(left_str, string_payload(expr.left, left_str) if
local_decl.append('{tmp} : aliased asn1Scc{eType};'.format( isinstance(expr.left, (ogAST.PrimVariable,
tmp=ada_string, ogAST.PrimConstant)) else '')
eType=expr.exprType.ReferencedTypeName right = '{}{}'.format(right_str, string_payload(expr.right, right_str) if
.replace('-', '_'))) isinstance(expr.right, (ogAST.PrimVariable,
ogAST.PrimConstant)) else '')
# If right or left is raw, declare a temporary variable for it, too
for sexp, sid in zip((expr.right, expr.left), (right_str, left_str)): ada_string = '(({}) & ({}))'.format(left, right)
if sexp.is_raw:
local_decl.append(u'tmp{idx} : aliased asn1Scc{eType};'.format(
idx=sexp.tmpVar,
eType=sexp.exprType.ReferencedTypeName
.replace('-', '_')))
stmts.append(u'tmp{idx} := {s_id};'.format(
idx=sexp.tmpVar, s_id=sid))
sexp.sid = u'tmp' + unicode(sexp.tmpVar)
# Length of raw string - update for sequence of
if isinstance(sexp, ogAST.PrimStringLiteral):
sexp.slen = unicode(len(sexp.value[1:-1]))
elif isinstance(sexp, ogAST.PrimEmptyString):
sexp.slen = u'0'
elif isinstance(sexp, ogAST.PrimSequenceOf):
sexp.slen = unicode(len(sexp.value))
else:
raise TypeError('Not a string/Sequence in APPEND')
else:
sexp.sid = sid
basic = find_basic_type(sexp.exprType)
if basic.Min == basic.Max:
# Fixed-size string
sexp.slen = unicode(basic.Max)
else:
# Variable-size types have a Length field
if isinstance(sexp, ogAST.PrimSubstring):
sexp.slen = u"{}'Length".format(sexp.sid)
else:
sexp.slen = u'{}.Length'.format(sexp.sid)
left_payload = expr.left.sid + string_payload(expr.left, expr.left.sid)
right_payload = expr.right.sid + string_payload(expr.right, expr.right.sid)
if unicode.isnumeric(expr.left.slen) \
and unicode.isnumeric(expr.right.slen):
length = unicode(int(expr.left.slen) + int(expr.right.slen))
else:
length = u'{} + {}'.format(expr.left.slen, expr.right.slen)
stmts.append(u'{res}.Data(1 .. {length}) := {lid} & {rid};'
.format(length=length,
res=ada_string,
lid=left_payload,
rid=right_payload))
basic_tmp = find_basic_type(expr.exprType)
if basic_tmp.Min != basic_tmp.Max:
# Update lenght field of resulting variable (if variable size)
stmts.append(u'{}.Length := {};'.format(ada_string, length))
return stmts, unicode(ada_string), local_decl return stmts, unicode(ada_string), local_decl
...@@ -1280,13 +1277,7 @@ def _string_literal(primary): ...@@ -1280,13 +1277,7 @@ def _string_literal(primary):
# as expected by the Ada type corresponding to Octet String # as expected by the Ada type corresponding to Octet String
unsigned_8 = [str(ord(val)) for val in primary.value[1:-1]] unsigned_8 = [str(ord(val)) for val in primary.value[1:-1]]
ada_string = u'(Data => (' + ', '.join( ada_string = u', '.join(unsigned_8)
unsigned_8) + ', others => 0)'
if basic_type.Min != basic_type.Max:
# Non-fixed string size -> add Length field
ada_string += u', Length => {}'.format(
str(len(primary.value[1:-1])))
ada_string += ')'
return [], unicode(ada_string), [] return [], unicode(ada_string), []
...@@ -1367,11 +1358,15 @@ def _sequence(seq): ...@@ -1367,11 +1358,15 @@ def _sequence(seq):
for elem, value in seq.value.viewitems(): for elem, value in seq.value.viewitems():
# Set the type of the field - easy thanks to ASN.1 flattened AST # Set the type of the field - easy thanks to ASN.1 flattened AST
delem = elem.replace('_', '-') delem = elem.replace('_', '-')
#value.exprType = (TYPES elem_specty = find_basic_type(seqType).Children[delem].type
# [seqType.ReferencedTypeName].type.Children[delem].type) #value.exprType = find_basic_type(seqType).Children[delem].type
value.exprType = find_basic_type(seqType).Children[delem].type
value_stmts, value_str, local_var = expression(value) value_stmts, value_str, local_var = expression(value)
ada_string += sep + elem + ' => ' + value_str if isinstance(value, (ogAST.PrimSequenceOf, ogAST.PrimStringLiteral)):
# Raw SEQOF element need additional parentheses
#value_str = '(Data => ({}))'.format(value_str)
value_str = array_content(value, value_str,
find_basic_type(elem_specty))
ada_string += "{} {} => {}".format(sep, elem, value_str)
sep = ', ' sep = ', '
stmts.extend(value_stmts) stmts.extend(value_stmts)
local_decl.extend(local_var) local_decl.extend(local_var)
...@@ -1384,31 +1379,22 @@ def _sequence_of(seqof): ...@@ -1384,31 +1379,22 @@ def _sequence_of(seqof):
''' Return Ada string for an ASN.1 SEQUENCE OF ''' ''' Return Ada string for an ASN.1 SEQUENCE OF '''
stmts, local_decl = [], [] stmts, local_decl = [], []
seqofType = seqof.exprType seqofType = seqof.exprType
typename = seqofType.ReferencedTypeName try:
LOG.debug('SequenceOf Typename:' + str(typename)) typename = seqofType.ReferencedTypeName
asn_type = TYPES[typename].type LOG.debug('SequenceOf Typename:' + str(typename))
min_size = asn_type.Min asn_type = TYPES[typename].type
max_size = asn_type.Max min_size = asn_type.Min
ada_string = 'asn1Scc{seqofType}\'('.format( max_size = asn_type.Max
seqofType=typename.replace('-', '_')) except AttributeError:
if min_size == max_size: min_size, max_size = seqofType.Min, seqofType.Max
# Fixed-length array - no need to set the Length field
ada_string += 'Data => asn1Scc{seqofType}_array\'('.format( tab = []
seqofType=typename.replace('-', '_'))
else:
# Variable-length array
ada_string += (
'Length => {length}, Data => asn1Scc{seqofType}_array\'('
.format(seqofType=typename.replace('-', '_'),
length=len(seqof.value)))
for i in xrange(len(seqof.value)): for i in xrange(len(seqof.value)):
# Set the type of the element (should not be useful anymore)
#seqof.value[i].exprType = TYPES[typename].type.type
item_stmts, item_str, local_var = expression(seqof.value[i]) item_stmts, item_str, local_var = expression(seqof.value[i])
stmts.extend(item_stmts) stmts.extend(item_stmts)
local_decl.extend(local_var) local_decl.extend(local_var)
ada_string += '{i} => {value}, '.format(i=i + 1, value=item_str) tab.append('{i} => {value}'.format(i=i + 1, value=item_str))
ada_string += 'others => {anyVal}))'.format(anyVal=item_str) ada_string = ', '.join(tab)
return stmts, unicode(ada_string), local_decl return stmts, unicode(ada_string), local_decl
...@@ -1463,6 +1449,10 @@ def _decision(dec): ...@@ -1463,6 +1449,10 @@ def _decision(dec):
local_decl.extend(ans_decl) local_decl.extend(ans_decl)
if not basic: if not basic:
if a.openRangeOp in (ogAST.ExprEq, ogAST.ExprNeq): if a.openRangeOp in (ogAST.ExprEq, ogAST.ExprNeq):
if isinstance(a.constant, (ogAST.PrimSequenceOf,
ogAST.PrimStringLiteral)):
ans_str = array_content(a.constant, ans_str,
find_basic_type(question_type))
exp = u'asn1Scc{actType}_Equal(tmp{idx}, {ans})'.format( exp = u'asn1Scc{actType}_Equal(tmp{idx}, {ans})'.format(
actType=actual_type, idx=dec.tmpVar, ans=ans_str) actType=actual_type, idx=dec.tmpVar, ans=ans_str)
if a.openRangeOp == ogAST.ExprNeq: if a.openRangeOp == ogAST.ExprNeq:
...@@ -1664,6 +1654,9 @@ def _inner_procedure(proc): ...@@ -1664,6 +1654,9 @@ def _inner_procedure(proc):
# Expression must be a ground expression, i.e. must not # Expression must be a ground expression, i.e. must not
# require temporary variable to store computed result # require temporary variable to store computed result
dst, dstr, dlocal = expression(def_value) dst, dstr, dlocal = expression(def_value)
varbty = find_basic_type(var_type)
if varbty.kind in ('SequenceOfType', 'OctetStringType'):
dstr = array_content(def_value, dstr, varbty)
assert not dst and not dlocal, 'Ground expression error' assert not dst and not dlocal, 'Ground expression error'
code.append('l_{name} : asn1Scc{sort}{default};'.format( code.append('l_{name} : asn1Scc{sort}{default};'.format(
name=var_name, name=var_name,
...@@ -1709,6 +1702,55 @@ def string_payload(prim, ada_string): ...@@ -1709,6 +1702,55 @@ def string_payload(prim, ada_string):
return payload return payload
def array_content(prim, values, asnty):
''' String literal and SEQOF are given as a sequence of elements ;
this function builds the Ada string needed to fit it in an ASN.1 array
i.e. convert "1,2,3" to "Data => (1,2,3, others=>0), [Length => 3]"
inputs: prim is of type PrimStringLiteral or PrimSequenceOf
values is a string with the sequence of numbers as processed by expression
asnty is the reference type of the string literal '''
rtype = find_basic_type(prim.exprType)
if asnty.Min != asnty.Max:
# Reference type can vary -> there is a Length field
rlen = u", Length => {}".format(rtype.Min)
else:
rlen = u""
if isinstance(prim, ogAST.PrimStringLiteral):
df = '0'
else:
# Find a default value for the "others" field in case of SEQOF
_, df, _ = expression(prim.value[0])
return u"(Data => ({}, others => {}){})".format(values, df, rlen)
def append_size(append):
''' Return a string corresponding to the length of an APPEND construct
This function is recursive, to handle cases such as a//b//c
that is handled as (a//b) // c -> get the length of a//b then add c
'''
result = ''
basic = find_basic_type(append.exprType)
if basic.Min == basic.Max:
# Simple case when appending two fixed-length sizes
return basic.Min
for each in (append.left, append.right):
if result:
result += ' + '
if isinstance(each, ogAST.ExprAppend):
# Inner append -> go recursively
result += append_size(each)
else:
bty = find_basic_type(each.exprType)
if bty.Min == bty.Max:
result += bty.Min
else:
# Must be a variable of type SEQOF
_, inner, _ = expression(each)
result += '{}.Length'.format(inner)
return result
def find_basic_type(a_type): def find_basic_type(a_type):
''' Return the ASN.1 basic type of a_type ''' ''' Return the ASN.1 basic type of a_type '''
basic_type = a_type basic_type = a_type
......
...@@ -590,6 +590,7 @@ def check_type_compatibility(primary, type_ref, context): ...@@ -590,6 +590,7 @@ def check_type_compatibility(primary, type_ref, context):
''' '''
assert type_ref is not None assert type_ref is not None
if type_ref is UNKNOWN_TYPE: if type_ref is UNKNOWN_TYPE:
#print traceback.print_stack()
raise TypeError('Type reference is unknown') raise TypeError('Type reference is unknown')
basic_type = find_basic_type(type_ref) basic_type = find_basic_type(type_ref)
...@@ -650,7 +651,8 @@ def check_type_compatibility(primary, type_ref, context): ...@@ -650,7 +651,8 @@ def check_type_compatibility(primary, type_ref, context):
+ basic_type.Min + ')') + basic_type.Min + ')')
elif isinstance(primary, ogAST.PrimSequenceOf) \ elif isinstance(primary, ogAST.PrimSequenceOf) \
and basic_type.kind == 'SequenceOfType': and basic_type.kind == 'SequenceOfType':
if (len(primary.value) < int(basic_type.Min) or if type_ref.__name__ != 'Apnd' and \
(len(primary.value) < int(basic_type.Min) or
len(primary.value) > int(basic_type.Max)): len(primary.value) > int(basic_type.Max)):
raise TypeError(str(len(primary.value)) + raise TypeError(str(len(primary.value)) +
' elements in SEQUENCE OF, while constraint is [' + ' elements in SEQUENCE OF, while constraint is [' +
...@@ -782,11 +784,20 @@ def compare_types(type_a, type_b): ...@@ -782,11 +784,20 @@ def compare_types(type_a, type_b):
if type_a.kind == type_b.kind: if type_a.kind == type_b.kind:
if type_a.kind == 'SequenceOfType': if type_a.kind == 'SequenceOfType':
if type_a.Min == type_b.Min and type_a.Max == type_b.Max: if type_a.Min == type_a.Max:
if type_a.Min == type_b.Min == type_b.Max:
compare_types(type_a.type, type_b.type)
return
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)):
compare_types(type_a.type, type_b.type) compare_types(type_a.type, type_b.type)
return return
else: else:
raise TypeError('Incompatible arrays') compare_types(type_a.type, type_b.type)
raise Warning('Size constraints mismatch - risk of overflow')
# TODO: Check that OctetString types have compatible range # TODO: Check that OctetString types have compatible range
return return
elif is_string(type_a) and is_string(type_b): elif is_string(type_a) and is_string(type_b):
...@@ -862,20 +873,6 @@ def fix_expression_types(expr, context): ...@@ -862,20 +873,6 @@ def fix_expression_types(expr, context):
fix_enumerated_and_choice(expr, context) fix_enumerated_and_choice(expr, context)
expr.right, expr.left = expr.left, expr.right expr.right, expr.left = expr.left, expr.right
# for side in permutations(('left', 'right')):