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

Parse VDM values

parent f1e29439
......@@ -34,182 +34,119 @@ from pyparsing import(Word, QuotedString, Literal, Combine, Optional,
import string
# TBC in VDM - Keep ASN.1 Value Notation
BitStringLiteral = ('"' + Word("01") + '"B').setResultsName('BITSTRING')
# TBC in VDM - Keep ASN.1 Value Notation
OctetStringLiteral=('"' + Word(string.hexdigits) + '"H').setResultsName('OCTETSTRING')
# QuotedString's first parameter = quote type..+multiline to support \n => OK
# Support embedded quotes as per GSER standard (""embedded quoted text"")
StringLiteral = QuotedString('"', escQuote='""', multiline=True,).setResultsName('QUOTEDSTRING')
# QuotedString's first parameter = quote type..+multiline to support \n
# Support embedded quotes (""embedded quoted text"")
STRINGLITERAL = QuotedString('"', escQuote='""', multiline=True,)
TRUE = Literal("true").setResultsName('TRUE')
FALSE = Literal("false").setResultsName('FALSE')
NULL = Literal("nil")
# TBC in VDM
NULL = Literal("NULL").setResultsName('NULL')
COMMA = Literal(',').suppress()
# TBC in VDM
PLUS_INFINITY = Literal("PLUS-INFINITY").setResultsName('PLUS-INFINITY')
MINUS_INFINITY = Literal("MINUS-INFINITY").setResultsName('MINUS-INFINITY')
# EMPTY_LIST:
LBRACKET = Literal('{').suppress()
RBRACKET = Literal('}').suppress()
# Square brackets
LSBRACKET = Literal('[').suppress()
RSBRACKET = Literal(']').suppress()
# Parenthesis
LPAREN = Literal('(').suppress()
RPAREN = Literal(')').suppress()
# INTEGER
INT = Combine(Optional(oneOf("+ -")) + (Word(srange("[1-9]"), nums)|Literal('0'))).setResultsName('INTEGER')
LT = Literal('<').suppress()
GT = Literal('>').suppress()
# This one is correct:
# a lowercase followed by a-zA-z and -
#LID = Word(string.lowercase, string.letters+string.digits+'-')
# Update MP 21/11/12: made it tolerant to uppercase for the first character
LID = Word(string.letters, string.letters+string.digits+'-')
identifier = LID.setResultsName('IDENTIFIER')
INT = Combine(Optional(oneOf("+ -"))
+ (Word(srange("[1-9]"), nums)|Literal('0'))).setResultsName('INTEGER')
# Value reference is in practice used to identify enumerated values
valuereference = LID.setResultsName('VALUE_REF')
LID = Word(string.lowercase, string.letters+string.digits+'_')
ID = Word(string.letters+string.digits+'_')
MKPREFIX = Literal("mk_").suppress()
# FloatingPointLiteral
DOT = Literal('.')
DOUBLE_DOT = Literal('..')
# Exponent (e.g. e+10)
Exponent = oneOf("e E") + Optional(oneOf("+ -")) + OneOrMore(Word(nums))
# Thefirst (INT + DOUBLE_DOT) is unclear (e.g. "5..").
FloatingPointLiteral = (INT + DOUBLE_DOT
| Combine(INT + DOT + Optional(Word(nums)) + Optional(Exponent))
FloatingPointLiteral = (Combine(INT + Optional(DOT) + Optional(Word(nums))
+ Optional(Exponent))
| INT).setResultsName('REAL1')
# Numeric value2 (eg. { mantissa 3, base 4, exponent 5 })
# Does this noataion exist in VDM ?
MANTISSA = Literal('mantissa').suppress()
BASE = Literal('base').suppress()
EXPONENT = Literal('exponent').suppress()
NUMERIC_VALUE2 = (nestedExpr('{', '}', MANTISSA + INT + COMMA + BASE + INT + COMMA + EXPONENT + INT)).setResultsName('REAL2')
# Forward allows to use recursive constructs
NAMED_VALUE_LIST = Forward()
SEQUENCE = Forward()
SETOF = Forward()
VALUE_LIST = Forward()
choiceValue = Forward()
ENUM = Forward()
SEQOF = Forward()
# Support for "Any" value (using a star)
AnyValueLiteral = Keyword('*').setResultsName('ANY')
# ASN.1 Value Notation: only missing construct are OID references
# Ambiguity: FloatingPointLiteral contains INT -> INT will never be parsed as REAL
value = (BitStringLiteral
| OctetStringLiteral
| TRUE
value = ( TRUE
| FALSE
| StringLiteral
| NULL
| PLUS_INFINITY
| MINUS_INFINITY
| NAMED_VALUE_LIST
| VALUE_LIST
| STRINGLITERAL
| SEQUENCE
| SEQOF
| SETOF
| (valuereference ^ choiceValue)
| ENUM
| (INT ^ FloatingPointLiteral)
| NUMERIC_VALUE2
| AnyValueLiteral)
# ASN.1 CHOICE --> TBC in VDM
choiceValue << (identifier + ':' + value).setResultsName('CHOICE')
# SEQUENCE
NAMED_VALUE_LIST << LPAREN + delimitedList(value) + RPAREN
)
# VDM SEQUENCE OF
VALUE_LIST << LSBRACKET + Optional(delimitedList(value)) + RSBRACKET
# SET OF
SEQUENCE << MKPREFIX + Optional(ID.suppress()) \
+ LPAREN + delimitedList(value) + RPAREN
SEQOF << LSBRACKET + Optional(delimitedList(value)) + RSBRACKET
SETOF << LBRACKET + Optional(delimitedList(value)) + RBRACKET
ENUM << LT + ID + GT
# Parse actions allow to modify the AST to be compliant with the ASN.1 Editor input
NAMED_VALUE_LIST.setParseAction(lambda s, l, t: [t.asList()])
VALUE_LIST.setParseAction(lambda s, l, t: [t.asList()])
# Parse actions allow to transform the AST on the fly
SEQUENCE.setParseAction(lambda s, l, t: [t.asList()])
SEQOF.setParseAction(lambda s, l, t: [t.asList()])
SETOF.setParseAction(lambda s, l, t: [t.asList()])
choiceValue.setParseAction(lambda s, l, t: {'Choice': t[0].replace('-', '_'), t[0].replace('-', '_'): t[2]})
valuereference.setParseAction(lambda s, l, t: {'Enum': t[0].replace('-', '_')})
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]))
TRUE.setParseAction(lambda s, l, t: True)
FALSE.setParseAction(lambda s, l, t: False)
AnyValueLiteral.setParseAction(lambda s, l, t: {'Any': t[0]})
OctetStringLiteral.setParseAction(lambda s, l, t: ''.join([chr(int(t[1][i:i+2], 16)) for i in range(0, len(t[1]), 2)]))
# BitString Warning: will only work with series of 8 bits
BitStringLiteral.setParseAction(lambda s, l, t: ''.join([chr(int(t[1][i:i+9], 2)) for i in range(0, len(t[1]), 2)]))
NULL.setParseAction(lambda s, l, t: "NULL")
def parse_vdm(varName='vdm', string=''):
''' Return a variable compatible with the ASN.1 Editor from a VDM string'''
try:
return {varName: value.parseString(string, True)[0]}
except ParseException as err:
print '[parse_vdm] Parsing error:', string
raise
print '[parse_vdm] Parsing error:', string, str(err)
def toASN1ValueNotation(val):
''' Create a GSER reprentation of the Python variable '''
result = ''
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 += val['Choice'].replace('_', '-').strip() + ':'
result += toASN1ValueNotation(val[val['Choice']])
result = pyside_to_vdm(val[val['Choice']])
elif 'Enum' in val:
result += unicode(val['Enum']).replace('_', '-').strip()
else: # SEQUENCE and SET
result += ' { '
needsComa = False
for seqElem in val:
if needsComa:
result += ', '
result += seqElem.replace('_', '-').strip() + ' '
result += toASN1ValueNotation(val[seqElem])
needsComa = True
result += ' }'
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
result += ' { '
needsComa = False
for seqOfElem in val:
if needsComa:
result += ', '
result += toASN1ValueNotation(seqOfElem)
needsComa = True
result += ' }'
# 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
elif isinstance(val, bool):
# boolean are in upper case in ASN.1
result += str(val).upper()
# boolean are in lower case in VDM
result = str(val).lower()
elif isinstance(val, basestring):
# Strings: add quotes, and if string contain non-displayable chars, use repr() to get a visible string
# Strings: add quotes
if all(c in string.printable for c in val):
result = '"' + val + '"'
result = '"{}"'.format(val)
else:
result = '"'
for c in val:
result += '%02x' % ord(c)
result += '"H'
result = "ERROR! String with invalid characters"
else:
result = str(val) # INTEGER and REAL
return result
def valueNotationToSwig(gser, dest, sort, ASN1Swig, ASN1_AST, var=None):
''' Parse a GSER value and fill a SWIG variable with it
def vdm_to_swig(gser, dest, sort, ASN1Swig, ASN1_AST, var=None):
''' Parse a VDM value and fill a SWIG variable with it
Inputs:
gser : input GSER string
dest : output SWIG instance to be filled
......
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