First stab at codegen of OBJECT IDENTIFIER values.
authorKim Grasman <kim.grasman@gmail.com>
Mon, 5 Aug 2013 07:48:17 +0000 (09:48 +0200)
committerKim Grasman <kim.grasman@gmail.com>
Mon, 5 Aug 2013 07:48:17 +0000 (09:48 +0200)
Improved grammar.
Better sema representation of OID values.

asn1ate/parser.py
asn1ate/pyasn1gen.py
asn1ate/sema.py
testdata/object_identifier.asn

index b9c99cb..d36a340 100644 (file)
@@ -180,7 +180,7 @@ def _build_asn1_grammar():
 
     # object identifier value
     name_form = Unique(identifier)
-    number_form = number | defined_value
+    number_form = Unique(number)
     name_and_number_form = name_form + Suppress('(') + number_form + Suppress(')')
     objid_components = name_and_number_form | name_form | number_form | defined_value
     objid_components_list = OneOrMore(objid_components)
@@ -312,6 +312,7 @@ def _build_asn1_grammar():
     module_definition.setParseAction(annotate('ModuleDefinition'))
     extension_marker.setParseAction(annotate('ExtensionMarker'))
     name_form.setParseAction(annotate('NameForm'))
+    number_form.setParseAction(annotate('NumberForm'))
     name_and_number_form.setParseAction(annotate('NameAndNumberForm'))
     object_identifier_value.setParseAction(annotate('ObjectIdentifierValue'))
 
index b370c83..b6d3738 100644 (file)
@@ -85,7 +85,8 @@ class Pyasn1Backend(object):
             ValueListType: self.expr_value_list_type,
             ChoiceType: self.expr_constructed_type,
             SequenceType: self.expr_constructed_type,
-            SetType: self.expr_constructed_type
+            SetType: self.expr_constructed_type,
+            ObjectIdentifierValue: self.expr_object_identifier_value
         }
 
     def generate_code(self):
@@ -287,9 +288,31 @@ class Pyasn1Backend(object):
     def decl_value_assignment(self, assignment):
         assigned_value, type_decl, value = assignment.value_name, assignment.type_decl, assignment.value
 
+        if isinstance(value, ObjectIdentifierValue):
+            value = self.expr_object_identifier_value(value)
+
         value_type = _translate_type(type_decl.type_name)
         return '%s = %s(%s)' % (assigned_value, value_type, value)
 
+    def expr_object_identifier_value(self, t):
+        normalized_components = []
+
+        for c in t.components:
+            if isinstance(c, NameForm):
+                if c.name in REGISTERED_OID_NAMES:
+                    normalized_components.append('univ.ObjectIdentifier((%s,))' % REGISTERED_OID_NAMES[c.name])
+                else:
+                    # TODO: handle defined values
+                    normalized_components.append('univ.ObjectIdentifier((%s,))' % c.name)
+            elif isinstance(c, NumberForm):
+                normalized_components.append('univ.ObjectIdentifier((%s,))' % c.value)
+            elif isinstance(c, NameAndNumberForm):
+                normalized_components.append('univ.ObjectIdentifier((%s,))' % c.number.value)
+            else:
+                assert False
+
+        return ' + '.join(normalized_components)
+
 
 def generate_pyasn1(sema_module, out_stream):
     return Pyasn1Backend(sema_module, out_stream).generate_code()
index 19dc5fd..b7eda08 100644 (file)
@@ -78,6 +78,26 @@ def topological_sort(assignments):
     return sorted(assignments, key=lambda a: topological_order.index(a.reference_name()))
 
 
+# Registered object identifier names
+REGISTERED_OID_NAMES = {
+    'ccitt': 0,
+    'iso': 1,
+    'joint-iso-ccitt': 2,
+    # ccitt
+    'recommendation': 0,
+    'question': 1,
+    'administration': 2,
+    'network-operator': 3,
+    # iso
+    'standard': 0,
+    'registration-authority': 1,
+    'member-body': 2,
+    'identified-organization': 3,
+    # joint-iso-ccitt
+    'country': 16,
+    'registration-procedures': 17
+}
+
 """
 Sema nodes
 
@@ -182,6 +202,8 @@ class ValueAssignment(object):
         refs = [self.type_decl.reference_name()]
         if isinstance(self.value, ValueReference):
             refs.append(self.value.reference_name())
+        elif isinstance(self.value, ObjectIdentifierValue):
+            refs.extend(self.value.references())
         else:
             # It's a literal, and they don't play into declaration order.
             pass
@@ -569,12 +591,25 @@ class NameForm(object):
     __repr__ = __str__
 
 
+class NumberForm(object):
+    def __init__(self, elements):
+        self.value = elements[0]
+
+    def references(self):
+        return []
+
+    def __str__(self):
+        return str(self.value)
+
+    __repr__ = __str__
+
+
 class NameAndNumberForm(object):
     def __init__(self, elements):
         # The first element is a NameForm containing only the
         # name, so unpack it into a string.
         self.name = elements[0].elements[0]
-        self.number = _maybe_create_sema_node(elements[1])
+        self.number = _create_sema_node(elements[1])
 
     def references(self):
         return [str(self.name), str(self.number)]
@@ -587,15 +622,17 @@ class NameAndNumberForm(object):
 
 class ObjectIdentifierValue(object):
     def __init__(self, elements):
-        self.components = [_maybe_create_sema_node(c) for c in elements]
+        self.components = [_create_sema_node(c) for c in elements]
 
     def references(self):
-        references = []
+        refs = []
         for component in self.components:
             if not isinstance(component, str):
-                references.extend(component.references())
+                refs.extend(component.references())
+            else:
+                refs.append(component)
 
-        return references
+        return refs
 
     def __str__(self):
         return '{' + ' '.join(str(x) for x in self.components) + '}'
@@ -659,6 +696,8 @@ def _create_sema_node(token):
         return ObjectIdentifierValue(token.elements)
     elif token.ty == 'NameForm':
         return NameForm(token.elements)
+    elif token.ty == 'NumberForm':
+        return NumberForm(token.elements)
     elif token.ty == 'NameAndNumberForm':
         return NameAndNumberForm(token.elements)
 
index f82d21c..8f56ad5 100644 (file)
@@ -20,7 +20,7 @@ BEGIN
   -- Value assignment, name form
   -- First three parts are known names, the last one a defined value.
   local INTEGER ::= 1234
-  v3 OBJECT IDENTIFIER ::= {iso member-body us local}
+  v3 OBJECT IDENTIFIER ::= {iso member-body us(840) local}
 
   -- Value assignment, mixed
   v4 OBJECT IDENTIFIER ::= {v1 723 local}