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 __future__ import print_function # Python 2 compatibility
29 from asn1ate import parser
30 from asn1ate.support import pygen
31 from asn1ate.sema import *
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.
42 class Foo(univ.Integer):
49 # univ.Integer is an expr
50 class Seq(univ.Sequence):
51 componentType = namedtype.NamedTypes(
52 namedtype.NamedType('foo', univ.Integer())
55 Typically, declarations can contain other declarations
56 or expressions, expressions can only contain other expressions.
58 def __init__(self, sema_module, out_stream):
59 self.sema_module = sema_module
60 self.writer = pygen.PythonWriter(out_stream)
62 self.decl_generators = {
63 ChoiceType: self.decl_constructed_type,
64 SequenceType: self.decl_constructed_type,
65 SetType: self.decl_constructed_type,
66 TaggedType: self.decl_tagged_type,
67 SimpleType: self.decl_simple_type,
68 UserDefinedType: self.decl_userdefined_type,
69 ValueListType: self.decl_value_list_type,
70 BitStringType: self.decl_bitstring_type,
71 SequenceOfType: self.decl_sequenceof_type,
72 SetOfType: self.decl_setof_type,
73 TypeAssignment: self.decl_type_assignment,
74 ValueAssignment: self.decl_value_assignment
77 self.expr_generators = {
78 TaggedType: self.expr_tagged_type,
79 SimpleType: self.expr_simple_type,
80 UserDefinedType: self.expr_userdefined_type,
81 ComponentType: self.expr_component_type,
82 NamedType: self.expr_named_type,
83 SequenceOfType: self.expr_sequenceof_type,
84 SetOfType: self.expr_setof_type,
85 ValueListType: self.expr_value_list_type,
86 ChoiceType: self.expr_constructed_type,
87 SequenceType: self.expr_constructed_type,
88 SetType: self.expr_constructed_type,
91 def generate_code(self):
92 self.writer.write_line('from pyasn1.type import univ, char, namedtype, namedval, tag, constraint, useful')
93 self.writer.write_blanks(2)
95 # TODO: Only generate _OID if sema_module
96 # contains object identifier values.
98 self.writer.write_blanks(2)
100 assignments = topological_sort(self.sema_module.assignments)
101 for assignment in assignments:
102 self.writer.write_block(self.generate_decl(assignment))
103 self.writer.write_blanks(2)
105 def generate_expr(self, t):
106 generator = self.expr_generators[type(t)]
109 def generate_decl(self, t):
110 generator = self.decl_generators[type(t)]
113 def decl_type_assignment(self, assignment):
114 fragment = self.writer.get_fragment()
116 assigned_type, type_decl = assignment.type_name, assignment.type_decl
118 base_type = _translate_type(type_decl.type_name)
119 fragment.write_line('class %s(%s):' % (assigned_type, base_type))
121 fragment.push_indent()
122 fragment.write_block(self.generate_decl(type_decl))
123 fragment.pop_indent()
127 def expr_simple_type(self, t):
128 type_expr = _translate_type(t.type_name) + '()'
130 type_expr += '.subtype(subtypeSpec=constraint.ValueRangeConstraint(%s, %s))' % (t.constraint.min_value, t.constraint.max_value)
134 def decl_simple_type(self, t):
136 return 'subtypeSpec = constraint.ValueRangeConstraint(%s, %s)' % (t.constraint.min_value, t.constraint.max_value)
140 def expr_userdefined_type(self, t):
141 return t.type_name + '()'
143 def decl_userdefined_type(self, t):
146 def decl_constructed_type(self, t):
147 fragment = self.writer.get_fragment()
149 fragment.write_line('componentType = namedtype.NamedTypes(')
151 fragment.push_indent()
152 fragment.write_block(self.expr_component_types(t.components))
153 fragment.pop_indent()
155 fragment.write_line(')')
159 def expr_constructed_type(self, t):
160 fragment = self.writer.get_fragment()
162 class_name = _translate_type(t.type_name)
164 fragment.write_line('%s(componentType=namedtype.NamedTypes(' % class_name)
166 fragment.push_indent()
167 fragment.write_block(self.expr_component_types(t.components))
168 fragment.pop_indent()
170 fragment.write_line('))')
174 def expr_component_types(self, components):
175 fragment = self.writer.get_fragment()
179 if not isinstance(c, ExtensionMarker):
180 component_exprs.append(self.generate_expr(c))
182 fragment.write_enumeration(component_exprs)
186 def expr_tagged_type(self, t):
187 tag_type = 'implicitTag' if t.implicit else 'explicitTag'
188 type_expr = self.generate_expr(t.type_decl)
189 type_expr += '.subtype(%s=%s)' % (tag_type, self.build_tag_expr(t))
193 def decl_tagged_type(self, t):
194 fragment = self.writer.get_fragment()
196 tag_type = 'tagImplicitly' if t.implicit else 'tagExplicitly'
197 base_type = _translate_type(t.type_decl.type_name)
198 fragment.write_line('tagSet = %s.tagSet.%s(%s)' % (base_type, tag_type, self.build_tag_expr(t)))
199 fragment.write_line(self.generate_decl(t.type_decl)) # possibly 'pass'. but that's OK in a decl
203 def build_tag_expr(self, tag_def):
204 context = _translate_tag_class(tag_def.class_name)
206 tagged_type_decl = self.sema_module.resolve_type_decl(tag_def.type_decl)
207 if isinstance(tagged_type_decl, ConstructedType):
208 tag_format = 'tag.tagFormatConstructed'
210 tag_format = 'tag.tagFormatSimple'
212 return 'tag.Tag(%s, %s, %s)' % (context, tag_format, tag_def.class_number)
214 def expr_component_type(self, t):
215 if t.components_of_type:
216 # COMPONENTS OF works like a literal include, so just
217 # expand all components of the referenced type.
218 included_type_decl = self.sema_module.resolve_type_decl(t.components_of_type)
219 included_content = self.expr_component_types(included_type_decl.components)
221 # Strip trailing newline from expr_component_types
222 # to make the list line up
223 return included_content.strip()
226 return "namedtype.OptionalNamedType('%s', %s)" % (t.identifier, self.generate_expr(t.type_decl))
227 elif t.default_value is not None:
228 type_expr = self.generate_expr(t.type_decl)
229 type_expr += '.subtype(value=%s)' % _translate_value(t.default_value)
231 return "namedtype.DefaultedNamedType('%s', %s)" % (t.identifier, type_expr)
233 return "namedtype.NamedType('%s', %s)" % (t.identifier, self.generate_expr(t.type_decl))
235 def expr_named_type(self, t):
236 return "namedtype.NamedType('%s', %s)" % (t.identifier, self.generate_expr(t.type_decl))
238 def decl_value_list_type(self, t):
239 fragment = self.writer.get_fragment()
242 fragment.write_line('namedValues = namedval.NamedValues(')
243 fragment.push_indent()
245 named_values = ['(\'%s\', %s)' % (v.identifier, v.value) for v in t.named_values if not isinstance(v, ExtensionMarker)]
246 fragment.write_enumeration(named_values)
248 fragment.pop_indent()
249 fragment.write_line(')')
251 fragment.write_line('pass')
255 def expr_value_list_type(self, t):
256 class_name = _translate_type(t.type_name)
258 named_values = ['(\'%s\', %s)' % (v.identifier, v.value) for v in t.named_values if not isinstance(v, ExtensionMarker)]
259 return '%s(namedValues=namedval.NamedValues(%s))' % (class_name, ', '.join(named_values))
261 return class_name + '()'
263 def decl_bitstring_type(self, t):
264 fragment = self.writer.get_fragment()
267 fragment.write_line('namedValues = namedval.NamedValues(')
268 fragment.push_indent()
270 named_bit_list = list(map(lambda v: '(\'%s\', %s)' % (v.identifier, v.value), t.named_bits))
271 fragment.write_enumeration(named_bit_list)
273 fragment.pop_indent()
274 fragment.write_line(')')
276 fragment.write_line('pass')
280 def expr_sequenceof_type(self, t):
281 return 'univ.SequenceOf(componentType=%s)' % self.generate_expr(t.type_decl)
283 def decl_sequenceof_type(self, t):
284 return 'componentType = %s' % self.generate_expr(t.type_decl)
286 def expr_setof_type(self, t):
287 return 'univ.SetOf(componentType=%s)' % self.generate_expr(t.type_decl)
289 def decl_setof_type(self, t):
290 return 'componentType = %s' % self.generate_expr(t.type_decl)
292 def decl_value_assignment(self, assignment):
293 assigned_value, type_decl, value = assignment.value_name, assignment.type_decl, assignment.value
295 if isinstance(value, ObjectIdentifierValue):
296 value_constructor = self.build_object_identifier_value(value)
298 value_type = _translate_type(type_decl.type_name)
299 value_constructor = '%s(%s)' % (value_type, value)
301 return '%s = %s' % (assigned_value, value_constructor)
303 def build_object_identifier_value(self, t):
304 objid_components = []
306 for c in t.components:
307 if isinstance(c, NameForm):
308 if c.name in REGISTERED_OID_NAMES:
309 objid_components.append(str(REGISTERED_OID_NAMES[c.name]))
311 objid_components.append(c.name)
312 elif isinstance(c, NumberForm):
313 objid_components.append(str(c.value))
314 elif isinstance(c, NameAndNumberForm):
315 objid_components.append(str(c.number.value))
319 return '_OID(%s)' % ', '.join(objid_components)
321 def generate_OID(self):
322 self.writer.write_line('def _OID(*components):')
323 self.writer.push_indent()
324 self.writer.write_line('output = []')
325 self.writer.write_line('for x in tuple(components):')
326 self.writer.push_indent()
327 self.writer.write_line('if isinstance(x, univ.ObjectIdentifier):')
328 self.writer.push_indent()
329 self.writer.write_line('output.extend(list(x))')
330 self.writer.pop_indent()
331 self.writer.write_line('else:')
332 self.writer.push_indent()
333 self.writer.write_line('output.append(int(x))')
334 self.writer.pop_indent()
335 self.writer.pop_indent()
336 self.writer.write_blanks(1)
337 self.writer.write_line('return univ.ObjectIdentifier(output)')
338 self.writer.pop_indent()
340 self.writer.pop_indent()
343 def generate_pyasn1(sema_module, out_stream):
344 return Pyasn1Backend(sema_module, out_stream).generate_code()
347 # Translation tables from ASN.1 primitives to pyasn1 primitives
348 _ASN1_TAG_CONTEXTS = {
349 'APPLICATION': 'tag.tagClassApplication',
350 'PRIVATE': 'tag.tagClassPrivate',
351 'UNIVERSAL': 'tag.tagClassUniversal'
355 _ASN1_BUILTIN_VALUES = {
361 _ASN1_BUILTIN_TYPES = {
362 'INTEGER': 'univ.Integer',
363 'BOOLEAN': 'univ.Boolean',
365 'ENUMERATED': 'univ.Enumerated',
367 'BIT STRING': 'univ.BitString',
368 'OCTET STRING': 'univ.OctetString',
369 'CHOICE': 'univ.Choice',
370 'SEQUENCE': 'univ.Sequence',
372 'SEQUENCE OF': 'univ.SequenceOf',
373 'SET OF': 'univ.SetOf',
374 'UTF8String': 'char.UTF8String',
375 'GeneralString': 'char.GeneralString',
376 'NumericString': 'char.NumericString',
377 'PrintableString': 'char.PrintableString',
378 'IA5String': 'char.IA5String',
379 'OBJECT IDENTIFIER': 'univ.ObjectIdentifier',
380 'GeneralizedTime': 'useful.GeneralizedTime',
381 'UTCTime': 'useful.UTCTime',
382 'ObjectDescriptor': 'useful.ObjectDescriptor', # In pyasn1 r1.2
386 def _translate_type(type_name):
387 """ Translate ASN.1 built-in types to pyasn1 equivalents.
388 Non-builtins are not translated.
390 return _ASN1_BUILTIN_TYPES.get(type_name, type_name)
393 def _translate_tag_class(tag_class):
394 """ Translate ASN.1 tag class names to pyasn1 equivalents.
395 Defaults to tag.tagClassContext if tag_class is not
398 return _ASN1_TAG_CONTEXTS.get(tag_class, 'tag.tagClassContext')
401 def _translate_value(value):
402 """ Translate ASN.1 built-in values to Python equivalents.
403 Unrecognized values are not translated.
405 return _ASN1_BUILTIN_VALUES.get(value, value)
408 # Simplistic command-line driver
410 with open(args[0]) as f:
413 parse_tree = parser.parse_asn1(asn1def)
415 modules = build_semantic_model(parse_tree)
417 print('WARNING: More than one module generated to the same stream.', file=sys.stderr)
419 for module in modules:
420 print(pygen.auto_generated_header())
421 generate_pyasn1(module, sys.stdout)
426 if __name__ == '__main__':
427 sys.exit(main(sys.argv[1:]))