Support for selection types.
authorKim Grasman <kim.grasman@gmail.com>
Sun, 27 Jul 2014 12:32:21 +0000 (14:32 +0200)
committerKim Grasman <kim.grasman@gmail.com>
Sun, 27 Jul 2014 12:32:21 +0000 (14:32 +0200)
asn1ate/parser.py
asn1ate/pyasn1gen.py
asn1ate/sema.py
testdata/builtin_types.asn

index f58f85c..33ea93f 100644 (file)
@@ -227,7 +227,6 @@ def _build_asn1_grammar():
     # todo: consider other defined types from 13.1
     external_type_reference = module_reference + Suppress('.') + typereference
     defined_type = external_type_reference | typereference
-    referenced_type = Unique(defined_type)  # todo: consider other ref:d types from 16.3
 
     # values
 
@@ -265,6 +264,7 @@ def _build_asn1_grammar():
     sequenceof_type = Suppress(SEQUENCE) + Optional(size_constraint, default=None) + Suppress(OF) + (type_ | named_type)
     setof_type = Suppress(SET) + Optional(size_constraint, default=None) + Suppress(OF) + (type_ | named_type)
     choice_type = CHOICE + braced_list(named_type | extension_marker)
+    selection_type = identifier + Suppress('<') + type_
     enumerated_type = ENUMERATED + braced_list(enumeration | extension_marker)
     bitstring_type = BIT_STRING + Optional(braced_list(named_number), default=[]) + Optional(single_value_constraint | size_constraint, default=None)
     plain_integer_type = INTEGER
@@ -291,6 +291,8 @@ def _build_asn1_grammar():
     value_list_type = restricted_integer_type | enumerated_type
     builtin_type = value_list_type | tagged_type | simple_type | constructed_type | sequenceof_type | setof_type | bitstring_type
 
+    referenced_type = defined_type | selection_type  # todo: consider other ref:d types from 16.3
+
     type_ << (builtin_type | referenced_type)
 
     # EXT: identifier should not be Optional here, but
@@ -366,7 +368,8 @@ def _build_asn1_grammar():
     assignment_list.setParseAction(annotate('AssignmentList'))
     bstring.setParseAction(annotate('BinaryStringValue'))
     hstring.setParseAction(annotate('HexStringValue'))
-    referenced_type.setParseAction(annotate('ReferencedType'))
+    defined_type.setParseAction(annotate('DefinedType'))
+    selection_type.setParseAction(annotate('SelectionType'))
     referenced_value.setParseAction(annotate('ReferencedValue'))
 
     start = OneOrMore(module_definition)
index 5c72331..24dc2e4 100644 (file)
@@ -96,16 +96,18 @@ class Pyasn1Backend(object):
             SequenceOfType: self.defn_collection_type,
             SetOfType: self.defn_collection_type,
             TaggedType: self.defn_tagged_type,
+            SelectionType: self.defn_selection_type,
             SimpleType: self.defn_simple_type,
-            ReferencedType: self.defn_referenced_type,
+            DefinedType: self.defn_defined_type,
             ValueListType: self.defn_value_list_type,
             BitStringType: self.defn_bitstring_type,
         }
 
         self.inline_generators = {
             TaggedType: self.inline_tagged_type,
+            SelectionType: self.inline_selection_type,
             SimpleType: self.inline_simple_type,
-            ReferencedType: self.inline_referenced_type,
+            DefinedType: self.inline_defined_type,
             ComponentType: self.inline_component_type,
             NamedType: self.inline_named_type,
             SequenceOfType: self.inline_sequenceof_type,
@@ -165,6 +167,9 @@ class Pyasn1Backend(object):
 
         assigned_type, type_decl = assignment.type_name, assignment.type_decl
 
+        if isinstance(type_decl, SelectionType):
+            type_decl = self.sema_module.resolve_selection_type(type_decl)
+
         assigned_type = _translate_type(assigned_type)
         base_type = _translate_type(type_decl.type_name)
         fragment.write_line('class %s(%s):' % (assigned_type, base_type))
@@ -186,7 +191,7 @@ class Pyasn1Backend(object):
 
         return None
 
-    def defn_referenced_type(self, class_name, t):
+    def defn_defined_type(self, class_name, t):
         return None
 
     def defn_constructed_type(self, class_name, t):
@@ -213,6 +218,9 @@ class Pyasn1Backend(object):
 
         return str(fragment)
 
+    def defn_selection_type(self, class_name, t):
+        return None
+
     def defn_value_list_type(self, class_name, t):
         fragment = self.writer.get_fragment()
 
@@ -263,7 +271,7 @@ class Pyasn1Backend(object):
 
         return type_expr
 
-    def inline_referenced_type(self, t):
+    def inline_defined_type(self, t):
         return _translate_type(t.type_name) + '()'
 
     def inline_constructed_type(self, t):
@@ -300,6 +308,12 @@ class Pyasn1Backend(object):
 
         return type_expr
 
+    def inline_selection_type(self, t):
+        selected_type = self.sema_module.resolve_selection_type(t)
+        assert selected_type is not None, "Found no member %s in %s" % (t.identifier, t.type_decl)
+
+        return self.generate_expr(selected_type)
+
     def build_tag_expr(self, tag_def):
         context = _translate_tag_class(tag_def.class_name)
 
index af37982..0800682 100644 (file)
@@ -261,6 +261,19 @@ class Module(SemaNode):
         else:
             return type_decl
 
+    def get_type_decl(self, type_name):
+        user_types = self.user_types()
+        return user_types[type_name]
+
+    def resolve_selection_type(self, selection_type_decl):
+        assert isinstance(selection_type_decl, SelectionType), "Expected SelectionType, was %s" % type(selection_type_decl).__name__
+
+        choice_type = self.get_type_decl(selection_type_decl.type_decl.type_name)
+        for named_type in choice_type.components:
+            if named_type.identifier == selection_type_decl.identifier:
+                return named_type.type_decl
+
+        return None
 
     def __str__(self):
         return '%s DEFINITIONS ::=\n' % self.name \
@@ -433,6 +446,10 @@ class SimpleType(SemaNode):
 
 
 class ReferencedType(SemaNode):
+    pass
+
+
+class DefinedType(ReferencedType):
     def __init__(self, elements):
         # TODO: Module references are not resolved at the moment,
         # and I'm not sure how to handle them.
@@ -452,6 +469,24 @@ class ReferencedType(SemaNode):
     __repr__ = __str__
 
 
+class SelectionType(ReferencedType):
+    def __init__(self, elements):
+        self.identifier = elements[0].elements[0]
+        self.type_decl = _create_sema_node(elements[1])
+
+    @property
+    def type_name(self):
+        return self.type_decl.type_name
+
+    def reference_name(self):
+        return self.type_name
+
+    def __str__(self):
+        return '%s < %s' % (self.identifier, self.type_name)
+
+    __repr__ = __str__
+
+
 class ReferencedValue(SemaNode):
     def __init__(self, elements):
         # TODO: Module references are not resolved at the moment,
@@ -742,8 +777,10 @@ def _create_sema_node(token):
         return _create_sema_node(token.elements[0])
     elif token.ty == 'SimpleType':
         return SimpleType(token.elements)
-    elif token.ty == 'ReferencedType':
-        return ReferencedType(token.elements)
+    elif token.ty == 'DefinedType':
+        return DefinedType(token.elements)
+    elif token.ty == 'SelectionType':
+        return SelectionType(token.elements)
     elif token.ty == 'ReferencedValue':
         return ReferencedValue(token.elements)
     elif token.ty == 'TaggedType':
index 4c6f56c..d6b6d8b 100644 (file)
@@ -43,4 +43,11 @@ BEGIN
   -- Collection types
   SequenceOf ::= SEQUENCE OF INTEGER
   SetOf ::= SET OF INTEGER
+
+  -- Selection type
+  Selection ::= a < Choice
+  SelectedSequence ::= SEQUENCE {
+    a a < Choice,
+    b b < Choice
+  }
 END