Add automatic tags.
authorJames Ward <j.ward@acfr.usyd.edu.au>
Tue, 6 Oct 2015 23:02:09 +0000 (10:02 +1100)
committerJames Ward <j.ward@acfr.usyd.edu.au>
Fri, 9 Oct 2015 02:09:21 +0000 (13:09 +1100)
ConstructedTypes now have a method to autotag their components.
This will wrap all components in a TaggedType with incrementing
tag number, but only if no components are already tagged (as per
the ASN.1 specification).

After generating the module(s) this method is called on all
ConstructedTypes in the tree if the module's tag default is
AUTOMATIC.

Ignore ExtensionMarkers when autotagging.

Resolves #20.

asn1ate/sema.py
testdata/module_tag_default.asn

index 9c7b118..7cdedd1 100644 (file)
@@ -35,6 +35,15 @@ def build_semantic_model(parse_result):
         _assert_annotated_token(token)
         root.append(_create_sema_node(token))
 
+    # Head back through the model to act on any automatic tagging
+    # Objects in root must be Modules by definition of the parser
+    for module in root:
+        if module.tag_default == TagImplicity.AUTOMATIC:
+            # Automatic tagging is on - wrap the members of constructed types
+            for descendant in module.descendants():
+                if isinstance(descendant, ConstructedType):
+                    descendant.auto_tag()
+
     return root
 
 
@@ -376,6 +385,17 @@ class ConstructedType(SemaNode):
         self.type_name = type_name
         self.components = [_create_sema_node(token) for token in component_tokens]
 
+    def auto_tag(self):
+        # Constructed types can have ExtensionMarkers as components - ignore them
+        component_types = [c.type_decl for c in self.components if hasattr(c, 'type_decl')]
+        already_tagged = any(isinstance(c, TaggedType) for c in component_types)
+        if not already_tagged:
+            # Wrap components in TaggedTypes
+            for tag_number, child in enumerate([c for c in self.children() if hasattr(c, 'type_decl')]):
+                element = child.type_decl
+                tagged_type = TaggedType((None, tag_number, None, element))
+                child.type_decl = tagged_type
+
     def __str__(self):
         component_type_list = ', '.join(map(str, self.components))
         return '%s { %s }' % (self.type_name, component_type_list)
@@ -427,17 +447,22 @@ class SetOfType(CollectionType):
 
 class TaggedType(SemaNode):
     def __init__(self, elements):
-        tag_token, implicity, type_token = elements
-
         self.class_name = None
         self.class_number = None
-        for tag_element in tag_token.elements:
-            if tag_element.ty == 'TagClassNumber':
-                self.class_number = tag_element.elements[0]
-            elif tag_element.ty == 'TagClass':
-                self.class_name = tag_element.elements[0]
-            else:
-                assert False, 'Unknown tag element: %s' % tag_element
+        if len(elements) == 3:
+            tag_token, implicity, type_token = elements
+            for tag_element in tag_token.elements:
+                if tag_element.ty == 'TagClassNumber':
+                    self.class_number = tag_element.elements[0]
+                elif tag_element.ty == 'TagClass':
+                    self.class_name = tag_element.elements[0]
+                else:
+                    assert False, 'Unknown tag element: %s' % tag_element
+            self.type_decl = _create_sema_node(type_token)
+        elif len(elements) == 4:
+            self.class_name, self.class_number, implicity, self.type_decl = elements
+        else:
+            assert False, 'Incorrect number of elements passed to TaggedType'
 
         if implicity == 'IMPLICIT':
             self.implicity = TagImplicity.IMPLICIT
@@ -446,8 +471,6 @@ class TaggedType(SemaNode):
         elif implicity is None:
             self.implicity = None  # Module-default or automatic
 
-        self.type_decl = _create_sema_node(type_token)
-
     @property
     def type_name(self):
         return self.type_decl.type_name
index 16203d1..55d27be 100644 (file)
@@ -11,6 +11,7 @@ Sequence ::= SEQUENCE
 
 END
 
+-- IMPLICIT TAGS should result in EXPLICIT for CHOICE.
 ImplicitModule DEFINITIONS IMPLICIT TAGS ::=
 BEGIN
 
@@ -19,22 +20,73 @@ Sequence ::= SEQUENCE
     field1 [0] INTEGER,
     field2 [1] BOOLEAN,
     field3 [2] EXPLICIT INTEGER,
-    field4 [3] IMPLICIT BOOLEAN
+    field4 [3] IMPLICIT BOOLEAN,
+    field5 [4] CHOICE { a INTEGER,
+                    b BOOLEAN
+                  }
 }
 
 END
 
+-- AUTOMATIC TAGS should result in implicit tags being added in order.
+AutomaticModule DEFINITIONS AUTOMATIC TAGS ::=
+BEGIN
+
+Sequence ::= SEQUENCE
+{
+    field1 INTEGER,
+    field2 BOOLEAN,
+    field3 INTEGER,
+    field4 BOOLEAN
+}
+
+END
 
--- AUTOMATIC TAGS is considered the same as IMPLICIT for now.
+-- AUTOMATIC TAGS should not be applied if a tag exists.
 AutomaticModule DEFINITIONS AUTOMATIC TAGS ::=
 BEGIN
 
 Sequence ::= SEQUENCE
 {
-    field1 [0] INTEGER,
-    field2 [1] BOOLEAN,
-    field3 [2] EXPLICIT INTEGER,
-    field4 [3] IMPLICIT BOOLEAN
+    field1 INTEGER,
+    field2 BOOLEAN,
+    field3 [2] INTEGER,
+    field4 BOOLEAN
+}
+
+END
+
+-- AUTOMATIC TAGS should nest. CHOICE is tagged EXPLICIT.
+-- Defined types are still EXPLICIT if they are a CHOICE.
+AutomaticModule DEFINITIONS AUTOMATIC TAGS ::=
+BEGIN
+
+Sequence ::= SEQUENCE
+{
+    field1 INTEGER,
+    field2 CHOICE { a INTEGER,
+                    b BOOLEAN
+                  }, 
+    field3 SEQUENCE { x INTEGER,
+                      y BOOLEAN
+                    },
+    field4 SET { p INTEGER,
+                 q BOOLEAN
+               },
+    field5 BOOLEAN
+}
+
+Choice ::= CHOICE
+{
+    field1 INTEGER,
+    field2 BOOLEAN
+}
+
+Sequence2 ::= SEQUENCE {
+    field1 Choice,
+    field2 BOOLEAN,
+    ...
 }
 
 END
+