def test_checks_for_correct_explicit_size_on_parameters(self): ir = _make_ir_from_emb("struct Foo(y: UInt:300):\n" " 0 [+1] UInt x\n") error_parameter = ir.module[0].type[0].runtime_parameter[0] error_location = error_parameter.physical_type_alias.source_location self.assertEqual( [[error.error("m.emb", error_location, "Potential range of parameter is 0 to {}, which cannot " "fit in a 64-bit signed or unsigned integer.".format( 2**300-1))]], error.filter_errors(constraints.check_constraints(ir)))
def test_enum_value_too_wide_multiple_signed_error_message(self): ir = _make_ir_from_emb('[$default byte_order: "LittleEndian"]\n' "enum Foo:\n" " LOW = -3\n" " LOW2 = -2\n" " LOW3 = -1\n" " HIGH = 0x8000_0000_0000_0000\n" " HIGH2 = 0x8000_0000_0000_0001\n") error_value = ir.module[0].type[0].enumeration.value[3].value error_value2 = ir.module[0].type[0].enumeration.value[4].value self.assertEqual([ [error.error( "m.emb", error_value.source_location, "Value 9223372036854775808 is out of range for 64-bit signed " "enumeration.")], [error.error( "m.emb", error_value2.source_location, "Value 9223372036854775809 is out of range for 64-bit signed " "enumeration.")] ], error.filter_errors(constraints.check_constraints(ir)))
def test_explicit_non_byte_size_array_element(self): ir = _make_ir_from_emb('[$default byte_order: "LittleEndian"]\n' "struct Foo:\n" " 0 [+2] UInt:4[4] nibbles\n") error_type = ir.module[0].type[0].structure.field[0].type.array_type self.assertEqual([ [error.error( "m.emb", error_type.base_type.source_location, "Array elements in structs must have sizes which are a multiple of " "8 bits.")] ], error.filter_errors(constraints.check_constraints(ir)))
def test_enum_value_too_low(self): ir = _make_ir_from_emb('[$default byte_order: "LittleEndian"]\n' "enum Foo:\n" " LOW = -0x8000_0000_0000_0001\n") error_value = ir.module[0].type[0].enumeration.value[0].value self.assertEqual([ [error.error( "m.emb", error_value.source_location, "Value -9223372036854775809 is out of range for 64-bit signed " + "enumeration.")] ], constraints.check_constraints(ir))
def test_enum_value_too_wide_small_size_error_message(self): ir = _make_ir_from_emb('[$default byte_order: "LittleEndian"]\n' "enum Foo:\n" " [maximum_bits: 8]\n" " HIGH = 0x100\n") error_value = ir.module[0].type[0].enumeration.value[0].value self.assertEqual([[ error.error( "m.emb", error_value.source_location, "Value 256 is out of range for 8-bit unsigned enumeration.") ]], error.filter_errors(constraints.check_constraints(ir)))
def test_next_in_first_field(self): ir = self._make_ir("struct Foo:\n" " $next [+2] UInt:8[] a\n" " $next [+4] UInt b\n") struct = ir.module[0].type[0].structure self.assertEqual([[ error.error( "m.emb", struct.field[0].location.start.source_location, "`$next` may not be used in the first physical field of " + "a structure; perhaps you meant `0`?"), ]], synthetics.desugar(ir))
def test_next_in_size(self): ir = self._make_ir("struct Foo:\n" " 0 [+2] UInt:8[] a\n" " 1 [+$next] UInt b\n") struct = ir.module[0].type[0].structure self.assertEqual([[ error.error( "m.emb", struct.field[1].location.size.source_location, "`$next` may only be used in the start expression of a " + "physical field."), ]], synthetics.desugar(ir))
def _check_for_bad_next_keyword_in_size(expression, source_file_name, errors): if not expression.HasField("builtin_reference"): return if expression.builtin_reference.canonical_name.object_path[0] != "$next": return errors.append([ error.error( source_file_name, expression.source_location, "`$next` may only be used in the start expression of a " + "physical field.") ])
def test_disallows_null_byte_order_on_multibyte_array_elements(self): ir = _make_ir_from_emb("struct Foo:\n" " 0 [+4] UInt:16[] uint\n" ' [byte_order: "Null"]\n') byte_order = ir.module[0].type[0].structure.field[0].attribute[0] self.assertEqual([[ error.error( "m.emb", byte_order.value.source_location, "Attribute 'byte_order' may only be 'Null' for one-byte fields." ) ]], attribute_checker.normalize_and_verify(ir))
def test_disallows_unknown_byte_order(self): ir = _make_ir_from_emb("struct Foo:\n" " 0 [+2] UInt bar\n" ' [byte_order: "NoEndian"]\n') byte_order = ir.module[0].type[0].structure.field[0].attribute[0] self.assertEqual([[ error.error( "m.emb", byte_order.value.source_location, "Attribute 'byte_order' must be 'BigEndian' or 'LittleEndian' or " "'Null'.") ]], attribute_checker.normalize_and_verify(ir))
def test_error_non_fixed_size_inner_array_dimension(self): ir = _make_ir_from_emb("struct Foo:\n" " 0 [+1] UInt size\n" " 1 [+size] UInt:8[size-1][1] one_byte\n") error_array = ir.module[0].type[0].structure.field[1].type.array_type self.assertEqual([[ error.error( "m.emb", error_array.base_type.array_type.element_count.source_location, "Inner array dimensions must be constant.") ]], error.filter_errors(constraints.check_constraints(ir)))
def test_error_on_equality_mismatched_operands_bool_int(self): ir = self._make_ir("struct Foo:\n" " 0 [+1] UInt x\n" " 1 [+true==1] UInt:8[] y\n") expression = ir.module[0].type[0].structure.field[1].location.size self.assertEqual([[ error.error( "m.emb", expression.source_location, "Both arguments of operator '==' must have the same " "type.") ]], error.filter_errors(type_check.annotate_types(ir)))
def test_rejects_is_integer_with_non_constant_value(self): external_ir = _make_ir_from_emb( "external Foo:\n" " [is_integer: $static_size_in_bits == 1]\n" " [addressable_unit_size: 1]\n") external_type_ir = external_ir.module[0].type[0] self.assertEqual([[ error.error( "m.emb", external_type_ir.attribute[0].value.source_location, "Attribute 'is_integer' must have a constant boolean value.") ]], attribute_checker.normalize_and_verify(external_ir))
def test_enum_value_too_wide(self): ir = _make_ir_from_emb('[$default byte_order: "LittleEndian"]\n' "enum Foo:\n" " LOW = -1\n" " HIGH = 0x8000_0000_0000_0000\n") error_value = ir.module[0].type[0].enumeration.value[0].value self.assertEqual([[ error.error( "m.emb", error_value.source_location, "Value -1 is out of range for unsigned enumeration.") ]], error.filter_errors(constraints.check_constraints(ir)))
def test_error_on_integer_type_in_existence_condition(self): ir = self._make_ir("struct Foo:\n" " 0 [+1] UInt:8[] x\n" " if 1:\n" " 1 [+9] UInt:8[] y\n") expression = ir.module[0].type[0].structure.field[ 1].existence_condition self.assertEqual([[ error.error("m.emb", expression.source_location, "Existence condition must be a boolean.") ]], type_check.check_types(ir))
def test_error_on_bad_equality_left_operand(self): ir = self._make_ir("struct Foo:\n" " 0 [+1] UInt:8[] x\n" " 1 [+x==x] UInt:8[] y\n") expression = ir.module[0].type[0].structure.field[1].location.size self.assertEqual([[ error.error( "m.emb", expression.function.args[0].source_location, "Left argument of operator '==' must be an integer, " "boolean, or enum.") ]], error.filter_errors(type_check.annotate_types(ir)))
def test_lower_bound_wrong_argument_type(self): ir = self._make_ir("struct Foo:\n" " $lower_bound(Bar.XX) [+1] UInt:8[] x\n" "enum Bar:\n" " XX = 0\n") expression = ir.module[0].type[0].structure.field[0].location.start self.assertEqual([[ error.error( "m.emb", expression.function.args[0].source_location, "Argument 0 of function '$lower_bound' must be an integer.") ]], error.filter_errors(type_check.annotate_types(ir)))
def test_error_on_too_many_argument_has(self): ir = self._make_ir("struct Foo:\n" " if $present(y, y):\n" " 0 [+1] UInt x\n" " 1 [+1] UInt y\n") expression = ir.module[0].type[0].structure.field[ 0].existence_condition self.assertEqual([[ error.error("m.emb", expression.source_location, "Function '$present' requires exactly 1 argument.") ]], error.filter_errors(type_check.annotate_types(ir)))
def test_error_on_bad_choice_mismatched_operands(self): ir = self._make_ir("struct Foo:\n" " 0 [+1] UInt:8[] x\n" " 1 [+true ? 0 : true] UInt:8[] y\n") expression = ir.module[0].type[0].structure.field[1].location.size self.assertEqual([[ error.error( "m.emb", expression.source_location, "The if-true and if-false clauses of operator '?:' must " "have the same type.") ]], error.filter_errors(type_check.annotate_types(ir)))
def test_rejects_non_constant_attribute(self): ir = _make_ir_from_emb('[$default byte_order: "LittleEndian"]\n' "struct Foo:\n" " [fixed_size_in_bits: field1]\n" " 0 [+2] UInt field1\n") attr = ir.module[0].type[0].attribute[0] self.assertEqual([[ error.error( "m.emb", attr.value.source_location, "Attribute 'fixed_size_in_bits' must have a constant value.") ]], attribute_checker.normalize_and_verify(ir))
def test_rejects_duplicate_attribute(self): ir = _make_ir_from_emb("external Foo:\n" " [is_integer: true]\n" " [is_integer: true]\n") self.assertEqual([[ error.error("m.emb", ir.module[0].type[0].attribute[1].source_location, "Duplicate attribute 'is_integer'."), error.note("m.emb", ir.module[0].type[0].attribute[0].source_location, "Original attribute"), ]], attribute_checker.normalize_and_verify(ir))
def test_explicit_enumeration_size_too_big(self): ir = _make_ir_from_emb('[$default byte_order: "BigEndian"]\n' "struct Foo:\n" " 0 [+9] Bar seventy_two_bit\n" "enum Bar:\n" " BAZ = 0\n") error_type = ir.module[0].type[0].structure.field[0].type self.assertEqual([[ error.error("m.emb", error_type.source_location, "Enumeration type 'Bar' cannot be 72 bits; enumerations " "must be between 1 and 64 bits, inclusive."), ]], error.filter_errors(constraints.check_constraints(ir)))
def test_undersized_anonymous_bit_field(self): ir = _make_ir_from_emb('[$default byte_order: "LittleEndian"]\n' "struct Foo:\n" " 0 [+1] bits:\n" " 0 [+32] UInt field\n") error_type = ir.module[0].type[0].structure.field[0].type self.assertEqual([[ error.error( "m.emb", error_type.source_location, "Fixed-size anonymous type cannot be placed in field of size 8 " "bits; requires 32 bits.") ]], error.filter_errors(constraints.check_constraints(ir)))
def test_field_type_not_allowed_in_bits(self): ir = _make_ir_from_emb('[$default byte_order: "LittleEndian"]\n' "bits Foo:\n" " 0 [+16] Bar bar\n" "external Bar:\n" " [addressable_unit_size: 8]\n") error_type = ir.module[0].type[0].structure.field[0].type self.assertEqual([[ error.error( "m.emb", error_type.source_location, "Byte-oriented type 'Bar' cannot be used in a bits field.") ]], error.filter_errors(constraints.check_constraints(ir)))
def test_struct_field_too_big_for_type(self): ir = _make_ir_from_emb("struct Foo:\n" " 0 [+2] Byte double_byte\n" "struct Byte:\n" " 0 [+1] UInt b\n") error_type = ir.module[0].type[0].structure.field[0].type self.assertEqual([[ error.error( "m.emb", error_type.source_location, "Fixed-size type 'Byte' cannot be placed in field of size 16 bits; " "requires 8 bits.") ]], error.filter_errors(constraints.check_constraints(ir)))
def test_error_on_bad_choice_if_true_operand(self): ir = self._make_ir("struct Foo:\n" " 0 [+1] UInt:8[] x\n" " 1 [+true ? x : x] UInt:8[] y\n") expression = ir.module[0].type[0].structure.field[1].location.size if_true_arg = expression.function.args[1] self.assertEqual([[ error.error( "m.emb", if_true_arg.source_location, "If-true clause of operator '?:' must be an integer, " "boolean, or enum.") ]], error.filter_errors(type_check.annotate_types(ir)))
def test_rejects_requires_on_array(self): ir = _make_ir_from_emb("struct Foo:\n" " 0 [+4] UInt:8[] array\n" " [requires: false]\n") field_ir = ir.module[0].type[0].structure.field[0] self.assertEqual([[ error.error( "m.emb", field_ir.attribute[0].value.source_location, "Attribute 'requires' is only allowed on integer, " "enumeration, or boolean fields, not arrays."), error.note("m.emb", field_ir.type.source_location, "Field type."), ]], error.filter_errors(attribute_checker.normalize_and_verify(ir)))
def test_error_on_passing_unneeded_parameter(self): ir = self._make_ir("struct Foo:\n" " 0 [+1] Bar(1) b\n" "struct Bar:\n" " 0 [+1] UInt:8[] x\n") type_ir = ir.module[0].type[0].structure.field[0].type bar = ir.module[0].type[1] self.assertEqual([[ error.error("m.emb", type_ir.source_location, "Type Bar requires 0 parameters; 1 parameter given."), error.note("m.emb", bar.source_location, "Definition of type Bar.") ]], type_check.check_types(ir))
def test_rejects_requires_on_float(self): ir = _make_ir_from_emb('[$default byte_order: "LittleEndian"]\n' "struct Foo:\n" " 0 [+4] Float float\n" " [requires: false]\n") field_ir = ir.module[0].type[0].structure.field[0] self.assertEqual([[ error.error( "m.emb", field_ir.attribute[0].value.source_location, "Attribute 'requires' is only allowed on integer, " "enumeration, or boolean fields.") ]], error.filter_errors(attribute_checker.normalize_and_verify(ir)))
def _verify_byte_order_attribute_on_field(field, type_definition, source_file_name, ir, errors): """Verifies the byte_order attribute on the given field.""" byte_order_attr = ir_util.get_attribute(field.attribute, attributes.BYTE_ORDER) field_needs_byte_order = _field_needs_byte_order(field, type_definition, ir) if byte_order_attr and not field_needs_byte_order: errors.append([error.error( source_file_name, byte_order_attr.source_location, "Attribute 'byte_order' not allowed on field which is not byte order " "dependent.")]) if not byte_order_attr and field_needs_byte_order: errors.append([error.error( source_file_name, field.source_location, "Attribute 'byte_order' required on field which is byte order " "dependent.")]) if (byte_order_attr and byte_order_attr.string_constant.text == "Null" and not _field_may_have_null_byte_order(field, type_definition, ir)): errors.append([error.error( source_file_name, byte_order_attr.source_location, "Attribute 'byte_order' may only be 'Null' for one-byte fields.")])