Properly module-qualify type references in sema
[third_party/asn1ate.git] / asn1ate / sema.py
1 # Copyright (c) 2013-2017, Schneider Electric Buildings AB
2 # All rights reserved.
3 #
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.
14 #
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.
25
26 from asn1ate import parser
27
28
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.
32     """
33     root = []
34     for token in parse_result:
35         _assert_annotated_token(token)
36         root.append(_create_sema_node(token))
37
38     # Head back through the model to act on any automatic tagging
39     # Objects in root must be Modules by definition of the parser
40     for module in root:
41         if module.tag_default == TagImplicitness.AUTOMATIC:
42             # Automatic tagging is on - wrap the members of constructed types
43             for descendant in module.descendants():
44                 if isinstance(descendant, ConstructedType):
45                     descendant.auto_tag()
46
47     return root
48
49
50 def topological_sort(assignments):
51     """ Algorithm adapted from:
52     http://en.wikipedia.org/wiki/Topological_sorting.
53
54     Use this in code generators to sort assignments in dependency order, IFF
55     there are no circular dependencies.
56
57     Assumes assignments is an iterable of items with two methods:
58     - reference_name() -- returns the reference name of the assignment
59     - references() -- returns an iterable of reference names
60     upon which the assignment depends.
61     """
62     graph = dict((a.reference_name(), a.references()) for a in assignments)
63
64     def has_predecessor(node):
65         for predecessors in graph.values():
66             if node in predecessors:
67                 return True
68
69         return False
70
71     # Build a topological order of reference names
72     topological_order = []
73     roots = [name for name in graph.keys()
74              if not has_predecessor(name)]
75
76     while roots:
77         root = roots.pop()
78
79         # Remove the current node from the graph
80         # and collect all new roots (the nodes that
81         # were previously only referenced from n)
82         successors = graph.pop(root, set())
83         roots.extend(successor for successor in successors
84                      if not has_predecessor(successor))
85
86         topological_order.insert(0, root)
87
88     if graph:
89         raise Exception('Can\'t sort cyclic references: %s' % graph)
90
91     # Sort the actual assignments based on the topological order
92     return sorted(assignments,
93                   key=lambda a: topological_order.index(a.reference_name()))
94
95
96 def dependency_sort(assignments):
97     """ We define a dependency sort as a Tarjan strongly-connected
98     components resolution. Tarjan's algorithm happens to topologically
99     sort as a by-product of finding strongly-connected components.
100
101     Use this in code generators to sort assignments in dependency order, if
102     there are circular dependencies. It is slower than ``topological_sort``.
103
104     In the sema model, each node depends on types mentioned in its
105     ``descendants``. The model is nominally a tree, except ``descendants``
106     can contain node references forming a cycle.
107
108     Returns a list of tuples, where each item represents a component
109     in the graph. Ideally they're one-tuples, but if the graph has cycles
110     items can have any number of elements constituting a cycle.
111
112     This is nice, because the output is in perfect dependency order,
113     except for the cycle components, where there is no order. They
114     can be detected on the basis of their plurality and handled
115     separately.
116     """
117     # Build reverse-lookup table from name -> node.
118     assignments_by_name = {a.reference_name(): a for a in assignments}
119
120     # Build the dependency graph.
121     graph = {}
122     for assignment in assignments:
123         references = assignment.references()
124         graph[assignment] = [assignments_by_name[r] for r in references
125                              if r in assignments_by_name]
126
127     # Now let Tarjan do its work! Adapted from here:
128     # http://www.logarithmic.net/pfh-files/blog/01208083168/tarjan.py
129     index_counter = [0]
130     stack = []
131     lowlinks = {}
132     index = {}
133     result = []
134
135     def strongconnect(node):
136         # Set the depth index for this node to the smallest unused index
137         index[node] = index_counter[0]
138         lowlinks[node] = index_counter[0]
139         index_counter[0] += 1
140         stack.append(node)
141
142         # Consider successors of `node`
143         successors = graph.get(node, [])
144         for successor in successors:
145             if successor not in lowlinks:
146                 # Successor has not yet been visited; recurse on it
147                 strongconnect(successor)
148                 lowlinks[node] = min(lowlinks[node], lowlinks[successor])
149             elif successor in stack:
150                 # the successor is in the stack and hence in the current
151                 # strongly connected component (SCC)
152                 lowlinks[node] = min(lowlinks[node], index[successor])
153
154         # If `node` is a root node, pop the stack and generate an SCC
155         if lowlinks[node] == index[node]:
156             connected_component = []
157
158             while True:
159                 successor = stack.pop()
160                 connected_component.append(successor)
161                 if successor == node:
162                     break
163
164             component = tuple(connected_component)
165             result.append(component)
166
167     for node in sorted(graph.keys(), key=lambda a: a.reference_name()):
168         if node not in lowlinks:
169             strongconnect(node)
170
171     return result
172
173
174 # Registered object identifier names
175 REGISTERED_OID_NAMES = {
176     'ccitt': 0,
177     'iso': 1,
178     'joint-iso-ccitt': 2,
179     # ccitt
180     'recommendation': 0,
181     'question': 1,
182     'administration': 2,
183     'network-operator': 3,
184     # iso
185     'standard': 0,
186     'registration-authority': 1,
187     'member-body': 2,
188     'identified-organization': 3,
189     # joint-iso-ccitt
190     'country': 16,
191     'registration-procedures': 17
192 }
193
194
195 class TagImplicitness(object):
196     """ Tag implicit/explicit enumeration """
197     IMPLICIT = 0
198     EXPLICIT = 1
199     AUTOMATIC = 2
200
201
202 """
203 Sema nodes
204
205 Concepts in the ASN.1 specification are mirrored here as a simple object model.
206
207 Class and member names typically follow the ASN.1 terminology, but there are
208 some concepts captured which are not expressed in the spec.
209
210 Most notably, we build a dependency graph of all types and values in a module,
211 to allow code generators to build code in dependency order.
212
213 All nodes that somehow denote a referenced type or value, either definitions
214 (type and value assignments) or references (referenced types, referenced values,
215 etc) must have a method called ``reference_name``.
216 """
217
218
219 class SemaNode(object):
220     """ Base class for all sema nodes. """
221
222     def children(self):
223         """ Return a list of all contained sema nodes.
224
225         This implementation finds all member variables of type
226         SemaNode. It also expands list members, to transparently
227         handle the case where a node holds a list of other
228         sema nodes.
229         """
230         # Collect all SemaNode members.
231         members = list(vars(self).values())
232         children = [m for m in members if isinstance(m, SemaNode)]
233
234         # Expand SemaNodes out of list members, but do not recurse
235         # through lists of lists.
236         list_members = [m for m in members if isinstance(m, list)]
237         for m in list_members:
238             children.extend(n for n in m if isinstance(n, SemaNode))
239
240         return children
241
242     def descendants(self):
243         """ Return a list of all recursively contained sema nodes.
244         """
245         descendants = []
246         for child in self.children():
247             descendants.append(child)
248             descendants.extend(child.descendants())
249
250         return descendants
251
252
253 class Module(SemaNode):
254     def __init__(self, elements):
255         self._user_types = {}
256
257         module_reference, definitive_identifier, tag_default, extension_default, module_body = elements
258         exports, imports, assignments = module_body.elements
259
260         self.name = module_reference.elements[0]
261
262         if tag_default == 'IMPLICIT TAGS':
263             self.tag_default = TagImplicitness.IMPLICIT
264         elif tag_default == 'EXPLICIT TAGS':
265             self.tag_default = TagImplicitness.EXPLICIT
266         elif tag_default == 'AUTOMATIC TAGS':
267             self.tag_default = TagImplicitness.AUTOMATIC
268         else:
269             if tag_default is not None:
270                 raise Exception('Unexpected tag default: %s' % tag_default)
271             # Tag default was not specified, default to explicit
272             self.tag_default = TagImplicitness.EXPLICIT
273
274         self.assignments = [_create_sema_node(token) for token in assignments.elements]
275
276     def user_types(self):
277         if not self._user_types:
278             # Index all type assignments by name
279             type_assignments = [a for a in self.assignments if isinstance(a, TypeAssignment)]
280             for user_defined in type_assignments:
281                 self._user_types[user_defined.type_name] = user_defined.type_decl
282
283         return self._user_types
284
285     def resolve_type_decl(self, type_decl, referenced_modules):
286         """ Recursively resolve user-defined types to their built-in
287         declaration.
288         """
289         if isinstance(type_decl, ReferencedType):
290             module = None
291             if not type_decl.module_name or type_decl.module_name == self.name:
292                 module = self
293             else:
294                 # Find the referenced module
295                 for ref_mod in referenced_modules:
296                     if ref_mod.name == type_decl.module_name:
297                         module = ref_mod
298                         break
299             if not module:
300                 raise Exception('Unrecognized referenced module %s in %s.' % (type_decl.module_name,
301                                                                               [module.name for module in
302                                                                                referenced_modules]))
303             return module.resolve_type_decl(module.user_types()[type_decl.type_name], referenced_modules)
304         else:
305             return type_decl
306
307     def get_type_decl(self, type_name):
308         user_types = self.user_types()
309         return user_types[type_name]
310
311     def resolve_selection_type(self, selection_type_decl):
312         if not isinstance(selection_type_decl, SelectionType):
313             raise Exception("Expected SelectionType, was %s" % selection_type_decl.__class__.__name__)
314
315         choice_type = self.get_type_decl(selection_type_decl.type_decl.type_name)
316         for named_type in choice_type.components:
317             if named_type.identifier == selection_type_decl.identifier:
318                 return named_type.type_decl
319
320         return None
321
322     def resolve_tag_implicitness(self, tag_implicitness, tagged_type_decl):
323         """ The implicitness for a tag depends on three things:
324         * Any written implicitness on the tag decl itself (``tag_implicitness``)
325         * The module's tag default (kept in ``self.tag_default``)
326         * Details of the tagged type according to X.680, 30.6c (``tagged_type_decl``)
327         """
328         if tag_implicitness is not None:
329             return tag_implicitness
330
331         # Tagged CHOICEs must always be explicit if the default is implicit, automatic or empty
332         # See X.680, 30.6c
333         if isinstance(tagged_type_decl, ChoiceType):
334             return TagImplicitness.EXPLICIT
335
336         # No tag implicitness specified, use module-default
337         if self.tag_default is None:
338             # Explicit is default if nothing
339             return TagImplicitness.EXPLICIT
340         elif self.tag_default == TagImplicitness.AUTOMATIC:
341             # TODO: Expand according to rules for automatic tagging.
342             return TagImplicitness.IMPLICIT
343
344         return self.tag_default
345
346     def __str__(self):
347         return '%s DEFINITIONS ::=\n' % self.name \
348                + 'BEGIN\n' \
349                + '\n'.join(map(str, self.assignments)) + '\n' \
350                + 'END\n'
351
352     __repr__ = __str__
353
354
355 class Assignment(SemaNode):
356     def references(self):
357         """ Return a set of all reference names (both values and types) that
358         this assignment depends on.
359
360         This happens to coincide with all contained SemaNodes as exposed by
361         ``descendants`` with a ``reference_name`` method.
362         """
363         return set(d.reference_name() for d in self.descendants()
364                    if hasattr(d, 'reference_name'))
365
366
367 class TypeAssignment(Assignment):
368     def __init__(self, elements):
369         if len(elements) != 3:
370             raise Exception('Malformed type assignment')
371         type_name, _, type_decl = elements
372         self.type_name = type_name
373         self.type_decl = _create_sema_node(type_decl)
374
375     def reference_name(self):
376         return self.type_name
377
378     def __str__(self):
379         return '%s ::= %s' % (self.type_name, self.type_decl)
380
381     __repr__ = __str__
382
383
384 class ValueAssignment(Assignment):
385     def __init__(self, elements):
386         value_name, type_name, _, value = elements
387         self.value_name = value_name
388         self.type_decl = _create_sema_node(type_name)
389         self.value = _maybe_create_sema_node(value)
390
391     def reference_name(self):
392         return self.value_name
393
394     def __str__(self):
395         return '%s %s ::= %s' % (self.value_name, self.type_decl, self.value)
396
397     __repr__ = __str__
398
399
400 class ConstructedType(SemaNode):
401     """ Base type for SEQUENCE, SET and CHOICE. """
402
403     def __init__(self, elements):
404         type_name, component_tokens = elements
405         self.type_name = type_name
406         self.components = [_create_sema_node(token)
407                            for token in component_tokens]
408
409     def auto_tag(self):
410         # Constructed types can have ExtensionMarkers as components, ignore them
411         component_types = [c.type_decl for c in self.components
412                            if hasattr(c, 'type_decl')]
413         already_tagged = any(isinstance(c, TaggedType) for c in component_types)
414         if not already_tagged:
415             # Wrap components in TaggedTypes
416             for tag_number, child in enumerate([c for c in self.children()
417                                                 if hasattr(c, 'type_decl')]):
418                 element = child.type_decl
419                 tagged_type = TaggedType((None, str(tag_number), None, element))
420                 child.type_decl = tagged_type
421
422     def __str__(self):
423         component_type_list = ', '.join(map(str, self.components))
424         return '%s { %s }' % (self.type_name, component_type_list)
425
426     __repr__ = __str__
427
428
429 class ChoiceType(ConstructedType):
430     def __init__(self, elements):
431         super(ChoiceType, self).__init__(elements)
432
433
434 class SequenceType(ConstructedType):
435     def __init__(self, elements):
436         super(SequenceType, self).__init__(elements)
437
438
439 class SetType(ConstructedType):
440     def __init__(self, elements):
441         super(SetType, self).__init__(elements)
442
443
444 class CollectionType(SemaNode):
445     """ Base type for SET OF and SEQUENCE OF. """
446
447     def __init__(self, kind, elements):
448         self.kind = kind
449         self.type_name = self.kind + ' OF'
450         self.size_constraint = _maybe_create_sema_node(elements[0])
451         self.type_decl = _create_sema_node(elements[1])
452
453     def __str__(self):
454         if self.size_constraint:
455             return '%s %s OF %s' % (self.kind, self.size_constraint, self.type_decl)
456         else:
457             return '%s OF %s' % (self.kind, self.type_decl)
458
459     __repr__ = __str__
460
461
462 class SequenceOfType(CollectionType):
463     def __init__(self, elements):
464         super(SequenceOfType, self).__init__('SEQUENCE', elements)
465
466
467 class SetOfType(CollectionType):
468     def __init__(self, elements):
469         super(SetOfType, self).__init__('SET', elements)
470
471
472 class TaggedType(SemaNode):
473     def __init__(self, elements):
474         self.class_name = None
475         self.class_number = None
476         if len(elements) == 3:
477             tag_token, implicitness, type_token = elements
478             for tag_element in tag_token.elements:
479                 if tag_element.ty == 'TagClassNumber':
480                     self.class_number = tag_element.elements[0]
481                 elif tag_element.ty == 'TagClass':
482                     self.class_name = tag_element.elements[0]
483                 else:
484                     raise Exception('Unknown tag element: %s' % tag_element)
485             self.type_decl = _create_sema_node(type_token)
486         elif len(elements) == 4:
487             self.class_name, self.class_number, implicitness, self.type_decl = elements
488         else:
489             raise Exception('Incorrect number of elements passed to TaggedType')
490
491         if implicitness == 'IMPLICIT':
492             self.implicitness = TagImplicitness.IMPLICIT
493         elif implicitness == 'EXPLICIT':
494             self.implicitness = TagImplicitness.EXPLICIT
495         elif implicitness is None:
496             self.implicitness = None  # Module-default or automatic
497
498     @property
499     def type_name(self):
500         return self.type_decl.type_name
501
502     def __str__(self):
503         class_spec = []
504         if self.class_name:
505             class_spec.append(self.class_name)
506         class_spec.append(self.class_number)
507
508         result = '[%s] ' % ' '.join(class_spec)
509         if self.implicitness == TagImplicitness.IMPLICIT:
510             result += 'IMPLICIT '
511         elif self.implicitness == TagImplicitness.EXPLICIT:
512             result += 'EXPLICIT '
513         else:
514             pass  # module-default
515
516         result += str(self.type_decl)
517
518         return result
519
520     __repr__ = __str__
521
522
523 class SimpleType(SemaNode):
524     def __init__(self, elements):
525         self.constraint = None
526         self.type_name = elements[0]
527         if len(elements) > 1:
528             _assert_annotated_token(elements[1])
529             self.constraint = _create_sema_node(elements[1])
530
531     def __str__(self):
532         if self.constraint is None:
533             return self.type_name
534
535         return '%s %s' % (self.type_name, self.constraint)
536
537     __repr__ = __str__
538
539
540 class ReferencedType(SemaNode):
541     pass
542
543
544 class DefinedType(ReferencedType):
545     def __init__(self, elements):
546         self.constraint = None
547         self.module_name = None
548
549         module_ref, type_ref, size_constraint = elements
550         if module_ref:
551             self.module_name = module_ref.elements[0]
552         self.type_name = type_ref
553         if size_constraint:
554             self.constraint = _create_sema_node(size_constraint)
555
556     def reference_name(self):
557         return self.type_name
558
559     def __str__(self):
560         if self.module_name:
561             type_name = self.module_name + '.' + self.type_name
562         else:
563             type_name = self.type_name
564
565         if self.constraint is None:
566             return type_name
567
568         return '%s %s' % (type_name, self.constraint)
569
570     __repr__ = __str__
571
572
573 class SelectionType(ReferencedType):
574     def __init__(self, elements):
575         self.identifier = elements[0].elements[0]
576         self.type_decl = _create_sema_node(elements[1])
577
578     @property
579     def type_name(self):
580         return self.type_decl.type_name
581
582     def reference_name(self):
583         return self.type_name
584
585     def __str__(self):
586         return '%s < %s' % (self.identifier, self.type_name)
587
588     __repr__ = __str__
589
590
591 class ReferencedValue(SemaNode):
592     def __init__(self, elements):
593         if len(elements) > 1 and elements[0].ty == 'ModuleReference':
594             self.module_reference = elements[0].elements[0]
595             self.name = elements[1]
596         else:
597             self.module_reference = None
598             self.name = elements[0]
599
600     def reference_name(self):
601         return self.name
602
603     def __str__(self):
604         if not self.module_reference:
605             return self.name
606         return '%s.%s' % (self.module_reference, self.name)
607
608     __repr__ = __str__
609
610
611 class SingleValueConstraint(SemaNode):
612     def __init__(self, elements):
613         self.value = _maybe_create_sema_node(elements[0])
614
615     def __str__(self):
616         return '(%s)' % self.value
617
618     __repr__ = __str__
619
620
621 class ValueRangeConstraint(SemaNode):
622     def __init__(self, elements):
623         self.min_value = _maybe_create_sema_node(elements[0])
624         self.max_value = _maybe_create_sema_node(elements[1])
625
626     def __str__(self):
627         return '(%s..%s)' % (self.min_value, self.max_value)
628
629     __repr__ = __str__
630
631
632 class SizeConstraint(SemaNode):
633     """ Size constraints nest single-value or range constraints to denote valid sizes. """
634
635     def __init__(self, elements):
636         self.nested = _create_sema_node(elements[0])
637         if not isinstance(self.nested, (ValueRangeConstraint, SingleValueConstraint)):
638             raise Exception('Unexpected size constraint type %s' % self.nested.__class__.__name__)
639
640     def __str__(self):
641         return 'SIZE%s' % self.nested
642
643     __repr__ = __str__
644
645
646 class ComponentType(SemaNode):
647     def __init__(self, elements):
648         self.identifier = None
649         self.type_decl = None
650         self.default_value = None
651         self.optional = False
652         self.components_of_type = None
653
654         def crack_named_type(token):
655             named_type = NamedType(token)
656             self.identifier = named_type.identifier
657             self.type_decl = named_type.type_decl
658
659         first_token = elements[0]
660         if first_token.ty == 'NamedType':
661             crack_named_type(first_token.elements)
662         elif first_token.ty == 'ComponentTypeOptional':
663             crack_named_type(first_token.elements[0].elements)
664             self.optional = True
665         elif first_token.ty == 'ComponentTypeDefault':
666             crack_named_type(first_token.elements[0].elements)
667             self.default_value = _maybe_create_sema_node(first_token.elements[1])
668         elif first_token.ty == 'ComponentTypeComponentsOf':
669             self.components_of_type = _create_sema_node(first_token.elements[0])
670         else:
671             raise Exception('Unknown component type %s' % first_token)
672
673     def __str__(self):
674         if self.components_of_type:
675             return 'COMPONENTS OF %s' % self.components_of_type
676
677         result = '%s %s' % (self.identifier, self.type_decl)
678         if self.optional:
679             result += ' OPTIONAL'
680         elif self.default_value is not None:
681             result += ' DEFAULT %s' % self.default_value
682
683         return result
684
685     __repr__ = __str__
686
687
688 class NamedType(SemaNode):
689     def __init__(self, elements):
690         first_token = elements[0]
691         if first_token.ty == 'Type':
692             # EXT: unnamed member
693             type_token = first_token
694             self.identifier = _get_next_unnamed()
695         elif first_token.ty == 'Identifier':
696             # an identifier
697             self.identifier = first_token.elements[0]
698             type_token = elements[1]
699         else:
700             raise Exception('Unexpected token %s' % first_token.ty)
701
702         self.type_decl = _create_sema_node(type_token)
703
704     def __str__(self):
705         return '%s %s' % (self.identifier, self.type_decl)
706
707     __repr__ = __str__
708
709
710 class ValueListType(SemaNode):
711     def __init__(self, elements):
712         self.constraint = None
713         self.type_name = elements[0]
714
715         self.named_values = [_create_sema_node(token) for token in elements[1]]
716         for idx, n in enumerate(self.named_values):
717             if isinstance(n, NamedValue) and n.value is None:
718                 if idx == 0:
719                     n.value = str(0)
720                 else:
721                     n.value = str(int(self.named_values[idx - 1].value) + 1)
722
723         if len(elements) > 2:
724             self.constraint = _maybe_create_sema_node(elements[2])
725
726     def __str__(self):
727         named_value_list = ''
728         constraint = ''
729
730         if self.named_values:
731             named_value_list = ' { %s }' % ', '.join(map(str, self.named_values))
732
733         if self.constraint:
734             constraint = ' %s' % self.constraint
735
736         return '%s%s%s' % (self.type_name, named_value_list, constraint)
737
738     __repr__ = __str__
739
740
741 class BitStringType(SemaNode):
742     def __init__(self, elements):
743         self.type_name = elements[0]
744         self.named_bits = [_create_sema_node(token) for token in elements[1]]
745         self.constraint = _maybe_create_sema_node(elements[2])
746
747     def __str__(self):
748         named_bit_list = ''
749         constraint = ''
750
751         if self.named_bits:
752             named_bit_list = ' { %s }' % ', '.join(map(str, self.named_bits))
753
754         if self.constraint:
755             constraint = ' %s' % self.constraint
756
757         return '%s%s%s' % (self.type_name, named_bit_list, constraint)
758
759     __repr__ = __str__
760
761
762 class NamedValue(SemaNode):
763     def __init__(self, elements):
764         if len(elements) == 1:
765             identifier_token = elements[0]
766             self.identifier = identifier_token
767             self.value = None
768         else:
769             identifier_token, value_token = elements
770             self.identifier = identifier_token.elements[0]
771             self.value = value_token.elements[0]
772
773     def __str__(self):
774         return '%s (%s)' % (self.identifier, self.value)
775
776     __repr__ = __str__
777
778
779 class ExtensionMarker(SemaNode):
780     def __init__(self, elements):
781         pass
782
783     def __str__(self):
784         return '...'
785
786     __repr__ = __str__
787
788
789 class NameForm(SemaNode):
790     def __init__(self, elements):
791         self.name = elements[0]
792
793     def reference_name(self):
794         return self.name
795
796     def __str__(self):
797         return self.name
798
799     __repr__ = __str__
800
801
802 class NumberForm(SemaNode):
803     def __init__(self, elements):
804         self.value = elements[0]
805
806     def __str__(self):
807         return str(self.value)
808
809     __repr__ = __str__
810
811
812 class NameAndNumberForm(SemaNode):
813     def __init__(self, elements):
814         self.name = _create_sema_node(elements[0])
815         self.number = _create_sema_node(elements[1])
816
817     def __str__(self):
818         return '%s(%s)' % (self.name, self.number)
819
820     __repr__ = __str__
821
822
823 class ObjectIdentifierValue(SemaNode):
824     def __init__(self, elements):
825         self.components = [_create_sema_node(c) for c in elements]
826
827     def __str__(self):
828         return '{' + ' '.join(str(x) for x in self.components) + '}'
829
830     __repr__ = __str__
831
832
833 class BinaryStringValue(SemaNode):
834     def __init__(self, elements):
835         self.value = elements[0]
836
837     def __str__(self):
838         return '\'%s\'B' % self.value
839
840     __repr__ = __str__
841
842
843 class HexStringValue(SemaNode):
844     def __init__(self, elements):
845         self.value = elements[0]
846
847     def __str__(self):
848         return '\'%s\'H' % self.value
849
850     __repr__ = __str__
851
852
853 def _maybe_create_sema_node(token):
854     if isinstance(token, parser.AnnotatedToken):
855         return _create_sema_node(token)
856     else:
857         return token
858
859
860 def _create_sema_node(token):
861     _assert_annotated_token(token)
862
863     if token.ty == 'ModuleDefinition':
864         return Module(token.elements)
865     elif token.ty == 'TypeAssignment':
866         return TypeAssignment(token.elements)
867     elif token.ty == 'ValueAssignment':
868         return ValueAssignment(token.elements)
869     elif token.ty == 'ComponentType':
870         return ComponentType(token.elements)
871     elif token.ty == 'NamedType':
872         return NamedType(token.elements)
873     elif token.ty == 'ValueListType':
874         return ValueListType(token.elements)
875     elif token.ty == 'BitStringType':
876         return BitStringType(token.elements)
877     elif token.ty == 'NamedValue':
878         return NamedValue(token.elements)
879     elif token.ty == 'Type':
880         # Type tokens have a more specific type category
881         # embedded as their first element
882         return _create_sema_node(token.elements[0])
883     elif token.ty == 'SimpleType':
884         return SimpleType(token.elements)
885     elif token.ty == 'DefinedType':
886         return DefinedType(token.elements)
887     elif token.ty == 'SelectionType':
888         return SelectionType(token.elements)
889     elif token.ty == 'ReferencedValue':
890         return ReferencedValue(token.elements)
891     elif token.ty == 'TaggedType':
892         return TaggedType(token.elements)
893     elif token.ty == 'SequenceType':
894         return SequenceType(token.elements)
895     elif token.ty == 'ChoiceType':
896         return ChoiceType(token.elements)
897     elif token.ty == 'SetType':
898         return SetType(token.elements)
899     elif token.ty == 'SequenceOfType':
900         return SequenceOfType(token.elements)
901     elif token.ty == 'SetOfType':
902         return SetOfType(token.elements)
903     elif token.ty == 'ExtensionMarker':
904         return ExtensionMarker(token.elements)
905     elif token.ty == 'SingleValueConstraint':
906         return SingleValueConstraint(token.elements)
907     elif token.ty == 'SizeConstraint':
908         return SizeConstraint(token.elements)
909     elif token.ty == 'ValueRangeConstraint':
910         return ValueRangeConstraint(token.elements)
911     elif token.ty == 'ObjectIdentifierValue':
912         return ObjectIdentifierValue(token.elements)
913     elif token.ty == 'NameForm':
914         return NameForm(token.elements)
915     elif token.ty == 'NumberForm':
916         return NumberForm(token.elements)
917     elif token.ty == 'NameAndNumberForm':
918         return NameAndNumberForm(token.elements)
919     elif token.ty == 'BinaryStringValue':
920         return BinaryStringValue(token.elements)
921     elif token.ty == 'HexStringValue':
922         return HexStringValue(token.elements)
923
924     raise Exception('Unknown token type: %s' % token.ty)
925
926
927 def _assert_annotated_token(obj):
928     if type(obj) is not parser.AnnotatedToken:
929         raise Exception('Object %r is not an annotated token' % obj)
930
931
932 # HACK: Generate unique names for unnamed members
933 _unnamed_counter = 0
934
935
936 def _get_next_unnamed():
937     global _unnamed_counter
938     _unnamed_counter += 1
939     return 'unnamed%d' % _unnamed_counter