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
88 def generate_code(self):
89 self.writer.write_line('from pyasn1.type import univ, char, namedtype, namedval, tag, constraint')
90 self.writer.write_blanks(2)
92 assignments = topological_sort(self.sema_module.assignments)
93 for assignment in assignments:
94 self.writer.write_block(self.generate_decl(assignment))
95 self.writer.write_blanks(2)
97 def generate_expr(self, t):
98 generator = self.expr_generators[type(t)]
101 def generate_decl(self, t):
102 generator = self.decl_generators[type(t)]
105 def decl_type_assignment(self, assignment):
106 fragment = self.writer.get_fragment()
108 assigned_type, type_decl = assignment.type_name, assignment.type_decl
110 base_type = _translate_type(type_decl.type_name)
111 fragment.write_line('class %s(%s):' % (assigned_type, base_type))
113 fragment.push_indent()
114 fragment.write_block(self.generate_decl(type_decl))
115 fragment.pop_indent()
119 def expr_simple_type(self, t):
120 type_expr = _translate_type(t.type_name) + '()'
122 type_expr += '.subtype(subtypeSpec=constraint.ValueRangeConstraint(%s, %s))' % (t.constraint.min_value, t.constraint.max_value)
126 def decl_simple_type(self, t):
128 return 'subtypeSpec = constraint.ValueRangeConstraint(%s, %s)' % (t.constraint.min_value, t.constraint.max_value)
132 def expr_userdefined_type(self, t):
133 return t.type_name + '()'
135 def decl_userdefined_type(self, t):
138 def decl_constructed_type(self, t):
139 fragment = self.writer.get_fragment()
141 fragment.write_line('componentType = namedtype.NamedTypes(')
143 fragment.push_indent()
144 fragment.write_block(self.expr_component_types(t.components))
145 fragment.pop_indent()
147 fragment.write_line(')')
151 def expr_component_types(self, components):
152 fragment = self.writer.get_fragment()
156 if not isinstance(c, ExtensionMarker):
157 component_exprs.append(self.generate_expr(c))
159 fragment.write_enumeration(component_exprs)
163 def expr_tagged_type(self, t):
164 tag_type = 'implicitTag' if t.implicit else 'explicitTag'
165 type_expr = self.generate_expr(t.type_decl)
166 type_expr += '.subtype(%s=%s)' % (tag_type, self.build_tag_expr(t))
170 def decl_tagged_type(self, t):
171 fragment = self.writer.get_fragment()
173 tag_type = 'tagImplicitly' if t.implicit else 'tagExplicitly'
174 base_type = _translate_type(t.type_decl.type_name)
175 fragment.write_line('tagSet = %s.tagSet.%s(%s)' % (base_type, tag_type, self.build_tag_expr(t)))
176 fragment.write_line(self.generate_decl(t.type_decl)) # possibly 'pass'. but that's OK in a decl
180 def build_tag_expr(self, tag_def):
181 context = _translate_tag_class(tag_def.class_name)
183 tagged_type_decl = self.sema_module.resolve_type_decl(tag_def.type_decl)
184 if isinstance(tagged_type_decl, ConstructedType):
185 tag_format = 'tag.tagFormatConstructed'
187 tag_format = 'tag.tagFormatSimple'
189 return 'tag.Tag(%s, %s, %s)' % (context, tag_format, tag_def.class_number)
191 def expr_component_type(self, t):
192 if t.components_of_type:
193 # COMPONENTS OF works like a literal include, so just
194 # expand all components of the referenced type.
195 included_type_decl = self.sema_module.resolve_type_decl(t.components_of_type)
196 included_content = self.expr_component_types(included_type_decl.components)
198 # Strip trailing newline from expr_component_types
199 # to make the list line up
200 return included_content.strip()
203 return "namedtype.OptionalNamedType('%s', %s)" % (t.identifier, self.generate_expr(t.type_decl))
204 elif t.default_value is not None:
205 type_expr = self.generate_expr(t.type_decl)
206 type_expr += '.subtype(value=%s)' % _translate_value(t.default_value)
208 return "namedtype.DefaultedNamedType('%s', %s)" % (t.identifier, type_expr)
210 return "namedtype.NamedType('%s', %s)" % (t.identifier, self.generate_expr(t.type_decl))
212 def expr_named_type(self, t):
213 return "namedtype.NamedType('%s', %s)" % (t.identifier, self.generate_expr(t.type_decl))
215 def decl_value_list_type(self, t):
216 fragment = self.writer.get_fragment()
219 fragment.write_line('namedValues = namedval.NamedValues(')
220 fragment.push_indent()
222 named_values = list(map(lambda v: '(\'%s\', %s)' % (v.identifier, v.value), t.named_values))
223 fragment.write_enumeration(named_values)
225 fragment.pop_indent()
226 fragment.write_line(')')
228 fragment.write_line('pass')
232 def expr_value_list_type(self, t):
234 named_values = list(map(lambda v: '(\'%s\', %s)' % (v.identifier, v.value), t.named_values))
235 return 'namedValues=namedval.NamedValues(%s)' % ', '.join(named_values)
239 def decl_bitstring_type(self, t):
240 fragment = self.writer.get_fragment()
243 fragment.write_line('namedValues = namedval.NamedValues(')
244 fragment.push_indent()
246 named_bit_list = list(map(lambda v: '(\'%s\', %s)' % (v.identifier, v.value), t.named_bits))
247 fragment.write_enumeration(named_bit_list)
249 fragment.pop_indent()
250 fragment.write_line(')')
252 fragment.write_line('pass')
256 def expr_sequenceof_type(self, t):
257 return 'univ.SequenceOf(componentType=%s)' % self.generate_expr(t.type_decl)
259 def decl_sequenceof_type(self, t):
260 return 'componentType = %s' % self.generate_expr(t.type_decl)
262 def expr_setof_type(self, t):
263 return 'univ.SetOf(componentType=%s)' % self.generate_expr(t.type_decl)
265 def decl_setof_type(self, t):
266 return 'componentType = %s' % self.generate_expr(t.type_decl)
268 def decl_value_assignment(self, assignment):
269 assigned_value, type_decl, value = assignment.value_name, assignment.type_decl, assignment.value
271 value_type = _translate_type(type_decl.type_name)
272 return '%s = %s(%s)' % (assigned_value, value_type, value)
275 def generate_pyasn1(sema_module, out_stream):
276 return Pyasn1Backend(sema_module, out_stream).generate_code()
279 # Translation tables from ASN.1 primitives to pyasn1 primitives
280 _ASN1_TAG_CONTEXTS = {
281 'APPLICATION': 'tag.tagClassApplication',
282 'PRIVATE': 'tag.tagClassPrivate',
283 'UNIVERSAL': 'tag.tagClassUniversal'
287 _ASN1_BUILTIN_VALUES = {
293 _ASN1_BUILTIN_TYPES = {
294 'INTEGER': 'univ.Integer',
295 'BOOLEAN': 'univ.Boolean',
297 'ENUMERATED': 'univ.Enumerated',
299 'BIT STRING': 'univ.BitString',
300 'OCTET STRING': 'univ.OctetString',
301 'CHOICE': 'univ.Choice',
302 'SEQUENCE': 'univ.Sequence',
304 'SEQUENCE OF': 'univ.SequenceOf',
305 'SET OF': 'univ.SetOf',
306 'UTF8String': 'char.UTF8String',
307 'OBJECT IDENTIFIER': 'univ.ObjectIdentifier'
311 def _translate_type(type_name):
312 """ Translate ASN.1 built-in types to pyasn1 equivalents.
313 Non-builtins are not translated.
315 return _ASN1_BUILTIN_TYPES.get(type_name, type_name)
318 def _translate_tag_class(tag_class):
319 """ Translate ASN.1 tag class names to pyasn1 equivalents.
320 Defaults to tag.tagClassContext if tag_class is not
323 return _ASN1_TAG_CONTEXTS.get(tag_class, 'tag.tagClassContext')
326 def _translate_value(value):
327 """ Translate ASN.1 built-in values to Python equivalents.
328 Unrecognized values are not translated.
330 return _ASN1_BUILTIN_VALUES.get(value, value)
333 # Simplistic command-line driver
335 with open(args[0]) as f:
338 parse_tree = parser.parse_asn1(asn1def)
340 modules = build_semantic_model(parse_tree)
342 print('WARNING: More than one module generated to the same stream.', file=sys.stderr)
344 for module in modules:
345 print(pygen.auto_generated_header())
346 generate_pyasn1(module, sys.stdout)
351 if __name__ == '__main__':
352 sys.exit(main(sys.argv[1:]))