def unbounded_expression_type_for_physical_type(type_definition): """Gets the ExpressionType for a field of the given TypeDefinition. Arguments: type_definition: an ir_pb2.TypeDefinition. Returns: An ir_pb2.ExpressionType with the corresponding expression type filled in: for example, [prelude].UInt will result in an ExpressionType with the `integer` field filled in. The returned ExpressionType will not have any bounds set. """ # TODO(bolms): Add a `[value_type]` attribute for `external`s. if ir_util.get_boolean_attribute(type_definition.attribute, attributes.IS_INTEGER): return ir_pb2.ExpressionType(integer=ir_pb2.IntegerType()) elif tuple(type_definition.name.canonical_name.object_path) == ("Flag", ): # This is a hack: the Flag type should say that it is a boolean. return ir_pb2.ExpressionType(boolean=ir_pb2.BooleanType()) elif type_definition.HasField("enumeration"): return ir_pb2.ExpressionType(enumeration=ir_pb2.EnumType( name=ir_pb2.Reference( canonical_name=type_definition.name.canonical_name))) else: return ir_pb2.ExpressionType(opaque=ir_pb2.OpaqueType())
def test_is_constant_enumeration_type(self): self.assertFalse( ir_util.is_constant_type( ir_pb2.ExpressionType(enumeration=ir_pb2.EnumType()))) self.assertTrue( ir_util.is_constant_type( ir_pb2.ExpressionType(enumeration=ir_pb2.EnumType(value="0"))))
def test_is_constant_boolean_type(self): self.assertFalse( ir_util.is_constant_type( ir_pb2.ExpressionType(boolean=ir_pb2.BooleanType()))) self.assertTrue( ir_util.is_constant_type( ir_pb2.ExpressionType(boolean=ir_pb2.BooleanType(value=True)))) self.assertTrue( ir_util.is_constant_type( ir_pb2.ExpressionType(boolean=ir_pb2.BooleanType( value=False))))
def test_is_constant_integer_type(self): self.assertFalse( ir_util.is_constant_type( ir_pb2.ExpressionType( integer=ir_pb2.IntegerType(modulus="10", modular_value="5", minimum_value="-5", maximum_value="15")))) self.assertTrue( ir_util.is_constant_type( ir_pb2.ExpressionType( integer=ir_pb2.IntegerType(modulus="infinity", modular_value="5", minimum_value="5", maximum_value="5"))))
def test_is_constant_enum(self): self.assertTrue( ir_util.is_constant( ir_pb2.Expression( constant_reference=ir_pb2.Reference(), type=ir_pb2.ExpressionType(enumeration=ir_pb2.EnumType( value="12")))))
def test_constant_value_of_boolean_reference(self): self.assertTrue( ir_util.constant_value( ir_pb2.Expression( constant_reference=ir_pb2.Reference(), type=ir_pb2.ExpressionType(boolean=ir_pb2.BooleanType( value=True)))))
def test_constant_value_of_integer_reference(self): self.assertEqual( 12, ir_util.constant_value( ir_pb2.Expression( constant_reference=ir_pb2.Reference(), type=ir_pb2.ExpressionType(integer=ir_pb2.IntegerType( modulus="infinity", modular_value="12")))))
def test_constant_value_of_enum(self): self.assertEqual( 12, ir_util.constant_value( ir_pb2.Expression( constant_reference=ir_pb2.Reference(), type=ir_pb2.ExpressionType(enumeration=ir_pb2.EnumType( value="12")))))
def _construct_boolean_attribute(name, value, source_location): """Constructs a boolean Attribute with the given name and value.""" attr_value = ir_pb2.AttributeValue( expression=ir_pb2.Expression( boolean_constant=ir_pb2.BooleanConstant( value=value, source_location=source_location), type=ir_pb2.ExpressionType(boolean=ir_pb2.BooleanType(value=value)), source_location=source_location), source_location=source_location) return ir_pb2.Attribute(name=ir_pb2.Word(text=name, source_location=source_location), value=attr_value, source_location=source_location)
def _construct_integer_attribute(name, value, source_location): """Constructs an integer Attribute with the given name and value.""" attr_value = ir_pb2.AttributeValue( expression=ir_pb2.Expression( constant=ir_pb2.NumericConstant(value=str(value), source_location=source_location), type=ir_pb2.ExpressionType( integer=ir_pb2.IntegerType(modular_value=str(value), modulus="infinity", minimum_value=str(value), maximum_value=str(value))), source_location=source_location), source_location=source_location) return ir_pb2.Attribute(name=ir_pb2.Word(text=name), value=attr_value, source_location=source_location)
def test_is_constant_opaque_type(self): self.assertFalse( ir_util.is_constant_type( ir_pb2.ExpressionType(opaque=ir_pb2.OpaqueType())))
def test_get_integer_attribute(self): type_def = ir_pb2.TypeDefinition(attribute=[ ir_pb2.Attribute(value=ir_pb2.AttributeValue( expression=ir_pb2.Expression(type=ir_pb2.ExpressionType( integer=ir_pb2.IntegerType()))), name=ir_pb2.Word(text="phil")), ir_pb2.Attribute(value=ir_pb2.AttributeValue( expression=ir_pb2.Expression( constant=ir_pb2.NumericConstant(value="20"), type=ir_pb2.ExpressionType(integer=ir_pb2.IntegerType( modular_value="20", modulus="infinity")))), name=ir_pb2.Word(text="bob"), is_default=True), ir_pb2.Attribute(value=ir_pb2.AttributeValue( expression=ir_pb2.Expression( constant=ir_pb2.NumericConstant(value="10"), type=ir_pb2.ExpressionType(integer=ir_pb2.IntegerType( modular_value="10", modulus="infinity")))), name=ir_pb2.Word(text="bob")), ir_pb2.Attribute(value=ir_pb2.AttributeValue( expression=ir_pb2.Expression( constant=ir_pb2.NumericConstant(value="5"), type=ir_pb2.ExpressionType(integer=ir_pb2.IntegerType( modular_value="5", modulus="infinity")))), name=ir_pb2.Word(text="bob2")), ir_pb2.Attribute(value=ir_pb2.AttributeValue( expression=ir_pb2.Expression( constant=ir_pb2.NumericConstant(value="0"), type=ir_pb2.ExpressionType(integer=ir_pb2.IntegerType( modular_value="0", modulus="infinity")))), name=ir_pb2.Word(text="bob2"), is_default=True), ir_pb2.Attribute(value=ir_pb2.AttributeValue( expression=ir_pb2.Expression( constant=ir_pb2.NumericConstant(value="30"), type=ir_pb2.ExpressionType(integer=ir_pb2.IntegerType( modular_value="30", modulus="infinity")))), name=ir_pb2.Word(text="bob3"), is_default=True), ir_pb2.Attribute(value=ir_pb2.AttributeValue( expression=ir_pb2.Expression(function=ir_pb2.Function( function=ir_pb2.Function.ADDITION, args=[ ir_pb2.Expression( constant=ir_pb2.NumericConstant(value="100"), type=ir_pb2.ExpressionType( integer=ir_pb2.IntegerType( modular_value="100", modulus="infinity"))), ir_pb2.Expression( constant=ir_pb2.NumericConstant(value="100"), type=ir_pb2.ExpressionType( integer=ir_pb2.IntegerType( modular_value="100", modulus="infinity"))) ]), type=ir_pb2.ExpressionType( integer=ir_pb2.IntegerType( modular_value="200", modulus="infinity")))), name=ir_pb2.Word(text="bob4")), ir_pb2.Attribute(value=ir_pb2.AttributeValue( expression=ir_pb2.Expression( constant=ir_pb2.NumericConstant(value="40"), type=ir_pb2.ExpressionType(integer=ir_pb2.IntegerType( modular_value="40", modulus="infinity")))), name=ir_pb2.Word()), ]) self.assertEqual( 10, ir_util.get_integer_attribute(type_def.attribute, "bob")) self.assertEqual( 5, ir_util.get_integer_attribute(type_def.attribute, "bob2")) self.assertIsNone( ir_util.get_integer_attribute(type_def.attribute, "Bob")) self.assertEqual( 10, ir_util.get_integer_attribute(type_def.attribute, "Bob", default_value=10)) self.assertIsNone( ir_util.get_integer_attribute(type_def.attribute, "bob3")) self.assertEqual( 200, ir_util.get_integer_attribute(type_def.attribute, "bob4"))
def _invert_expression(expression, ir): """For the given expression, searches for an algebraic inverse expression. That is, it takes the notional equation: $logical_value = expression and, if there is exactly one `field_reference` in `expression`, it will attempt to solve the equation for that field. For example, if the expression is `x + 1`, it will iteratively transform: $logical_value = x + 1 $logical_value - 1 = x + 1 - 1 $logical_value - 1 = x and finally return `x` and `$logical_value - 1`. The purpose of this transformation is to find an assignment statement that can be used to write back through certain virtual fields. E.g., given: struct Foo: 0 [+1] UInt raw_value let actual_value = raw_value + 100 it should be possible to write a value to the `actual_value` field, and have it set `raw_value` to the appropriate value. Arguments: expression: an ir_pb2.Expression to be inverted. ir: the full IR, for looking up symbols. Returns: (field_reference, inverse_expression) if expression can be inverted, otherwise None. """ reference_path = _find_field_reference_path(expression) if reference_path is None: return None subexpression = expression result = ir_pb2.Expression( builtin_reference=ir_pb2.Reference( canonical_name=ir_pb2.CanonicalName( module_file="", object_path=["$logical_value"] ), source_name=[ir_pb2.Word( text="$logical_value", source_location=ir_pb2.Location(is_synthetic=True) )], source_location=ir_pb2.Location(is_synthetic=True) ), type=expression.type, source_location=ir_pb2.Location(is_synthetic=True) ) # This loop essentially starts with: # # f(g(x)) == $logical_value # # and ends with # # x == g_inv(f_inv($logical_value)) # # At each step, `subexpression` has one layer removed, and `result` has a # corresponding inverse function applied. So, for example, it might start # with: # # 2 + ((3 - x) - 10) == $logical_value # # On each iteration, `subexpression` and `result` will become: # # (3 - x) - 10 == $logical_value - 2 [subtract 2 from both sides] # (3 - x) == ($logical_value - 2) + 10 [add 10 to both sides] # x == 3 - (($logical_value - 2) + 10) [subtract both sides from 3] # # This is an extremely limited algebraic solver, but it covers common-enough # cases. # # Note that any equation that can be solved here becomes part of Emboss's # contract, forever, so be conservative in expanding its solving capabilities! for index in reference_path: if subexpression.function.function == ir_pb2.Function.ADDITION: result = ir_pb2.Expression( function=ir_pb2.Function( function=ir_pb2.Function.SUBTRACTION, args=[ result, subexpression.function.args[1 - index], ] ), type=ir_pb2.ExpressionType(integer=ir_pb2.IntegerType()) ) elif subexpression.function.function == ir_pb2.Function.SUBTRACTION: if index == 0: result = ir_pb2.Expression( function=ir_pb2.Function( function=ir_pb2.Function.ADDITION, args=[ result, subexpression.function.args[1], ] ), type=ir_pb2.ExpressionType(integer=ir_pb2.IntegerType()) ) else: result = ir_pb2.Expression( function=ir_pb2.Function( function=ir_pb2.Function.SUBTRACTION, args=[ subexpression.function.args[0], result, ] ), type=ir_pb2.ExpressionType(integer=ir_pb2.IntegerType()) ) else: return None subexpression = subexpression.function.args[index] expression_bounds.compute_constraints_of_expression(result, ir) return subexpression, result