1 # Copyright (c) 2013, Schneider Electric Buildings AB
4 # Redistribution and use in source and binary forms, with or without
5 # modification, are permitted provided that the following conditions are met:
6 # * Redistributions of source code must retain the above copyright
7 # notice, this list of conditions and the following disclaimer.
8 # * Redistributions in binary form must reproduce the above copyright
9 # notice, this list of conditions and the following disclaimer in the
10 # documentation and/or other materials provided with the distribution.
11 # * Neither the name of Schneider Electric Buildings AB nor the
12 # names of contributors may be used to endorse or promote products
13 # derived from this software without specific prior written permission.
15 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
16 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
19 # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20 # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22 # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24 # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 from asn1ate import parser
29 def build_semantic_model(parse_result):
30 """ Build a semantic model of the ASN.1 definition
31 from a syntax tree generated by asn1ate.parser.
34 for token in parse_result:
35 _assert_annotated_token(token)
36 root.append(_create_sema_node(token))
41 def topological_sort(assignments):
42 """ Algorithm adapted from:
43 http://en.wikipedia.org/wiki/Topological_sorting.
45 Assumes assignments is an iterable of items with two methods:
46 - reference_name() -- returns the reference name of the assignment
47 - references() -- returns an iterable of reference names
48 upon which the assignment depends.
50 graph = dict((a.reference_name(), set(a.references())) for a in assignments)
52 def has_predecessor(node):
53 for predecessor in graph.keys():
54 if node in graph[predecessor]:
59 # Build a topological order of reference names
60 topological_order = []
61 roots = [name for name in graph.keys() if not has_predecessor(name)]
66 # Remove the current node from the graph
67 # and collect all new roots (the nodes that
68 # were previously only referenced from n)
69 successors = graph.pop(root, set())
70 roots.extend(successor for successor in successors if not has_predecessor(successor))
72 topological_order.insert(0, root)
75 raise Exception('Can\'t sort cyclic references: %s' % graph)
77 # Sort the actual assignments based on the topological order
78 return sorted(assignments, key=lambda a: topological_order.index(a.reference_name()))
81 # Registered object identifier names
82 REGISTERED_OID_NAMES = {
90 'network-operator': 3,
93 'registration-authority': 1,
95 'identified-organization': 3,
98 'registration-procedures': 17
104 Concepts in the ASN.1 specification are mirrored here as a simple object model.
106 Class and member names typically follow the ASN.1 terminology, but there are
107 some concepts captured which are not expressed in the spec.
109 Most notably, we build a dependency graph of all types and values in a module,
110 to allow code generators to build code in dependency order.
112 All nodes that may be referenced (type and value assignments) must have a
113 method called ``reference_name``.
115 All nodes that may reference other types (e.g. assignments, component types)
116 must have a method called ``references`` returning the names of all referenced
119 Typically, if you have a ``reference_name``, you must also have a ``references``,
120 but not the other way around.
123 class SemaNode(object):
125 raise NotImplementedError()
128 class Module(object):
129 def __init__(self, elements):
130 self._user_types = {}
132 module_reference, _, _, _, _, module_body, _ = elements
133 self.name = module_reference.elements[0]
135 if module_body.elements:
136 _, assignments = module_body.elements
137 self.assignments = [_create_sema_node(token) for token in assignments.elements]
139 self.assignments = []
141 def user_types(self):
142 if not self._user_types:
143 # Index all type assignments by name
144 type_assignments = [a for a in self.assignments if isinstance(a, TypeAssignment)]
145 for user_defined in type_assignments:
146 self._user_types[user_defined.type_name] = user_defined.type_decl
148 return self._user_types
150 def resolve_type_decl(self, type_decl):
151 """ Recursively resolve user-defined types to their
152 built-in declaration.
154 user_types = self.user_types()
156 if isinstance(type_decl, UserDefinedType):
157 return self.resolve_type_decl(user_types[type_decl.type_name])
163 return '%s DEFINITIONS ::=\n' % self.name \
165 + '\n'.join(map(str, self.assignments)) + '\n' \
171 class TypeAssignment(object):
172 def __init__(self, elements):
173 assert(len(elements) == 3)
174 type_name, _, type_decl = elements
175 self.type_name = type_name
176 self.type_decl = _create_sema_node(type_decl)
178 def reference_name(self):
179 return self.type_name
181 def references(self):
182 refs = self.type_decl.references()
184 # Remove any self-references
185 refs = [ref for ref in refs if ref != self.type_name]
190 return '%s ::= %s' % (self.type_name, self.type_decl)
195 class ValueAssignment(object):
196 def __init__(self, elements):
197 value_name, type_name, _, value = elements
198 self.value_name = ValueReference(value_name.elements) # First token is always a valuereference
199 self.type_decl = _create_sema_node(type_name)
201 if isinstance(value, parser.AnnotatedToken):
202 self.value = _create_sema_node(value)
206 def reference_name(self):
207 return self.value_name.reference_name()
209 def references(self):
210 refs = [self.type_decl.reference_name()]
211 if isinstance(self.value, ValueReference):
212 refs.append(self.value.reference_name())
213 elif isinstance(self.value, ObjectIdentifierValue):
214 refs.extend(self.value.references())
216 # It's a literal, and they don't play into declaration order.
219 # Remove any self-references
220 refs = [ref for ref in refs if ref != self.value_name]
225 return '%s %s ::= %s' % (self.value_name, self.type_decl, self.value)
230 class ValueReference(object):
231 def __init__(self, elements):
232 self.name = elements[0]
234 def reference_name(self):
237 def references(self):
246 class ConstructedType(object):
247 """ Base type for SEQUENCE, SET and CHOICE. """
248 def __init__(self, elements):
249 type_name, component_tokens = elements
250 self.type_name = type_name
251 self.components = [_create_sema_node(token) for token in component_tokens]
253 def references(self):
255 for component in self.components:
256 references.extend(component.references())
260 component_type_list = ', '.join(map(str, self.components))
261 return '%s { %s }' % (self.type_name, component_type_list)
266 class ChoiceType(ConstructedType):
267 def __init__(self, elements):
268 super(ChoiceType, self).__init__(elements)
271 class SequenceType(ConstructedType):
272 def __init__(self, elements):
273 super(SequenceType, self).__init__(elements)
276 class SetType(ConstructedType):
277 def __init__(self, elements):
278 super(SetType, self).__init__(elements)
281 class CollectionType(object):
282 """ Base type for SET OF and SEQUENCE OF. """
283 def __init__(self, kind, elements):
285 self.type_name = self.kind + ' OF'
287 if elements[0].ty == 'Type':
288 self.size_constraint = None
289 self.type_decl = _create_sema_node(elements[0])
290 elif elements[0].ty == 'SizeConstraint':
291 self.size_constraint = _create_sema_node(elements[0])
292 self.type_decl = _create_sema_node(elements[1])
294 assert False, 'Unknown form of %s OF declaration: %s' % (self.kind, elements)
296 def references(self):
297 return self.type_decl.references()
300 if self.size_constraint:
301 return '%s %s OF %s' % (self.kind, self.size_constraint, self.type_decl)
303 return '%s OF %s' % (self.kind, self.type_decl)
308 class SequenceOfType(CollectionType):
309 def __init__(self, elements):
310 super(SequenceOfType, self).__init__('SEQUENCE', elements)
313 class SetOfType(CollectionType):
314 def __init__(self, elements):
315 super(SetOfType, self).__init__('SET', elements)
318 class TaggedType(object):
319 def __init__(self, elements):
320 self.class_name = None
321 self.class_number = None
322 self.implicit = False
324 tag_token = elements[0]
325 if type(elements[1]) is parser.AnnotatedToken:
326 type_token = elements[1]
328 self.implicit = elements[1] == 'IMPLICIT'
329 type_token = elements[2]
331 for tag_element in tag_token.elements:
332 if tag_element.ty == 'TagClassNumber':
333 self.class_number = tag_element.elements[0]
334 elif tag_element.ty == 'TagClass':
335 self.class_name = tag_element.elements[0]
337 assert False, 'Unknown tag element: %s' % tag_element
339 self.type_decl = _create_sema_node(type_token)
343 return self.type_decl.type_name
345 def reference_name(self):
346 return self.type_decl.type_name
348 def references(self):
349 return self.type_decl.references()
354 class_spec.append(self.class_name)
355 class_spec.append(self.class_number)
357 result = '[%s] ' % ' '.join(class_spec)
359 result += 'IMPLICIT '
361 result += str(self.type_decl)
368 class SimpleType(object):
369 def __init__(self, elements):
370 self.constraint = None
371 self.type_name = elements[0]
372 if len(elements) > 1 and elements[1].ty == 'Constraint':
373 self.constraint = Constraint(elements[1].elements)
375 def reference_name(self):
376 return self.type_name
378 def references(self):
379 refs = [self.type_name]
381 refs.extend(self.constraint.references())
386 if self.constraint is None:
387 return self.type_name
389 return '%s %s' % (self.type_name, self.constraint)
394 class UserDefinedType(object):
395 def __init__(self, elements):
396 self.type_name = elements[0]
398 def references(self):
399 return [self.type_name]
402 return self.type_name
407 class Constraint(object):
408 def __init__(self, elements):
409 min_value, max_value = elements
411 self.min_value = _maybe_create_sema_node(min_value)
412 self.max_value = _maybe_create_sema_node(max_value)
414 def references(self):
416 if isinstance(self.min_value, ValueReference):
417 refs.append(self.min_value.reference_name())
419 if isinstance(self.max_value, ValueReference):
420 refs.append(self.max_value.reference_name())
425 return '(%s..%s)' % (self.min_value, self.max_value)
430 class SizeConstraint(Constraint):
431 """ Size constraints have the same form as any value range constraints."""
433 return 'SIZE(%s..%s)' % (self.min_value, self.max_value)
438 class ComponentType(object):
439 def __init__(self, elements):
440 self.identifier = None
441 self.type_decl = None
442 self.default_value = None
443 self.optional = False
444 self.components_of_type = None
446 def crack_named_type(token):
447 named_type = NamedType(token)
448 self.identifier = named_type.identifier
449 self.type_decl = named_type.type_decl
451 first_token = elements[0]
452 if first_token.ty == 'NamedType':
453 crack_named_type(first_token.elements)
454 elif first_token.ty == 'ComponentTypeOptional':
455 crack_named_type(first_token.elements[0].elements)
457 elif first_token.ty == 'ComponentTypeDefault':
458 crack_named_type(first_token.elements[0].elements)
459 self.default_value = _maybe_create_sema_node(first_token.elements[1])
460 elif first_token.ty == 'ComponentTypeComponentsOf':
461 self.components_of_type = _create_sema_node(first_token.elements[0])
463 assert False, 'Unknown component type %s' % first_token
465 def references(self):
466 if self.components_of_type:
467 return [self.components_of_type.type_name]
469 refs = [self.type_decl.type_name]
470 refs.extend(self.type_decl.references())
472 if self.default_value is not None:
473 refs.append(str(self.default_value))
478 if self.components_of_type:
479 return 'COMPONENTS OF %s' % self.components_of_type
481 result = '%s %s' % (self.identifier, self.type_decl)
483 result += ' OPTIONAL'
484 elif self.default_value is not None:
485 result += ' DEFAULT %s' % self.default_value
492 class NamedType(object):
493 def __init__(self, elements):
494 first_token = elements[0]
495 if first_token.ty == 'Type':
496 # EXT: unnamed member
497 type_token = first_token
498 self.identifier = _get_next_unnamed()
499 elif first_token.ty == 'Identifier':
501 self.identifier = first_token.elements[0]
502 type_token = elements[1]
504 self.type_decl = _create_sema_node(type_token)
506 def references(self):
507 return self.type_decl.references()
510 return '%s %s' % (self.identifier, self.type_decl)
515 class ValueListType(object):
516 def __init__(self, elements):
517 self.type_name = elements[0]
518 if len(elements) > 1:
519 self.named_values = [_create_sema_node(token) for token in elements[1]]
521 self.named_values = None
523 def references(self):
524 # TODO: Value references
528 if self.named_values:
529 named_value_list = ', '.join(map(str, self.named_values))
530 return '%s { %s }' % (self.type_name, named_value_list)
532 return '%s' % self.type_name
537 class BitStringType(object):
538 def __init__(self, elements):
539 self.type_name = elements[0]
540 if len(elements) > 1:
541 self.named_bits = [_create_sema_node(token) for token in elements[1]]
543 self.named_bits = None
545 def references(self):
546 # TODO: Value references
551 named_bit_list = ', '.join(map(str, self.named_bits))
552 return '%s { %s }' % (self.type_name, named_bit_list)
554 return '%s' % self.type_name
559 class NamedValue(object):
560 def __init__(self, elements):
561 identifier_token, value_token = elements
562 self.identifier = identifier_token.elements[0]
563 self.value = value_token.elements[0]
565 def references(self):
566 # TODO: This appears to never be called. Investigate.
570 return '%s (%s)' % (self.identifier, self.value)
575 class ExtensionMarker(object):
576 def __init__(self, elements):
579 def references(self):
580 # TODO: This appears to never be called. Investigate.
589 class NameForm(object):
590 def __init__(self, elements):
591 self.name = elements[0]
593 def references(self):
602 class NumberForm(object):
603 def __init__(self, elements):
604 self.value = elements[0]
606 def references(self):
610 return str(self.value)
615 class NameAndNumberForm(object):
616 def __init__(self, elements):
617 # The first element is a NameForm containing only the
618 # name, so unpack it into a string.
619 self.name = elements[0].elements[0]
620 self.number = _create_sema_node(elements[1])
622 def references(self):
623 return [str(self.name), str(self.number)]
626 return '%s(%s)' % (self.name, self.number)
631 class ObjectIdentifierValue(object):
632 def __init__(self, elements):
633 self.components = [_create_sema_node(c) for c in elements]
635 def references(self):
637 for component in self.components:
638 if not isinstance(component, str):
639 refs.extend(component.references())
641 refs.append(component)
646 return '{' + ' '.join(str(x) for x in self.components) + '}'
651 def _maybe_create_sema_node(token):
652 if isinstance(token, parser.AnnotatedToken):
653 return _create_sema_node(token)
658 def _create_sema_node(token):
659 _assert_annotated_token(token)
661 if token.ty == 'ModuleDefinition':
662 return Module(token.elements)
663 elif token.ty == 'TypeAssignment':
664 return TypeAssignment(token.elements)
665 elif token.ty == 'ValueAssignment':
666 return ValueAssignment(token.elements)
667 elif token.ty == 'ValueReference':
668 return ValueReference(token.elements)
669 elif token.ty == 'ComponentType':
670 return ComponentType(token.elements)
671 elif token.ty == 'NamedType':
672 return NamedType(token.elements)
673 elif token.ty == 'ValueListType':
674 return ValueListType(token.elements)
675 elif token.ty == 'BitStringType':
676 return BitStringType(token.elements)
677 elif token.ty == 'NamedValue':
678 return NamedValue(token.elements)
679 elif token.ty == 'Type':
680 # Type tokens have a more specific type category
681 # embedded as their first element
682 return _create_sema_node(token.elements[0])
683 elif token.ty == 'SimpleType':
684 return SimpleType(token.elements)
685 elif token.ty == 'ReferencedType':
686 return UserDefinedType(token.elements)
687 elif token.ty == 'TaggedType':
688 return TaggedType(token.elements)
689 elif token.ty == 'SequenceType':
690 return SequenceType(token.elements)
691 elif token.ty == 'ChoiceType':
692 return ChoiceType(token.elements)
693 elif token.ty == 'SetType':
694 return SetType(token.elements)
695 elif token.ty == 'SequenceOfType':
696 return SequenceOfType(token.elements)
697 elif token.ty == 'SetOfType':
698 return SetOfType(token.elements)
699 elif token.ty == 'ExtensionMarker':
700 return ExtensionMarker(token.elements)
701 elif token.ty == 'SizeConstraint':
702 return SizeConstraint(token.elements)
703 elif token.ty == 'ObjectIdentifierValue':
704 return ObjectIdentifierValue(token.elements)
705 elif token.ty == 'NameForm':
706 return NameForm(token.elements)
707 elif token.ty == 'NumberForm':
708 return NumberForm(token.elements)
709 elif token.ty == 'NameAndNumberForm':
710 return NameAndNumberForm(token.elements)
712 raise Exception('Unknown token type: %s' % token.ty)
715 def _assert_annotated_token(obj):
716 assert(type(obj) is parser.AnnotatedToken)
719 # HACK: Generate unique names for unnamed members
721 def _get_next_unnamed():
722 global _unnamed_counter
723 _unnamed_counter += 1
724 return 'unnamed%d' % _unnamed_counter