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 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
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
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)
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)
96 def generate_expr(self, t):
97 generator = self.expr_generators[type(t)]
100 def generate_decl(self, t):
101 generator = self.decl_generators[type(t)]
104 def decl_type_assignment(self, assignment):
105 fragment = self.writer.get_fragment()
107 assigned_type, type_decl = assignment.type_name, assignment.type_decl
109 base_type = _translate_type(type_decl.type_name)
110 fragment.write_line('class %s(%s):' % (assigned_type, base_type))
112 fragment.push_indent()
113 fragment.write_block(self.generate_decl(type_decl))
114 fragment.pop_indent()
118 def expr_simple_type(self, t):
119 type_expr = _translate_type(t.type_name) + '()'
121 type_expr += '.subtype(subtypeSpec=constraint.ValueRangeConstraint(%s, %s))' % (t.constraint.min_value, t.constraint.max_value)
125 def decl_simple_type(self, t):
127 return 'subtypeSpec = constraint.ValueRangeConstraint(%s, %s)' % (t.constraint.min_value, t.constraint.max_value)
131 def expr_userdefined_type(self, t):
132 return t.type_name + '()'
134 def decl_userdefined_type(self, t):
137 def decl_constructed_type(self, t):
138 fragment = self.writer.get_fragment()
140 fragment.write_line('componentType = namedtype.NamedTypes(')
142 fragment.push_indent()
143 fragment.write_block(self.expr_component_types(t.components))
144 fragment.pop_indent()
146 fragment.write_line(')')
150 def expr_component_types(self, components):
151 fragment = self.writer.get_fragment()
155 component_exprs.append(self.generate_expr(c))
157 fragment.write_enumeration(component_exprs)
161 def expr_tagged_type(self, t):
162 tag_type = 'implicitTag' if t.implicit else 'explicitTag'
163 type_expr = self.generate_expr(t.type_decl)
164 type_expr += '.subtype(%s=%s)' % (tag_type, self.build_tag_expr(t))
168 def decl_tagged_type(self, t):
169 fragment = self.writer.get_fragment()
171 tag_type = 'tagImplicitly' if t.implicit else 'tagExplicitly'
172 base_type = _translate_type(t.type_decl.type_name)
173 fragment.write_line('tagSet = %s.tagSet.%s(%s)' % (base_type, tag_type, self.build_tag_expr(t)))
174 fragment.write_line(self.generate_decl(t.type_decl)) # possibly 'pass'. but that's OK in a decl
178 def build_tag_expr(self, tag_def):
179 context = _translate_tag_class(tag_def.class_name)
181 tagged_type_decl = self.sema_module.resolve_type_decl(tag_def.type_decl)
182 if isinstance(tagged_type_decl, ConstructedType):
183 tag_format = 'tag.tagFormatConstructed'
185 tag_format = 'tag.tagFormatSimple'
187 return 'tag.Tag(%s, %s, %s)' % (context, tag_format, tag_def.class_number)
189 def expr_component_type(self, t):
190 if t.components_of_type:
191 # COMPONENTS OF works like a literal include, so just
192 # expand all components of the referenced type.
193 included_type_decl = self.sema_module.resolve_type_decl(t.components_of_type)
194 included_content = self.expr_component_types(included_type_decl.components)
196 # Strip trailing newline from expr_component_types
197 # to make the list line up
198 return included_content.strip()
201 return "namedtype.OptionalNamedType('%s', %s)" % (t.identifier, self.generate_expr(t.type_decl))
202 elif t.default_value is not None:
203 type_expr = self.generate_expr(t.type_decl)
204 type_expr += '.subtype(value=%s)' % _translate_value(t.default_value)
206 return "namedtype.DefaultedNamedType('%s', %s)" % (t.identifier, type_expr)
208 return "namedtype.NamedType('%s', %s)" % (t.identifier, self.generate_expr(t.type_decl))
210 def expr_named_type(self, t):
211 return "namedtype.NamedType('%s', %s)" % (t.identifier, self.generate_expr(t.type_decl))
213 def decl_value_list_type(self, t):
214 fragment = self.writer.get_fragment()
217 fragment.write_line('namedValues = namedval.NamedValues(')
218 fragment.push_indent()
220 named_values = list(map(lambda v: '(\'%s\', %s)' % (v.identifier, v.value), t.named_values))
221 fragment.write_enumeration(named_values)
223 fragment.pop_indent()
224 fragment.write_line(')')
226 fragment.write_line('pass')
230 def expr_value_list_type(self, t):
232 named_values = list(map(lambda v: '(\'%s\', %s)' % (v.identifier, v.value), t.named_values))
233 return 'namedValues=namedval.NamedValues(%s)' % ', '.join(named_values)
237 def decl_bitstring_type(self, t):
238 fragment = self.writer.get_fragment()
241 fragment.write_line('namedValues = namedval.NamedValues(')
242 fragment.push_indent()
244 named_bit_list = list(map(lambda v: '(\'%s\', %s)' % (v.identifier, v.value), t.named_bits))
245 fragment.write_enumeration(named_bit_list)
247 fragment.pop_indent()
248 fragment.write_line(')')
250 fragment.write_line('pass')
254 def expr_sequenceof_type(self, t):
255 return 'univ.SequenceOf(componentType=%s)' % self.generate_expr(t.type_decl)
257 def decl_sequenceof_type(self, t):
258 return 'componentType = %s' % self.generate_expr(t.type_decl)
260 def expr_setof_type(self, t):
261 return 'univ.SetOf(componentType=%s)' % self.generate_expr(t.type_decl)
263 def decl_setof_type(self, t):
264 return 'componentType = %s' % self.generate_expr(t.type_decl)
266 def decl_value_assignment(self, assignment):
267 assigned_value, type_decl, value = assignment.value_name, assignment.type_decl, assignment.value
269 value_type = _translate_type(type_decl.type_name)
270 return '%s = %s(%s)' % (assigned_value, value_type, value)
273 def generate_pyasn1(sema_module, out_stream):
274 return Pyasn1Backend(sema_module, out_stream).generate_code()
277 # Translation tables from ASN.1 primitives to pyasn1 primitives
278 _ASN1_TAG_CONTEXTS = {
279 'APPLICATION': 'tag.tagClassApplication',
280 'PRIVATE': 'tag.tagClassPrivate',
281 'UNIVERSAL': 'tag.tagClassUniversal'
285 _ASN1_BUILTIN_VALUES = {
291 _ASN1_BUILTIN_TYPES = {
292 'INTEGER': 'univ.Integer',
293 'BOOLEAN': 'univ.Boolean',
295 'ENUMERATED': 'univ.Enumerated',
297 'BIT STRING': 'univ.BitString',
298 'OCTET STRING': 'univ.OctetString',
299 'CHOICE': 'univ.Choice',
300 'SEQUENCE': 'univ.Sequence',
301 'SEQUENCE OF': 'univ.SequenceOf',
302 'SET OF': 'univ.SetOf',
303 'UTF8String': 'char.UTF8String'
307 def _translate_type(type_name):
308 """ Translate ASN.1 built-in types to pyasn1 equivalents.
309 Non-builtins are not translated.
311 return _ASN1_BUILTIN_TYPES.get(type_name, type_name)
314 def _translate_tag_class(tag_class):
315 """ Translate ASN.1 tag class names to pyasn1 equivalents.
316 Defaults to tag.tagClassContext if tag_class is not
319 return _ASN1_TAG_CONTEXTS.get(tag_class, 'tag.tagClassContext')
322 def _translate_value(value):
323 """ Translate ASN.1 built-in values to Python equivalents.
324 Unrecognized values are not translated.
326 return _ASN1_BUILTIN_VALUES.get(value, value)
329 # Simplistic command-line driver
331 with open(args[0]) as f:
334 parse_tree = parser.parse_asn1(asn1def)
336 modules = build_semantic_model(parse_tree)
338 print('WARNING: More than one module generated to the same stream.', file=sys.stderr)
340 for module in modules:
341 print(pygen.auto_generated_header())
342 generate_pyasn1(module, sys.stdout)
347 if __name__ == '__main__':
348 sys.exit(main(sys.argv[1:]))