Make SingleValueConstraint accept alternatives
authorKim Gräsman <kim.grasman@gmail.com>
Sun, 9 Jun 2019 12:51:13 +0000 (14:51 +0200)
committerKim Gräsman <kim.grasman@gmail.com>
Sun, 9 Jun 2019 12:51:13 +0000 (14:51 +0200)
SingleValueConstraint can describe a set of valid values, not
necessarily just one.

This is not strictly correct -- the "|" token is used to create a UNION
constraint composed of multiple other constraints of different types, so
e.g. (1 | a | 6..10) is valid ASN.1, but not accepted by asn1ate.

When proper combined constraints are implemented, this should fall out
nicely and just work, but for now, support a common scenario with more
than one SingleValue.

asn1ate/parser.py
asn1ate/pyasn1gen.py
asn1ate/sema.py
testdata/single_value_constraint.asn

index 7b0012ff673b2cf542d36393e307341f39448b8a..4fd341e42945040bbfb767bc2744c813171bc8d0 100644 (file)
@@ -239,7 +239,8 @@ def _build_asn1_grammar():
     # todo: consider the full subtype and general constraint syntax described in 45.*
     lower_bound = (constraint_real_value | signed_number | referenced_value | MIN)
     upper_bound = (constraint_real_value | signed_number | referenced_value | MAX)
-    single_value_constraint = Suppress('(') + value + Suppress(')')
+
+    single_value_constraint = Suppress('(') + Group(delimitedList(value, delim='|')) + Suppress(')')
     value_range_constraint = Suppress('(') + lower_bound + Suppress('..') + upper_bound + Suppress(')')
     # TODO: Include contained subtype constraint here if we ever implement it.
     size_constraint = Optional(Suppress('(')) + Suppress(SIZE) + (single_value_constraint | value_range_constraint) + Optional(Suppress(')'))
index 6b77cd3f385d13957e8bc588a5bba8f711c1e1dd..30bc56b6960df676e041a9b71bcc6c0690aa1026 100755 (executable)
@@ -364,14 +364,14 @@ class Pyasn1Backend(object):
     def build_constraint_expr(self, constraint):
         def unpack_size_constraint(nested):
             if isinstance(nested, SingleValueConstraint):
-                return self.translate_value(nested.value), self.translate_value(nested.value)
+                return self.translate_value(nested.values[0]), self.translate_value(nested.values[0])
             elif isinstance(nested, ValueRangeConstraint):
                 return self.translate_value(nested.min_value), self.translate_value(nested.max_value)
             else:
                 raise Exception('Unrecognized nested size constraint type: %s' % nested.__class__.__name__)
 
         if isinstance(constraint, SingleValueConstraint):
-            return 'constraint.SingleValueConstraint(%s)' % (self.translate_value(constraint.value))
+            return 'constraint.SingleValueConstraint(%s)' % ', '.join(self.translate_value(v) for v in constraint.values)
         elif isinstance(constraint, SizeConstraint):
             min_value, max_value = unpack_size_constraint(constraint.nested)
             return 'constraint.ValueSizeConstraint(%s, %s)' % (self.translate_value(min_value), self.translate_value(max_value))
index 35270b251afeca3abcb9135935d483318605d4f9..06687a7bceb13fa0a66aec04b88afddb35d0d0c6 100644 (file)
@@ -672,10 +672,10 @@ class ReferencedValue(SemaNode):
 
 class SingleValueConstraint(SemaNode):
     def __init__(self, elements):
-        self.value = _maybe_create_sema_node(elements[0])
+        self.values = [_maybe_create_sema_node(e) for e in elements[0]]
 
     def __str__(self):
-        return '(%s)' % self.value
+        return '(%s)' % ' | '.join(map(str, self.values))
 
     __repr__ = __str__
 
index 427d8cd45de9ecb0b160104805e612ee2d45b9c3..50177c156e40bc53ff0e68d8f1ae757e97223a11 100644 (file)
@@ -6,6 +6,7 @@ BEGIN
   ConstrainedInteger1 ::= INTEGER (50)
   ConstrainedInteger2 ::= INTEGER (value)
   ConstrainedInteger3 ::= INTEGER { one(10), two(20) } (10)
+  ConstrainedInteger4 ::= INTEGER (100 | 50 | 25)
 
   ConstrainedBitString1 ::= BIT STRING { one(1), two(2) } (1)
 
@@ -13,6 +14,7 @@ BEGIN
   ConstrainedReal1 ::= REAL (2.73)
   ConstrainedReal2 ::= REAL (realValue)
   ConstrainedReal3 ::= REAL (4E9)
+  ConstrainedReal4 ::= REAL (2.73 | 3.14 | 1.23)
 
   Alias ::= OCTET STRING
   ConstrainedAlias ::= Alias (SIZE(8))