コード例 #1
0
 def test_constant_none_value_of_operator_and_with_missing_value(self):
     self.assertIsNone(
         ir_util.constant_value(_parse_expression("true && foo"),
                                {"bar": 12}))
     self.assertIsNone(
         ir_util.constant_value(_parse_expression("foo && true"),
                                {"bar": 12}))
コード例 #2
0
ファイル: expression_bounds.py プロジェクト: reventlov/emboss
def _compute_constraints_of_field_reference(expression, ir):
    """Computes the constraints of a reference to a structure's field."""
    field_path = expression.field_reference.path[-1]
    field = ir_util.find_object(field_path, ir)
    if isinstance(field, ir_pb2.Field) and ir_util.field_is_virtual(field):
        # References to virtual fields should have the virtual field's constraints
        # copied over.
        compute_constraints_of_expression(field.read_transform, ir)
        expression.type.CopyFrom(field.read_transform.type)
        return
    # Non-virtual non-integer fields do not (yet) have constraints.
    if expression.type.WhichOneof("type") == "integer":
        # TODO(bolms): These lines will need to change when support is added for
        # fixed-point types.
        expression.type.integer.modulus = "1"
        expression.type.integer.modular_value = "0"
        type_definition = ir_util.find_parent_object(field_path, ir)
        if isinstance(field, ir_pb2.Field):
            referrent_type = field.type
        else:
            referrent_type = field.physical_type_alias
        if referrent_type.HasField("size_in_bits"):
            type_size = ir_util.constant_value(referrent_type.size_in_bits)
        else:
            field_size = ir_util.constant_value(field.location.size)
            if field_size is None:
                type_size = None
            else:
                type_size = field_size * type_definition.addressable_unit
        assert referrent_type.HasField("atomic_type"), field
        assert not referrent_type.atomic_type.reference.canonical_name.module_file
        _set_integer_constraints_from_physical_type(expression, referrent_type,
                                                    type_size)
コード例 #3
0
 def test_constant_none_value_of_operator_or_with_missing_value(self):
     self.assertIsNone(
         ir_util.constant_value(_parse_expression("foo || false"),
                                {"bar": 12}))
     self.assertIsNone(
         ir_util.constant_value(_parse_expression("false || foo"),
                                {"bar": 12}))
コード例 #4
0
 def test_constant_value_of_maximum(self):
     self.assertEqual(
         10, ir_util.constant_value(_parse_expression("$max(5, 10)")))
     self.assertEqual(10,
                      ir_util.constant_value(_parse_expression("$max(10)")))
     self.assertEqual(
         10,
         ir_util.constant_value(
             _parse_expression("$max(5, 9, 7, 10, 6, -100)")))
コード例 #5
0
 def test_constant_false_value_of_operator_and_with_missing_value(self):
     self.assertIs(
         False,
         ir_util.constant_value(_parse_expression("false && foo"),
                                {"bar": 12}))
     self.assertIs(
         False,
         ir_util.constant_value(_parse_expression("foo && false"),
                                {"bar": 12}))
コード例 #6
0
 def test_adds_fixed_size_attribute_to_anonymous_bits(self):
     struct_ir = _make_ir_from_emb('[$default byte_order: "LittleEndian"]\n'
                                   "struct Foo:\n"
                                   "  0 [+4]  bits:\n"
                                   "    0 [+8]  UInt  field\n")
     self.assertEqual([], attribute_checker.normalize_and_verify(struct_ir))
     size_attr = ir_util.get_attribute(
         struct_ir.module[0].type[0].attribute, _FIXED_SIZE)
     self.assertEqual(32, ir_util.constant_value(size_attr.expression))
     bits_size_attr = ir_util.get_attribute(
         struct_ir.module[0].type[0].subtype[0].attribute, _FIXED_SIZE)
     self.assertEqual(8, ir_util.constant_value(bits_size_attr.expression))
     self.assertEqual(struct_ir.module[0].type[0].source_location,
                      size_attr.source_location)
コード例 #7
0
def _check_that_enum_values_are_representable(enum_type, source_file_name,
                                              errors):
    """Checks that enumeration values can fit in an int64 or uint64."""
    values = []
    for value in enum_type.value:
        values.append((ir_util.constant_value(value.value), value))
    # Guess if the user intended a signed or unsigned enumeration based on how
    # many values would be out of range given either type.
    signed_out_of_range = [
        v for v in values if not -2**63 <= v[0] <= 2**63 - 1
    ]
    unsigned_out_of_range = [v for v in values if not 0 <= v[0] <= 2**64 - 1]
    if len(signed_out_of_range) < len(unsigned_out_of_range):
        out_of_range = signed_out_of_range
        range_name = "signed "
    else:
        out_of_range = unsigned_out_of_range
        range_name = "unsigned "
    # If all values are in range for either a signed or an unsigned enumeration,
    # this loop will have zero iterations.
    for value in out_of_range:
        errors.append([
            error.error(
                source_file_name, value[1].value.source_location,
                "Value {} is out of range for {}enumeration.".format(
                    value[0],
                    range_name if -2**63 <= value[0] <= 2**64 - 1 else ""))
        ])
コード例 #8
0
def _check_type_requirements_for_parameter_type(runtime_parameter, ir,
                                                source_file_name, errors):
    """Checks that the type of a parameter is valid."""
    physical_type = runtime_parameter.physical_type_alias
    logical_type = runtime_parameter.type
    size = ir_util.constant_value(physical_type.size_in_bits)
    if logical_type.WhichOneof("type") == "integer":
        integer_errors = _integer_bounds_errors(logical_type.integer,
                                                "parameter", source_file_name,
                                                physical_type.source_location)
        if integer_errors:
            errors.extend(integer_errors)
            return
        errors.extend(
            _check_physical_type_requirements(
                physical_type, runtime_parameter.source_location, size, ir,
                source_file_name))
    elif logical_type.WhichOneof("type") == "enumeration":
        if physical_type.HasField("size_in_bits"):
            # This seems a little weird: for `UInt`, `Int`, etc., the explicit size is
            # required, but for enums it is banned.  This is because enums have a
            # "native" 64-bit size in expressions, so the physical size is just
            # ignored.
            errors.extend([[
                error.error(
                    source_file_name,
                    physical_type.size_in_bits.source_location,
                    "Parameters with enum type may not have explicit size.")
            ]])
    else:
        assert False, "Non-integer/enum parameters should have been caught earlier."
コード例 #9
0
 def test_constant_value_of_builtin_reference(self):
     self.assertEqual(
         12,
         ir_util.constant_value(
             ir_pb2.Expression(builtin_reference=ir_pb2.Reference(
                 canonical_name=ir_pb2.CanonicalName(
                     object_path=["$foo"]))), {"$foo": 12}))
コード例 #10
0
 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)))))
コード例 #11
0
def _check_that_array_base_types_in_structs_are_multiples_of_bytes(
        type_ir, type_definition, source_file_name, errors, ir):
    # TODO(bolms): Remove this limitation.
    """Checks that the sizes of array elements are multiples of 8 bits."""
    if type_ir.base_type.HasField("array_type"):
        # Only check the innermost array for multidimensional arrays.
        return
    assert type_ir.base_type.HasField("atomic_type")
    if type_ir.base_type.HasField("size_in_bits"):
        assert ir_util.is_constant(type_ir.base_type.size_in_bits)
        base_type_size = ir_util.constant_value(type_ir.base_type.size_in_bits)
    else:
        fixed_size = ir_util.fixed_size_of_type_in_bits(type_ir.base_type, ir)
        if fixed_size is None:
            # Variable-sized elements are checked elsewhere.
            return
        base_type_size = fixed_size
    if base_type_size % type_definition.addressable_unit != 0:
        assert type_definition.addressable_unit == ir_pb2.TypeDefinition.BYTE
        errors.append([
            error.error(
                source_file_name, type_ir.base_type.source_location,
                "Array elements in structs must have sizes "
                "which are a multiple of 8 bits.")
        ])
コード例 #12
0
 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")))))
コード例 #13
0
 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")))))
コード例 #14
0
def _verify_size_attributes_on_structure(struct, type_definition,
                                         source_file_name, errors):
  """Verifies size attributes on a struct or bits."""
  fixed_size = _fixed_size_of_struct_or_bits(struct,
                                             type_definition.addressable_unit)
  fixed_size_attr = ir_util.get_attribute(type_definition.attribute,
                                          attributes.FIXED_SIZE)
  if not fixed_size_attr:
    return
  if fixed_size is None:
    errors.append([error.error(
        source_file_name, fixed_size_attr.source_location,
        "Struct is marked as fixed size, but contains variable-location "
        "fields.")])
  elif ir_util.constant_value(fixed_size_attr.expression) != fixed_size:
    errors.append([error.error(
        source_file_name, fixed_size_attr.source_location,
        "Struct is {} bits, but is marked as {} bits.".format(
            fixed_size, ir_util.constant_value(fixed_size_attr.expression)))])
コード例 #15
0
 def test_accepts_correct_size_attribute_on_struct(self):
     struct_ir = _make_ir_from_emb('[$default byte_order: "LittleEndian"]\n'
                                   "struct Foo:\n"
                                   "  [fixed_size_in_bits: 64]\n"
                                   "  0 [+2]  UInt  field1\n"
                                   "  4 [+4]  UInt  field3\n")
     self.assertEqual([], attribute_checker.normalize_and_verify(struct_ir))
     size_attr = ir_util.get_attribute(
         struct_ir.module[0].type[0].attribute, _FIXED_SIZE)
     self.assertTrue(size_attr.expression)
     self.assertEqual(64, ir_util.constant_value(size_attr.expression))
コード例 #16
0
def _render_type(type_ir, ir):
    """Returns the human-readable notation of the given type."""
    assert type_ir.HasField("atomic_type"), (
        "TODO(bolms): Implement _render_type for array types.")
    if type_ir.HasField("size_in_bits"):
        return _render_atomic_type_name(
            type_ir,
            ir,
            suffix=":" + str(ir_util.constant_value(type_ir.size_in_bits)))
    else:
        return _render_atomic_type_name(type_ir, ir)
コード例 #17
0
def _fixed_size_of_struct_or_bits(struct, unit_size):
  """Returns size of struct in bits or None, if struct is not fixed size."""
  size = 0
  for field in struct.field:
    if not field.HasField("location"):
      # Virtual fields do not contribute to the physical size of the struct.
      continue
    field_start = ir_util.constant_value(field.location.start)
    field_size = ir_util.constant_value(field.location.size)
    if field_start is None or field_size is None:
      # Technically, start + size could be constant even if start and size are
      # not; e.g. if start == x and size == 10 - x, but we don't handle that
      # here.
      return None
      # TODO(bolms): knows_own_size
      # TODO(bolms): compute min/max sizes for variable-sized arrays.
    field_end = field_start + field_size
    if field_end >= size:
      size = field_end
  return size * unit_size
コード例 #18
0
 def test_adds_fixed_size_attribute_to_struct_with_virtual_field(self):
     struct_ir = _make_ir_from_emb('[$default byte_order: "LittleEndian"]\n'
                                   "struct Foo:\n"
                                   "  0 [+2]  UInt  field1\n"
                                   "  let field2 = field1\n"
                                   "  2 [+2]  UInt  field3\n")
     self.assertEqual([], attribute_checker.normalize_and_verify(struct_ir))
     size_attr = ir_util.get_attribute(
         struct_ir.module[0].type[0].attribute, _FIXED_SIZE)
     self.assertEqual(32, ir_util.constant_value(size_attr.expression))
     self.assertEqual(struct_ir.module[0].type[0].source_location,
                      size_attr.source_location)
コード例 #19
0
def _field_may_have_null_byte_order(field, type_definition, ir):
  """Returns true if "Null" is a valid byte order for the given field."""
  # If the field is one unit in length, then byte order does not matter.
  if (ir_util.is_constant(field.location.size) and
      ir_util.constant_value(field.location.size) == 1):
    return True
  unit = type_definition.addressable_unit
  # Otherwise, if the field's type is either a one-unit-sized type or an array
  # of a one-unit-sized type, then byte order does not matter.
  if (ir_util.fixed_size_of_type_in_bits(ir_util.get_base_type(field.type), ir)
      == unit):
    return True
  # In all other cases, byte order does matter.
  return False
コード例 #20
0
 def test_adds_fixed_size_attribute_to_struct(self):
     # field2 is intentionally after field3, in order to trigger certain code
     # paths in attribute_checker.py.
     struct_ir = _make_ir_from_emb('[$default byte_order: "LittleEndian"]\n'
                                   "struct Foo:\n"
                                   "  0 [+2]  UInt  field1\n"
                                   "  4 [+4]  UInt  field2\n"
                                   "  2 [+2]  UInt  field3\n")
     self.assertEqual([], attribute_checker.normalize_and_verify(struct_ir))
     size_attr = ir_util.get_attribute(
         struct_ir.module[0].type[0].attribute, _FIXED_SIZE)
     self.assertEqual(64, ir_util.constant_value(size_attr.expression))
     self.assertEqual(struct_ir.module[0].type[0].source_location,
                      size_attr.source_location)
コード例 #21
0
def _check_physical_type_requirements(type_ir, usage_source_location, size, ir,
                                      source_file_name):
    """Checks that the given atomic `type_ir` is allowed to be `size` bits."""
    referenced_type_definition = ir_util.find_object(
        type_ir.atomic_type.reference, ir)
    # TODO(bolms): replace this with a check against an automatically-generated
    # `static_requirements` attribute on enum types.  (The main problem is that
    # the generated attribute would have no source text, so there would be a crash
    # when trying to display the error.)
    if referenced_type_definition.HasField("enumeration"):
        if size is None:
            return [[
                error.error(
                    source_file_name, type_ir.source_location,
                    "Enumeration {} cannot be placed in a dynamically-sized "
                    "field.".format(_render_type(type_ir, ir)))
            ]]
        elif size < 1 or size > 64:
            return [[
                error.error(
                    source_file_name, type_ir.source_location,
                    "Enumeration {} cannot be {} bits; enumerations must be between "
                    "1 and 64 bits, inclusive.".format(
                        _render_atomic_type_name(type_ir, ir), size))
            ]]

    if size is None:
        bindings = {"$is_statically_sized": False}
    else:
        bindings = {"$is_statically_sized": True, "$static_size_in_bits": size}
    requires_attr = ir_util.get_attribute(referenced_type_definition.attribute,
                                          attributes.STATIC_REQUIREMENTS)
    if requires_attr and not ir_util.constant_value(requires_attr.expression,
                                                    bindings):
        # TODO(bolms): Figure out a better way to build this error message.
        # The "Requirements specified here." message should print out the actual
        # source text of the requires attribute, so that should help, but it's still
        # a bit generic and unfriendly.
        return [[
            error.error(
                source_file_name, usage_source_location,
                "Requirements of {} not met.".format(
                    type_ir.atomic_type.reference.canonical_name.
                    object_path[-1])),
            error.note(
                type_ir.atomic_type.reference.canonical_name.module_file,
                requires_attr.source_location, "Requirements specified here.")
        ]]
    return []
コード例 #22
0
ファイル: expression_bounds.py プロジェクト: reventlov/emboss
def _compute_constant_value_of_constant_reference(expression, ir):
    referred_object = ir_util.find_object(
        expression.constant_reference.canonical_name, ir)
    if isinstance(referred_object, ir_pb2.EnumValue):
        compute_constraints_of_expression(referred_object.value, ir)
        assert ir_util.is_constant(referred_object.value)
        new_value = str(ir_util.constant_value(referred_object.value))
        expression.type.enumeration.value = new_value
    elif isinstance(referred_object, ir_pb2.Field):
        assert ir_util.field_is_virtual(referred_object), (
            "Non-virtual non-enum-value constant reference should have been caught "
            "in type_check.py")
        compute_constraints_of_expression(referred_object.read_transform, ir)
        expression.type.CopyFrom(referred_object.read_transform.type)
    else:
        assert False, "Unexpected constant reference type."
コード例 #23
0
ファイル: expression_bounds.py プロジェクト: reventlov/emboss
def _compute_constant_value_of_comparison_operator(expression):
    """Computes the constant value, if any, of a comparison operator."""
    args = expression.function.args
    if all(ir_util.is_constant(arg) for arg in args):
        functions = {
            ir_pb2.Function.EQUALITY: operator.eq,
            ir_pb2.Function.INEQUALITY: operator.ne,
            ir_pb2.Function.LESS: operator.lt,
            ir_pb2.Function.LESS_OR_EQUAL: operator.le,
            ir_pb2.Function.GREATER: operator.gt,
            ir_pb2.Function.GREATER_OR_EQUAL: operator.ge,
            ir_pb2.Function.AND: operator.and_,
            ir_pb2.Function.OR: operator.or_,
        }
        func = functions[expression.function.function]
        expression.type.boolean.value = func(
            *[ir_util.constant_value(arg) for arg in args])
コード例 #24
0
ファイル: attribute_checker.py プロジェクト: reventlov/emboss
def _add_missing_width_and_sign_attributes_on_enum(enum, type_definition):
  """Sets the maximum_bits and is_signed attributes for an enum, if needed."""
  max_bits_attr = ir_util.get_integer_attribute(type_definition.attribute,
                                                attributes.ENUM_MAXIMUM_BITS)
  if max_bits_attr is None:
    type_definition.attribute.extend([
        _construct_integer_attribute(attributes.ENUM_MAXIMUM_BITS,
                                     _DEFAULT_ENUM_MAXIMUM_BITS,
                                     type_definition.source_location)])
  signed_attr = ir_util.get_boolean_attribute(type_definition.attribute,
                                              attributes.IS_SIGNED)
  if signed_attr is None:
    for value in enum.value:
      numeric_value = ir_util.constant_value(value.value)
      if numeric_value < 0:
        is_signed = True
        break
    else:
      is_signed = False
    type_definition.attribute.extend([
        _construct_boolean_attribute(attributes.IS_SIGNED, is_signed,
                                     type_definition.source_location)])
コード例 #25
0
 def test_constant_value_of_subtraction(self):
     self.assertEqual(-2, ir_util.constant_value(_parse_expression("2-4")))
コード例 #26
0
 def test_constant_value_of_integer(self):
     self.assertEqual(6, ir_util.constant_value(_parse_expression("6")))
コード例 #27
0
 def test_constant_value_of_none(self):
     self.assertIsNone(ir_util.constant_value(ir_pb2.Expression()))
コード例 #28
0
 def test_constant_value_of_addition(self):
     self.assertEqual(6, ir_util.constant_value(_parse_expression("2+4")))
コード例 #29
0
def _field_size(field, type_definition):
    """Calculates the size of the given field in bits, if it is constant."""
    size = ir_util.constant_value(field.location.size)
    if size is None:
        return None
    return size * type_definition.addressable_unit
コード例 #30
0
def _check_type_requirements_for_field(type_ir, type_definition, field, ir,
                                       source_file_name, errors):
    """Checks that the `requires` attribute of each field's type is fulfilled."""
    if not type_ir.HasField("atomic_type"):
        return

    if field.type.HasField("atomic_type"):
        field_min_size = (int(field.location.size.type.integer.minimum_value) *
                          type_definition.addressable_unit)
        field_max_size = (int(field.location.size.type.integer.maximum_value) *
                          type_definition.addressable_unit)
        field_is_atomic = True
    else:
        field_is_atomic = False

    if type_ir.HasField("size_in_bits"):
        element_size = ir_util.constant_value(type_ir.size_in_bits)
    else:
        element_size = None

    referenced_type_definition = ir_util.find_object(
        type_ir.atomic_type.reference, ir)
    type_is_anonymous = referenced_type_definition.name.is_anonymous
    type_size_attr = ir_util.get_attribute(
        referenced_type_definition.attribute, attributes.FIXED_SIZE)
    if type_size_attr:
        type_size = ir_util.constant_value(type_size_attr.expression)
    else:
        type_size = None

    if (element_size is not None and type_size is not None
            and element_size != type_size):
        errors.append([
            error.error(
                source_file_name, type_ir.size_in_bits.source_location,
                "Explicit size of {} bits does not match fixed size ({} bits) of "
                "{}.".format(element_size, type_size,
                             _render_atomic_type_name(type_ir, ir))),
            error.note(
                type_ir.atomic_type.reference.canonical_name.module_file,
                type_size_attr.source_location, "Size specified here.")
        ])
        return

    # If the type had no size specifier (the ':32' in 'UInt:32'), but the type is
    # fixed size, then continue as if the type's size were explicitly stated.
    if element_size is None:
        element_size = type_size

    # TODO(bolms): When the full dynamic size expression for types is generated,
    # add a check that dynamically-sized types can, at least potentially, fit in
    # their fields.

    if field_is_atomic and element_size is not None:
        # If the field has a fixed size, and the (atomic) type contained therein is
        # also fixed size, then the sizes should match.
        #
        # TODO(bolms): Maybe change the case where the field is bigger than
        # necessary into a warning?
        if (field_max_size == field_min_size and
            (element_size > field_max_size or
             (element_size < field_min_size and not type_is_anonymous))):
            errors.append([
                error.error(
                    source_file_name, type_ir.source_location,
                    "Fixed-size {} cannot be placed in field of size {} bits; "
                    "requires {} bits.".format(_render_type(type_ir, ir),
                                               field_max_size, element_size))
            ])
            return
        elif element_size > field_max_size:
            errors.append([
                error.error(
                    source_file_name, type_ir.source_location,
                    "Field of maximum size {} bits cannot hold fixed-size {}, which "
                    "requires {} bits.".format(field_max_size,
                                               _render_type(type_ir, ir),
                                               element_size))
            ])
            return

    # If we're here, then field/type sizes are consistent.
    if (element_size is None and field_is_atomic
            and field_min_size == field_max_size):
        # From here down, we just use element_size.
        element_size = field_min_size

    errors.extend(
        _check_physical_type_requirements(type_ir, field.source_location,
                                          element_size, ir, source_file_name))