Remove now-unused function.
[asn2quickder] / asn1ate / pyasn1gen.py
1 # Copyright (c) 2013, 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 __future__ import print_function  # Python 2 compatibility
27
28 import sys
29 from asn1ate import parser
30 from asn1ate.support import pygen
31 from asn1ate.sema import *
32
33
34 class Pyasn1Backend(object):
35     """ Backend to generate pyasn1 declarations from semantic tree.
36     Generators are divided into declarations and expressions,
37     because types in pyasn1 can be declared either as class
38     definitions or inline, e.g.
39
40     # Foo ::= INTEGER
41     # Foo is a decl
42     class Foo(univ.Integer):
43         pass
44
45     # Seq ::= SEQUENCE {
46     #     foo INTEGER
47     # }
48     # Seq is a decl,
49     # univ.Integer is an expr
50     class Seq(univ.Sequence):
51         componentType = namedtype.NamedTypes(
52             namedtype.NamedType('foo', univ.Integer())
53         )
54
55     Typically, declarations can contain other declarations
56     or expressions, expressions can only contain other expressions.
57     """
58     def __init__(self, sema_module, out_stream):
59         self.sema_module = sema_module
60         self.writer = pygen.PythonWriter(out_stream)
61
62         self.decl_generators = {
63             ChoiceType: self.decl_constructed_type,
64             SequenceType: self.decl_constructed_type,
65             TaggedType: self.decl_tagged_type,
66             SimpleType: self.decl_simple_type,
67             UserDefinedType: self.decl_userdefined_type,
68             ValueListType: self.decl_value_list_type,
69             BitStringType: self.decl_bitstring_type,
70             SequenceOfType: self.decl_sequenceof_type,
71             SetOfType: self.decl_setof_type,
72             TypeAssignment: self.decl_type_assignment,
73             ValueAssignment: self.decl_value_assignment
74         }
75
76         self.expr_generators = {
77             TaggedType: self.expr_tagged_type,
78             SimpleType: self.expr_simple_type,
79             UserDefinedType: self.expr_userdefined_type,
80             ComponentType: self.expr_component_type,
81             NamedType: self.expr_named_type,
82             SequenceOfType: self.expr_sequenceof_type,
83             SetOfType: self.expr_setof_type,
84             ValueListType: self.expr_value_list_type
85         }
86
87     def generate_code(self):
88         self.writer.write_line('from pyasn1.type import univ, char, namedtype, namedval, tag, constraint')
89         self.writer.write_blanks(2)
90
91         assignments = topological_sort(self.sema_module.assignments)
92         for assignment in assignments:
93             self.writer.write_block(self.generate_decl(assignment))
94             self.writer.write_blanks(2)
95
96     def generate_expr(self, t):
97         generator = self.expr_generators[type(t)]
98         return generator(t)
99
100     def generate_decl(self, t):
101         generator = self.decl_generators[type(t)]
102         return generator(t)
103
104     def decl_type_assignment(self, assignment):
105         fragment = self.writer.get_fragment()
106
107         assigned_type, type_decl = assignment.type_name, assignment.type_decl
108
109         base_type = _translate_type(type_decl.type_name)
110         fragment.write_line('class %s(%s):' % (assigned_type, base_type))
111
112         fragment.push_indent()
113         fragment.write_block(self.generate_decl(type_decl))
114         fragment.pop_indent()
115
116         return str(fragment)
117
118     def expr_simple_type(self, t):
119         type_expr = _translate_type(t.type_name) + '()'
120         if t.constraint:
121             type_expr += '.subtype(subtypeSpec=constraint.ValueRangeConstraint(%s, %s))' % (t.constraint.min_value, t.constraint.max_value)
122
123         return type_expr
124
125     def decl_simple_type(self, t):
126         if t.constraint:
127             return 'subtypeSpec = constraint.ValueRangeConstraint(%s, %s)' % (t.constraint.min_value, t.constraint.max_value)
128         else:
129             return 'pass'
130
131     def expr_userdefined_type(self, t):
132         return t.type_name + '()'
133
134     def decl_userdefined_type(self, t):
135         return 'pass'
136
137     def decl_constructed_type(self, t):
138         fragment = self.writer.get_fragment()
139
140         fragment.write_line('componentType = namedtype.NamedTypes(')
141
142         fragment.push_indent()
143         fragment.write_block(self.expr_component_types(t.components))
144         fragment.pop_indent()
145
146         fragment.write_line(')')
147
148         return str(fragment)
149
150     def expr_component_types(self, components):
151         fragment = self.writer.get_fragment()
152
153         component_exprs = []
154         for c in components:
155             if not isinstance(c, ExtensionMarker):
156                 component_exprs.append(self.generate_expr(c))
157
158         fragment.write_enumeration(component_exprs)
159
160         return str(fragment)
161
162     def expr_tagged_type(self, t):
163         tag_type = 'implicitTag' if t.implicit else 'explicitTag'
164         type_expr = self.generate_expr(t.type_decl)
165         type_expr += '.subtype(%s=%s)' % (tag_type, self.build_tag_expr(t))
166
167         return type_expr
168
169     def decl_tagged_type(self, t):
170         fragment = self.writer.get_fragment()
171
172         tag_type = 'tagImplicitly' if t.implicit else 'tagExplicitly'
173         base_type = _translate_type(t.type_decl.type_name)
174         fragment.write_line('tagSet = %s.tagSet.%s(%s)' % (base_type, tag_type, self.build_tag_expr(t)))
175         fragment.write_line(self.generate_decl(t.type_decl))  # possibly 'pass'. but that's OK in a decl
176
177         return str(fragment)
178
179     def build_tag_expr(self, tag_def):
180         context = _translate_tag_class(tag_def.class_name)
181
182         tagged_type_decl = self.sema_module.resolve_type_decl(tag_def.type_decl)
183         if isinstance(tagged_type_decl, ConstructedType):
184             tag_format = 'tag.tagFormatConstructed'
185         else:
186             tag_format = 'tag.tagFormatSimple'
187
188         return 'tag.Tag(%s, %s, %s)' % (context, tag_format, tag_def.class_number)
189
190     def expr_component_type(self, t):
191         if t.components_of_type:
192             # COMPONENTS OF works like a literal include, so just
193             # expand all components of the referenced type.
194             included_type_decl = self.sema_module.resolve_type_decl(t.components_of_type)
195             included_content = self.expr_component_types(included_type_decl.components)
196
197             # Strip trailing newline from expr_component_types
198             # to make the list line up
199             return included_content.strip()
200
201         if t.optional:
202             return "namedtype.OptionalNamedType('%s', %s)" % (t.identifier, self.generate_expr(t.type_decl))
203         elif t.default_value is not None:
204             type_expr = self.generate_expr(t.type_decl)
205             type_expr += '.subtype(value=%s)' % _translate_value(t.default_value)
206
207             return "namedtype.DefaultedNamedType('%s', %s)" % (t.identifier, type_expr)
208         else:
209             return "namedtype.NamedType('%s', %s)" % (t.identifier, self.generate_expr(t.type_decl))
210
211     def expr_named_type(self, t):
212         return "namedtype.NamedType('%s', %s)" % (t.identifier, self.generate_expr(t.type_decl))
213
214     def decl_value_list_type(self, t):
215         fragment = self.writer.get_fragment()
216
217         if t.named_values:
218             fragment.write_line('namedValues = namedval.NamedValues(')
219             fragment.push_indent()
220
221             named_values = list(map(lambda v: '(\'%s\', %s)' % (v.identifier, v.value), t.named_values))
222             fragment.write_enumeration(named_values)
223
224             fragment.pop_indent()
225             fragment.write_line(')')
226         else:
227             fragment.write_line('pass')
228
229         return str(fragment)
230
231     def expr_value_list_type(self, t):
232         if t.named_values:
233             named_values = list(map(lambda v: '(\'%s\', %s)' % (v.identifier, v.value), t.named_values))
234             return 'namedValues=namedval.NamedValues(%s)' % ', '.join(named_values)
235         else:
236             return ''
237
238     def decl_bitstring_type(self, t):
239         fragment = self.writer.get_fragment()
240
241         if t.named_bits:
242             fragment.write_line('namedValues = namedval.NamedValues(')
243             fragment.push_indent()
244
245             named_bit_list = list(map(lambda v: '(\'%s\', %s)' % (v.identifier, v.value), t.named_bits))
246             fragment.write_enumeration(named_bit_list)
247
248             fragment.pop_indent()
249             fragment.write_line(')')
250         else:
251             fragment.write_line('pass')
252
253         return str(fragment)
254
255     def expr_sequenceof_type(self, t):
256         return 'univ.SequenceOf(componentType=%s)' % self.generate_expr(t.type_decl)
257
258     def decl_sequenceof_type(self, t):
259         return 'componentType = %s' % self.generate_expr(t.type_decl)
260
261     def expr_setof_type(self, t):
262         return 'univ.SetOf(componentType=%s)' % self.generate_expr(t.type_decl)
263
264     def decl_setof_type(self, t):
265         return 'componentType = %s' % self.generate_expr(t.type_decl)
266
267     def decl_value_assignment(self, assignment):
268         assigned_value, type_decl, value = assignment.value_name, assignment.type_decl, assignment.value
269
270         value_type = _translate_type(type_decl.type_name)
271         return '%s = %s(%s)' % (assigned_value, value_type, value)
272
273
274 def generate_pyasn1(sema_module, out_stream):
275     return Pyasn1Backend(sema_module, out_stream).generate_code()
276
277
278 # Translation tables from ASN.1 primitives to pyasn1 primitives
279 _ASN1_TAG_CONTEXTS = {
280     'APPLICATION': 'tag.tagClassApplication',
281     'PRIVATE': 'tag.tagClassPrivate',
282     'UNIVERSAL': 'tag.tagClassUniversal'
283 }
284
285
286 _ASN1_BUILTIN_VALUES = {
287     'FALSE': '0',
288     'TRUE': '1'
289 }
290
291
292 _ASN1_BUILTIN_TYPES = {
293     'INTEGER': 'univ.Integer',
294     'BOOLEAN': 'univ.Boolean',
295     'NULL': 'univ.Null',
296     'ENUMERATED': 'univ.Enumerated',
297     'REAL': 'univ.Real',
298     'BIT STRING': 'univ.BitString',
299     'OCTET STRING': 'univ.OctetString',
300     'CHOICE': 'univ.Choice',
301     'SEQUENCE': 'univ.Sequence',
302     'SEQUENCE OF': 'univ.SequenceOf',
303     'SET OF': 'univ.SetOf',
304     'UTF8String': 'char.UTF8String'
305 }
306
307
308 def _translate_type(type_name):
309     """ Translate ASN.1 built-in types to pyasn1 equivalents.
310     Non-builtins are not translated.
311     """
312     return _ASN1_BUILTIN_TYPES.get(type_name, type_name)
313
314
315 def _translate_tag_class(tag_class):
316     """ Translate ASN.1 tag class names to pyasn1 equivalents.
317     Defaults to tag.tagClassContext if tag_class is not
318     recognized.
319     """
320     return _ASN1_TAG_CONTEXTS.get(tag_class, 'tag.tagClassContext')
321
322
323 def _translate_value(value):
324     """ Translate ASN.1 built-in values to Python equivalents.
325     Unrecognized values are not translated.
326     """
327     return _ASN1_BUILTIN_VALUES.get(value, value)
328
329
330 # Simplistic command-line driver
331 def main(args):
332     with open(args[0]) as f:
333         asn1def = f.read()
334
335     parse_tree = parser.parse_asn1(asn1def)
336
337     modules = build_semantic_model(parse_tree)
338     if len(modules) > 1:
339         print('WARNING: More than one module generated to the same stream.', file=sys.stderr)
340
341     for module in modules:
342         print(pygen.auto_generated_header())
343         generate_pyasn1(module, sys.stdout)
344
345     return 0
346
347
348 if __name__ == '__main__':
349     sys.exit(main(sys.argv[1:]))