Merge pull request #29 from james-ward/sema-autotag
authorKim Gräsman <kim.grasman@gmail.com>
Tue, 22 Dec 2015 09:11:56 +0000 (10:11 +0100)
committerKim Gräsman <kim.grasman@gmail.com>
Tue, 22 Dec 2015 09:11:56 +0000 (10:11 +0100)
Add support for AUTOMATIC TAGS.

Patch by James Ward, thanks!

asn1ate/sema.py
testdata/module_tag_default.asn

index cd4015b..4fc222d 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
 
 
@@ -390,6 +399,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)
@@ -441,17 +461,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
@@ -460,8 +485,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
+