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

Improve the support for VDM

parent ea5b4744
......@@ -33,6 +33,7 @@ from PySide.QtUiTools import QUiLoader
import asn1_value_editor
from standalone_editor import asn1sccToasn1ValueEditorTypes
import vn
import vdm_vn
import resources
import vdmHandler
......@@ -639,26 +640,29 @@ class sdlHandler(QObject):
interface['in'].append((spec, asn1_instance))
else:
interface['out'].append((spec, as_bytes, asn1_instance))
# HERE: make the function call
# make the function call
vdm_cls = getattr(procedure, "vdm_instance", None)
if vdm_cls:
# convert input parameters to VDM value notation
inp_as_vdm = []
for _, asn1_instance in interface['in']:
inp_as_vdm.append(asn1_instance.GSER())
for spec, asn1_instance in interface['in']:
as_pyside = vn.fromValueNotationToPySide('var',
asn1_instance.GSER())
as_vdm = vdm_vn.pyside_to_vdm(as_pyside.popitem()[1],
spec['type'], self.proc.dataview)
inp_as_vdm.append(as_vdm)
# Actual function call with input parameters in VDM format:
outp = self.vdm.call_function(vdm_cls, name,
','.join(inp_as_vdm))
print "CALLED VDM. Result =", outp
# Use the pyside intermediate form to get the SWIG data
#outp = outp.replace('[', '{').replace(']', '}')
spec, _, out_asn1_inst = interface['out'][0]
# assuming 1 return parameter
vn.valueNotationToSwig(gser=outp,
dest=out_asn1_inst,
sort=spec['type'],
ASN1_AST=self.proc.dataview,
ASN1Swig=ASN1)
#spec_in, asn1_inst_in = interface['in'][0]
#spec_out, as_bytes, asn1_inst_out = interface['out'][0]
#asn1_inst_out.Set(asn1_inst_in.Get() + 1)
# assuming 1 return parameter
vdm_vn.vdm_to_swig(vdm=outp,
dest=out_asn1_inst,
sort=spec['type'],
ASN1_AST=self.proc.dataview,
ASN1Swig=ASN1)
# Copy the OUT parameters back from SWIG to ctypes
for spec, as_bytes, asn1_instance in interface['out']:
# Create new SWIG byte array
......
......@@ -35,7 +35,6 @@ from functools import partial
from itertools import chain
from standalone_editor import asn1sccToasn1ValueEditorTypes
import vn
try:
import dataview_uniq_asn as ASN1
......
......@@ -13,10 +13,10 @@
Set of: { a, b. c }
Sequence of: [a, b, c]
Enum: <value>
Choice: ?
Choice: direct value, no reference to the selected field
Bit string literal : ?
Octet string literal : ?
String Literal : ?
String Literal : "abc"
Copyright (c) 2012-2015 European Space Agency
......@@ -97,9 +97,9 @@ SETOF << LBRACKET + Optional(delimitedList(value)) + RBRACKET
ENUM << LT + ID + GT
# Parse actions allow to transform the AST on the fly
SEQUENCE.setParseAction(lambda s, l, t: [t.asList()])
SEQUENCE.setParseAction(lambda s, l, t: {'Seq': t.asList()})
SEQOF.setParseAction(lambda s, l, t: [t.asList()])
SETOF.setParseAction(lambda s, l, t: [t.asList()])
SETOF.setParseAction(lambda s, l, t: set(t))
ENUM.setParseAction(lambda s, l, t: {'Enum': t[0].replace('-', '_')})
FloatingPointLiteral.setParseAction(lambda s, l, t: float(t[0]))
INT.setParseAction(lambda s, l, t: int(t[0]))
......@@ -119,18 +119,27 @@ def pyside_to_vdm(val, sort=None, ASN1_AST=None):
''' Create a VDM reprentation of the Python variable '''
if isinstance(val, dict):
if 'Choice' in val:
result = pyside_to_vdm(val[val['Choice']])
choice = val['Choice'].replace('_', '-')
type_ref = ASN1_AST[sort.ReferencedTypeName].type
child_sort = type_ref.Children[choice].type
result = pyside_to_vdm(val[val['Choice']], child_sort, ASN1_AST)
elif 'Enum' in val:
result = '<{}>'.format(unicode(val['Enum']).strip())
else: # SEQUENCE
# We need the typename XXX
values = (pyside_to_vdm(field) for _, field in val.viewitems())
result = 'mk_TypeName({})'.format(', '.join(values))
elif isinstance(val, list): # SEQUENCE OF or SET OF
# We need to know the type (SEQOF and SETOF are different in VDM)
values = (pyside_to_vdm(item) for item in val)
result = '[{}]'.format(', '.join(values)) # SEQ OF
#result = '{{{}}'.format(', '.join(values)) # SET OF
typename = sort.ReferencedTypeName.replace('-', '_')
type_ref = ASN1_AST[sort.ReferencedTypeName].type
values = (pyside_to_vdm(field,
type_ref.Children[field.replace('_', '-')],
ASN1_AST) for _, field in val.viewitems())
result = 'mk_{}({})'.format(typename, ', '.join(values))
elif isinstance(val, list):
# Check if it is a SEQOF or SETOF
# Warning: ASN.1 backend python.stg only supports SequenceOf
type_ref = ASN1_AST[sort.ReferencedTypeName].type
child_sort = type_ref.type
values = (pyside_to_vdm(item, child_sort, ASN1_AST) for item in val)
pattern = '[{}]' if type_ref.kind == 'SequenceOfType' else '{{{}}}'
result = pattern.format(', '.join(values))
elif isinstance(val, bool):
# boolean are in lower case in VDM
result = str(val).lower()
......@@ -145,22 +154,35 @@ def pyside_to_vdm(val, sort=None, ASN1_AST=None):
return result
def vdm_to_swig(gser, dest, sort, ASN1Swig, ASN1_AST, var=None):
def vdm_to_swig(vdm, dest, sort, ASN1Swig, ASN1_AST, var=None):
''' Parse a VDM value and fill a SWIG variable with it
Inputs:
gser : input GSER string
vdm : input string in VDM value notation
dest : output SWIG instance to be filled
ASN1Swig : python module containing SWIG DV access
sort: ASN1 typename, with dashes, no underscores
ASN1_AST : AST generated by ASN1SCC
var : optional already pyside-converted GSER string
var : optional already pyside-converted input string
Outputs:
none - "dest" is modified by this function
'''
var = var or value.parseString(gser, True)[0]
# Parse the VDM string and transform it to a python value
var = var or value.parseString(vdm, True)[0]
def find_basic_type(a_type):
''' Return the ASN.1 basic type of a_type '''
basic_type = a_type
while basic_type.kind == 'ReferenceType':
# Find type with proper case in the data view
for typename in ASN1_AST.viewkeys():
if typename.lower() == basic_type.ReferencedTypeName.lower():
basic_type = TYPES[typename].type
break
return basic_type
def reach(field, orig, idx=True):
''' Helper: move swig pointer to the next field, and optionaly
index (if idx=True)
index (if idx=True)
Inputs: field is a string with optional index (e.g. "a[0]")
orig is the swig pointer
idx: set to true if you want the index to be reached
......@@ -174,8 +196,8 @@ def vdm_to_swig(gser, dest, sort, ASN1Swig, ASN1_AST, var=None):
''' Recursively fill up the value '''
if sort.kind == 'ReferenceType':
sort = ASN1_AST[sort.ReferencedTypeName]
if isinstance(inp, list):
# SEQUENCE OF
kind = sort.type.kind
if kind in ('SequenceOfType', 'SetOfType'):
# get the path to the sequence of
_, params, path = outp.GetState()
if path:
......@@ -192,43 +214,83 @@ def vdm_to_swig(gser, dest, sort, ASN1Swig, ASN1_AST, var=None):
reach(each, outp)
# The ASN1SCC AST only knows if the list has a fixed length
outp.SetLength(len(inp))
elif isinstance(inp, (int, float, bool)):
elif kind in ('IntegerType', 'RealType', 'BooleanType'):
outp.Set(inp)
elif isinstance(inp, dict):
if 'Enum' in inp:
# Get proper enum id from the ASN1SCC AST
enum_id = sort.type.EnumValues[
inp['Enum'].replace('_', '-')].EnumID
val = getattr(ASN1Swig.DV, enum_id)
outp.Set(val)
elif 'Choice' in inp:
child_name = inp['Choice']
ch_ty = sort.type.Children[child_name.replace('_', '-')]
enum_val = getattr(ASN1Swig.DV, ch_ty.EnumID)
outp.kind.Set(enum_val)
rec(inp[child_name],
getattr(outp,
child_name.replace('-', '_')),
ch_ty.type)
else:
# SEQUENCE
# get the path to the sequence
_, params, path = outp.GetState()
if path:
path = path.strip('.').split('.')
for field, data in inp.viewitems():
outp.Reset()
for each in path:
# Reach the path, including indexes
reach(each, outp)
# Then get the field itself
reach(field.replace('-', '_'), outp)
field_ty = sort.type.Children[field.replace('_', '-')]
rec(data, outp, field_ty.type)
# move back to original path
elif kind == 'EnumeratedType':
# Get proper enum id from the ASN1SCC AST
enum_id = sort.type.EnumValues[
inp['Enum'].replace('_', '-')].EnumID
val = getattr(ASN1Swig.DV, enum_id)
outp.Set(val)
elif kind == 'ChoiceType':
# choice : determinant is not set in the vdm string input
# it must be inferred based on the type
map_kind_type = {'BooleanType': bool,
'IntegerType': int,
'RealType': float,
'SequenceType': dict(Seq=[]),
'EnumeratedType': dict(Enum=[]),
'SequenceOfType': list,
'SetOfType': set
}
map_name_sort = {}
for child_name, child_sort in sort.type.Children.viewitems():
# find out the basic kind of each child (BooleanType, ...)
basic_kind = find_basic_type(each.type).kind
# and map it to a python basic type (except for choices)
if basic_kind != 'ChoiceType':
pytype = map_kind_type[basic_kind]
else:
pytype = 'choice_{}'.format(child_name)
if pytype in map_sort_name:
raise RuntimeError('VDM does not support CHOICEs with '
'more than one option of a given type')
map_name_sort[pytype] = child_name
# to be completed. CHOICEs are complicated because vdm does not
# give the name of the choice made
# so if you have a union like this: nat | T1 | T2
# there are two cases: either T1 and T2 are basic types
# (but different from nat) - there is no ambiguity, because from
# the notation we can directly discrimitate the union
# but if T1 and T2 are union types we need to recursively analyse
# them to figure out which path to take to encode the ASN.1 value
# Assuming the ASN.1 type CHOICE { a INTEGER, b CHOICE {...},
# c CHOICE {...} } The code above creates a mapping:
# { int: "a", "choice_b": "b", "choice_c": "c" }
# so if the VDM variable is an int -> no problem, we get field a
# but if it is not an int.. We must search in "b" and "c" choice
# types for a path that leads to a basic type corresponding to the
# VDM value. Todo...
# child_name = inp['Choice']
# ch_ty = sort.type.Children[child_name.replace('_', '-')]
# enum_val = getattr(ASN1Swig.DV, ch_ty.EnumID)
# outp.kind.Set(enum_val)
# rec(inp[child_name],
# getattr(outp,
# child_name.replace('-', '_')),
# ch_ty.type)
elif kind == 'SequenceType':
# get the path to the sequence
_, params, path = outp.GetState()
if path:
path = path.strip('.').split('.')
for field, data in zip(sort.type.Children.viewkeys(), inp['Seq']):
# Yikes! Ordering of fiels in the Sequence is not guaranteed
# in a normal dict....
outp.Reset()
if len(path):
reach(path[0], outp)
for each in path:
# Reach the path, including indexes
reach(each, outp)
# Then get the field itself
reach(field.replace('-', '_'), outp)
field_ty = sort.type.Children[field.replace('_', '-')]
rec(data, outp, field_ty.type)
# move back to original path
outp.Reset()
if len(path):
reach(path[0], outp)
else:
# Unsupported type
pass
......
Markdown is supported
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