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()))
84 Concepts in the ASN.1 specification are mirrored here as a simple object model.
86 Class and member names typically follow the ASN.1 terminology, but there are
87 some concepts captured which are not expressed in the spec.
89 Most notably, we build a dependency graph of all types and values in a module,
90 to allow code generators to build code in dependency order.
92 All nodes that may be referenced (type and value assignments) must have a
93 method called ``reference_name``.
95 All nodes that may reference other types (e.g. assignments, component types)
96 must have a method called ``references`` returning the names of all referenced
99 Typically, if you have a ``reference_name``, you must also have a ``references``,
100 but not the other way around.
103 class Module(object):
104 def __init__(self, elements):
105 module_reference, _, _, _, module_body, _ = elements
106 _assert_annotated_token(module_reference)
107 _assert_annotated_token(module_body)
109 self.name = module_reference.elements[0]
110 self.assignments = [_create_sema_node(token) for token in module_body.elements]
111 self._user_types = {}
113 def user_types(self):
114 if not self._user_types:
115 # Index all type assignments by name
116 type_assignments = [a for a in self.assignments if isinstance(a, TypeAssignment)]
117 for user_defined in type_assignments:
118 self._user_types[user_defined.type_name] = user_defined.type_decl
120 return self._user_types
122 def resolve_type_decl(self, type_decl):
123 """ Recursively resolve user-defined types to their
124 built-in declaration.
126 user_types = self.user_types()
128 if isinstance(type_decl, UserDefinedType):
129 return self.resolve_type_decl(user_types[type_decl.type_name])
135 return '%s DEFINITIONS ::=\n' % self.name \
137 + '\n'.join(map(str, self.assignments)) + '\n' \
143 class TypeAssignment(object):
144 def __init__(self, elements):
145 assert(len(elements) == 3)
146 type_name, _, type_decl = elements
147 self.type_name = type_name
148 self.type_decl = _create_sema_node(type_decl)
150 def reference_name(self):
151 return self.type_name
153 def references(self):
154 refs = self.type_decl.references()
156 # Remove any self-references
157 refs = [ref for ref in refs if ref != self.type_name]
162 return '%s ::= %s' % (self.type_name, self.type_decl)
167 class ValueAssignment(object):
168 def __init__(self, elements):
169 value_name, type_name, _, value = elements
170 self.value_name = ValueReference(value_name.elements) # First token is always a valuereference
171 self.type_decl = _create_sema_node(type_name)
173 if isinstance(value, parser.AnnotatedToken):
174 self.value = _create_sema_node(value)
178 def reference_name(self):
179 return self.value_name.reference_name()
181 def references(self):
182 refs = [self.type_decl.reference_name()]
183 if isinstance(self.value, ValueReference):
184 refs.append(self.value.reference_name())
186 # It's a literal, and they don't play into declaration order.
189 # Remove any self-references
190 refs = [ref for ref in refs if ref != self.value_name]
195 return '%s %s ::= %s' % (self.value_name, self.type_decl, self.value)
200 class ValueReference(object):
201 def __init__(self, elements):
202 self.name = elements[0]
204 def reference_name(self):
207 def references(self):
216 class ConstructedType(object):
217 """ Base type for SEQUENCE, SET and CHOICE. """
218 def __init__(self, elements):
219 type_name, component_tokens = elements
220 self.type_name = type_name
221 self.components = [_create_sema_node(token) for token in component_tokens]
223 def references(self):
225 for component in self.components:
226 references.extend(component.references())
230 component_type_list = ', '.join(map(str, self.components))
231 return '%s { %s }' % (self.type_name, component_type_list)
236 class ChoiceType(ConstructedType):
237 def __init__(self, elements):
238 super(ChoiceType, self).__init__(elements)
241 class SequenceType(ConstructedType):
242 def __init__(self, elements):
243 super(SequenceType, self).__init__(elements)
246 class SetType(ConstructedType):
247 def __init__(self, elements):
248 super(SetType, self).__init__(elements)
251 class CollectionType(object):
252 """ Base type for SET OF and SEQUENCE OF. """
253 def __init__(self, kind, elements):
255 self.type_name = self.kind + ' OF'
257 if elements[0].ty == 'Type':
258 self.size_constraint = None
259 self.type_decl = _create_sema_node(elements[0])
260 elif elements[0].ty == 'SizeConstraint':
261 self.size_constraint = _create_sema_node(elements[0])
262 self.type_decl = _create_sema_node(elements[1])
264 assert False, 'Unknown form of %s OF declaration: %s' % (self.kind, elements)
266 def references(self):
267 return self.type_decl.references()
270 if self.size_constraint:
271 return '%s %s OF %s' % (self.kind, self.size_constraint, self.type_decl)
273 return '%s OF %s' % (self.kind, self.type_decl)
278 class SequenceOfType(CollectionType):
279 def __init__(self, elements):
280 super(SequenceOfType, self).__init__('SEQUENCE', elements)
283 class SetOfType(CollectionType):
284 def __init__(self, elements):
285 super(SetOfType, self).__init__('SET', elements)
288 class TaggedType(object):
289 def __init__(self, elements):
290 self.class_name = None
291 self.class_number = None
292 self.implicit = False
294 tag_token = elements[0]
295 if type(elements[1]) is parser.AnnotatedToken:
296 type_token = elements[1]
298 self.implicit = elements[1] == 'IMPLICIT'
299 type_token = elements[2]
301 for tag_element in tag_token.elements:
302 if tag_element.ty == 'TagClassNumber':
303 self.class_number = tag_element.elements[0]
304 elif tag_element.ty == 'TagClass':
305 self.class_name = tag_element.elements[0]
307 assert False, 'Unknown tag element: %s' % tag_element
309 self.type_decl = _create_sema_node(type_token)
313 return self.type_decl.type_name
315 def reference_name(self):
316 return self.type_decl.type_name
318 def references(self):
319 return self.type_decl.references()
324 class_spec.append(self.class_name)
325 class_spec.append(self.class_number)
327 result = '[%s] ' % ' '.join(class_spec)
329 result += 'IMPLICIT '
331 result += str(self.type_decl)
338 class SimpleType(object):
339 def __init__(self, elements):
340 self.constraint = None
341 self.type_name = elements[0]
342 if len(elements) > 1 and elements[1].ty == 'Constraint':
343 self.constraint = Constraint(elements[1].elements)
345 def reference_name(self):
346 return self.type_name
348 def references(self):
349 refs = [self.type_name]
351 refs.extend(self.constraint.references())
356 if self.constraint is None:
357 return self.type_name
359 return '%s %s' % (self.type_name, self.constraint)
364 class UserDefinedType(object):
365 def __init__(self, elements):
366 self.type_name = elements[0]
368 def references(self):
369 return [self.type_name]
372 return self.type_name
377 class Constraint(object):
378 def __init__(self, elements):
379 min_value, max_value = elements
381 self.min_value = _maybe_create_sema_node(min_value)
382 self.max_value = _maybe_create_sema_node(max_value)
384 def references(self):
386 if isinstance(self.min_value, ValueReference):
387 refs.append(self.min_value.reference_name())
389 if isinstance(self.max_value, ValueReference):
390 refs.append(self.max_value.reference_name())
395 return '(%s..%s)' % (self.min_value, self.max_value)
400 class SizeConstraint(Constraint):
401 """ Size constraints have the same form as any value range constraints."""
403 return 'SIZE(%s..%s)' % (self.min_value, self.max_value)
408 class ComponentType(object):
409 def __init__(self, elements):
410 self.identifier = None
411 self.type_decl = None
412 self.default_value = None
413 self.optional = False
414 self.components_of_type = None
416 def crack_named_type(token):
417 named_type = NamedType(token)
418 self.identifier = named_type.identifier
419 self.type_decl = named_type.type_decl
421 first_token = elements[0]
422 if first_token.ty == 'NamedType':
423 crack_named_type(first_token.elements)
424 elif first_token.ty == 'ComponentTypeOptional':
425 crack_named_type(first_token.elements[0].elements)
427 elif first_token.ty == 'ComponentTypeDefault':
428 crack_named_type(first_token.elements[0].elements)
429 self.default_value = _maybe_create_sema_node(first_token.elements[1])
430 elif first_token.ty == 'ComponentTypeComponentsOf':
431 self.components_of_type = _create_sema_node(first_token.elements[0])
433 assert False, 'Unknown component type %s' % first_token
435 def references(self):
436 if self.components_of_type:
437 return [self.components_of_type.type_name]
439 refs = [self.type_decl.type_name]
440 refs.extend(self.type_decl.references())
442 if self.default_value is not None:
443 refs.append(str(self.default_value))
448 if self.components_of_type:
449 return 'COMPONENTS OF %s' % self.components_of_type
451 result = '%s %s' % (self.identifier, self.type_decl)
453 result += ' OPTIONAL'
454 elif self.default_value is not None:
455 result += ' DEFAULT %s' % self.default_value
462 class NamedType(object):
463 def __init__(self, elements):
464 first_token = elements[0]
465 if first_token.ty == 'Type':
466 # EXT: unnamed member
467 type_token = first_token
468 self.identifier = _get_next_unnamed()
469 elif first_token.ty == 'Identifier':
471 self.identifier = first_token.elements[0]
472 type_token = elements[1]
474 self.type_decl = _create_sema_node(type_token)
476 def references(self):
477 return self.type_decl.references()
480 return '%s %s' % (self.identifier, self.type_decl)
485 class ValueListType(object):
486 def __init__(self, elements):
487 self.type_name = elements[0]
488 if len(elements) > 1:
489 self.named_values = [_create_sema_node(token) for token in elements[1]]
491 self.named_values = None
493 def references(self):
494 # TODO: Value references
498 if self.named_values:
499 named_value_list = ', '.join(map(str, self.named_values))
500 return '%s { %s }' % (self.type_name, named_value_list)
502 return '%s' % self.type_name
507 class BitStringType(object):
508 def __init__(self, elements):
509 self.type_name = elements[0]
510 if len(elements) > 1:
511 self.named_bits = [_create_sema_node(token) for token in elements[1]]
513 self.named_bits = None
515 def references(self):
516 # TODO: Value references
521 named_bit_list = ', '.join(map(str, self.named_bits))
522 return '%s { %s }' % (self.type_name, named_bit_list)
524 return '%s' % self.type_name
529 class NamedValue(object):
530 def __init__(self, elements):
531 identifier_token, value_token = elements
532 self.identifier = identifier_token.elements[0]
533 self.value = value_token.elements[0]
535 def references(self):
536 # TODO: This appears to never be called. Investigate.
540 return '%s (%s)' % (self.identifier, self.value)
545 class ExtensionMarker(object):
546 def __init__(self, elements):
549 def references(self):
550 # TODO: This appears to never be called. Investigate.
558 def _maybe_create_sema_node(token):
559 if isinstance(token, parser.AnnotatedToken):
560 return _create_sema_node(token)
565 def _create_sema_node(token):
566 _assert_annotated_token(token)
568 if token.ty == 'ModuleDefinition':
569 return Module(token.elements)
570 elif token.ty == 'TypeAssignment':
571 return TypeAssignment(token.elements)
572 elif token.ty == 'ValueAssignment':
573 return ValueAssignment(token.elements)
574 elif token.ty == 'ValueReference':
575 return ValueReference(token.elements)
576 elif token.ty == 'ComponentType':
577 return ComponentType(token.elements)
578 elif token.ty == 'NamedType':
579 return NamedType(token.elements)
580 elif token.ty == 'ValueListType':
581 return ValueListType(token.elements)
582 elif token.ty == 'BitStringType':
583 return BitStringType(token.elements)
584 elif token.ty == 'NamedValue':
585 return NamedValue(token.elements)
586 elif token.ty == 'Type':
587 # Type tokens have a more specific type category
588 # embedded as their first element
589 return _create_sema_node(token.elements[0])
590 elif token.ty == 'SimpleType':
591 return SimpleType(token.elements)
592 elif token.ty == 'ReferencedType':
593 return UserDefinedType(token.elements)
594 elif token.ty == 'TaggedType':
595 return TaggedType(token.elements)
596 elif token.ty == 'SequenceType':
597 return SequenceType(token.elements)
598 elif token.ty == 'ChoiceType':
599 return ChoiceType(token.elements)
600 elif token.ty == 'SetType':
601 return SetType(token.elements)
602 elif token.ty == 'SequenceOfType':
603 return SequenceOfType(token.elements)
604 elif token.ty == 'SetOfType':
605 return SetOfType(token.elements)
606 elif token.ty == 'ExtensionMarker':
607 return ExtensionMarker(token.elements)
608 elif token.ty == 'SizeConstraint':
609 return SizeConstraint(token.elements)
611 raise Exception('Unknown token type: %s' % token.ty)
614 def _assert_annotated_token(obj):
615 assert(type(obj) is parser.AnnotatedToken)
618 # HACK: Generate unique names for unnamed members
620 def _get_next_unnamed():
621 global _unnamed_counter
622 _unnamed_counter += 1
623 return 'unnamed%d' % _unnamed_counter