Initial open-source commit of Emboss.
diff --git a/front_end/synthetics_test.py b/front_end/synthetics_test.py
new file mode 100644
index 0000000..10a23d3
--- /dev/null
+++ b/front_end/synthetics_test.py
@@ -0,0 +1,228 @@
+# Copyright 2019 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Tests for front_end.synthetics."""
+
+import unittest
+from front_end import glue
+from front_end import synthetics
+from front_end import test_util
+from public import ir_pb2
+
+
+class SyntheticsTest(unittest.TestCase):
+
+ def _find_attribute(self, field, name):
+ result = None
+ for attribute in field.attribute:
+ if attribute.name.text == name:
+ self.assertIsNone(result)
+ result = attribute
+ self.assertIsNotNone(result)
+ return result
+
+ def _make_ir(self, emb_text):
+ ir, unused_debug_info, errors = glue.parse_emboss_file(
+ "m.emb",
+ test_util.dict_file_reader({"m.emb": emb_text}),
+ stop_before_step="synthesize_fields")
+ assert not errors, errors
+ return ir
+
+ def test_nothing_to_do(self):
+ ir = self._make_ir("struct Foo:\n"
+ " 0 [+1] UInt x\n"
+ " 1 [+1] UInt:8[] y\n")
+ self.assertEqual([], synthetics.synthesize_fields(ir))
+
+ def test_adds_anonymous_bits_fields(self):
+ ir = self._make_ir("struct Foo:\n"
+ " 0 [+1] bits:\n"
+ " 0 [+4] Bar bar\n"
+ " 4 [+4] UInt uint\n"
+ " 1 [+1] bits:\n"
+ " 0 [+4] Bits nested_bits\n"
+ "enum Bar:\n"
+ " BAR = 0\n"
+ "bits Bits:\n"
+ " 0 [+4] UInt uint\n")
+ self.assertEqual([], synthetics.synthesize_fields(ir))
+ structure = ir.module[0].type[0].structure
+ # The first field should be the anonymous bits structure.
+ self.assertTrue(structure.field[0].HasField("location"))
+ # Then the aliases generated for those structures.
+ self.assertEqual("bar", structure.field[1].name.name.text)
+ self.assertEqual("uint", structure.field[2].name.name.text)
+ # Then the second anonymous bits.
+ self.assertTrue(structure.field[3].HasField("location"))
+ # Then the alias from the second anonymous bits.
+ self.assertEqual("nested_bits", structure.field[4].name.name.text)
+
+ def test_adds_correct_existence_condition(self):
+ ir = self._make_ir("struct Foo:\n"
+ " 0 [+1] bits:\n"
+ " 0 [+4] UInt bar\n")
+ self.assertEqual([], synthetics.synthesize_fields(ir))
+ bits_field = ir.module[0].type[0].structure.field[0]
+ alias_field = ir.module[0].type[0].structure.field[1]
+ self.assertEqual("bar", alias_field.name.name.text)
+ self.assertEqual(bits_field.name.name.text,
+ alias_field.existence_condition.function.args[0].function.
+ args[0].field_reference.path[0].source_name[-1].text)
+ self.assertEqual(bits_field.name.name.text,
+ alias_field.existence_condition.function.args[1].function.
+ args[0].field_reference.path[0].source_name[-1].text)
+ self.assertEqual("bar",
+ alias_field.existence_condition.function.args[1].function.
+ args[0].field_reference.path[1].source_name[-1].text)
+ self.assertEqual(
+ ir_pb2.Function.PRESENCE,
+ alias_field.existence_condition.function.args[0].function.function)
+ self.assertEqual(
+ ir_pb2.Function.PRESENCE,
+ alias_field.existence_condition.function.args[1].function.function)
+ self.assertEqual(ir_pb2.Function.AND,
+ alias_field.existence_condition.function.function)
+
+ def test_adds_correct_read_transform(self):
+ ir = self._make_ir("struct Foo:\n"
+ " 0 [+1] bits:\n"
+ " 0 [+4] UInt bar\n")
+ self.assertEqual([], synthetics.synthesize_fields(ir))
+ bits_field = ir.module[0].type[0].structure.field[0]
+ alias_field = ir.module[0].type[0].structure.field[1]
+ self.assertEqual("bar", alias_field.name.name.text)
+ self.assertEqual(
+ bits_field.name.name.text,
+ alias_field.read_transform.field_reference.path[0].source_name[-1].text)
+ self.assertEqual(
+ "bar",
+ alias_field.read_transform.field_reference.path[1].source_name[-1].text)
+
+ def test_adds_correct_abbreviation(self):
+ ir = self._make_ir("struct Foo:\n"
+ " 0 [+1] bits:\n"
+ " 0 [+4] UInt bar\n"
+ " 4 [+4] UInt baz (qux)\n")
+ self.assertEqual([], synthetics.synthesize_fields(ir))
+ bar_alias = ir.module[0].type[0].structure.field[1]
+ baz_alias = ir.module[0].type[0].structure.field[2]
+ self.assertFalse(bar_alias.HasField("abbreviation"))
+ self.assertEqual("qux", baz_alias.abbreviation.text)
+
+ def test_anonymous_bits_sets_correct_is_synthetic(self):
+ ir = self._make_ir("struct Foo:\n"
+ " 0 [+1] bits:\n"
+ " 0 [+4] UInt bar (b)\n")
+ self.assertEqual([], synthetics.synthesize_fields(ir))
+ bits_field = ir.module[0].type[0].subtype[0].structure.field[0]
+ alias_field = ir.module[0].type[0].structure.field[1]
+ self.assertFalse(alias_field.name.source_location.is_synthetic)
+ self.assertTrue(alias_field.HasField("abbreviation"))
+ self.assertFalse(alias_field.abbreviation.source_location.is_synthetic)
+ self.assertTrue(alias_field.HasField("read_transform"))
+ read_alias = alias_field.read_transform
+ self.assertTrue(read_alias.source_location.is_synthetic)
+ self.assertTrue(
+ read_alias.field_reference.path[0].source_location.is_synthetic)
+ alias_condition = alias_field.existence_condition
+ self.assertTrue(alias_condition.source_location.is_synthetic)
+ self.assertTrue(
+ alias_condition.function.args[0].source_location.is_synthetic)
+ self.assertTrue(bits_field.name.source_location.is_synthetic)
+ self.assertTrue(bits_field.name.name.source_location.is_synthetic)
+ self.assertTrue(bits_field.abbreviation.source_location.is_synthetic)
+
+ def test_adds_text_output_skip_attribute_to_anonymous_bits(self):
+ ir = self._make_ir("struct Foo:\n"
+ " 0 [+1] bits:\n"
+ " 0 [+4] UInt bar (b)\n")
+ self.assertEqual([], synthetics.synthesize_fields(ir))
+ bits_field = ir.module[0].type[0].structure.field[0]
+ text_output_attribute = self._find_attribute(bits_field, "text_output")
+ self.assertEqual("Skip", text_output_attribute.value.string_constant.text)
+
+ def test_skip_attribute_is_marked_as_synthetic(self):
+ ir = self._make_ir("struct Foo:\n"
+ " 0 [+1] bits:\n"
+ " 0 [+4] UInt bar\n")
+ self.assertEqual([], synthetics.synthesize_fields(ir))
+ bits_field = ir.module[0].type[0].structure.field[0]
+ attribute = self._find_attribute(bits_field, "text_output")
+ self.assertTrue(attribute.source_location.is_synthetic)
+ self.assertTrue(attribute.name.source_location.is_synthetic)
+ self.assertTrue(attribute.value.source_location.is_synthetic)
+ self.assertTrue(
+ attribute.value.string_constant.source_location.is_synthetic)
+
+ def test_adds_size_in_bytes(self):
+ ir = self._make_ir("struct Foo:\n"
+ " 1 [+l] UInt:8[] bytes\n"
+ " 0 [+1] UInt length (l)\n")
+ self.assertEqual([], synthetics.synthesize_fields(ir))
+ structure = ir.module[0].type[0].structure
+ size_in_bytes_field = structure.field[2]
+ max_size_in_bytes_field = structure.field[3]
+ min_size_in_bytes_field = structure.field[4]
+ self.assertEqual("$size_in_bytes", size_in_bytes_field.name.name.text)
+ self.assertEqual(ir_pb2.Function.MAXIMUM,
+ size_in_bytes_field.read_transform.function.function)
+ self.assertEqual("$max_size_in_bytes",
+ max_size_in_bytes_field.name.name.text)
+ self.assertEqual(ir_pb2.Function.UPPER_BOUND,
+ max_size_in_bytes_field.read_transform.function.function)
+ self.assertEqual("$min_size_in_bytes",
+ min_size_in_bytes_field.name.name.text)
+ self.assertEqual(ir_pb2.Function.LOWER_BOUND,
+ min_size_in_bytes_field.read_transform.function.function)
+ # The correctness of $size_in_bytes et al are tested much further down
+ # stream, in tests of the generated C++ code.
+
+ def test_adds_size_in_bits(self):
+ ir = self._make_ir("bits Foo:\n"
+ " 1 [+9] UInt hi\n"
+ " 0 [+1] Flag lo\n")
+ self.assertEqual([], synthetics.synthesize_fields(ir))
+ structure = ir.module[0].type[0].structure
+ size_in_bits_field = structure.field[2]
+ max_size_in_bits_field = structure.field[3]
+ min_size_in_bits_field = structure.field[4]
+ self.assertEqual("$size_in_bits", size_in_bits_field.name.name.text)
+ self.assertEqual(ir_pb2.Function.MAXIMUM,
+ size_in_bits_field.read_transform.function.function)
+ self.assertEqual("$max_size_in_bits",
+ max_size_in_bits_field.name.name.text)
+ self.assertEqual(ir_pb2.Function.UPPER_BOUND,
+ max_size_in_bits_field.read_transform.function.function)
+ self.assertEqual("$min_size_in_bits",
+ min_size_in_bits_field.name.name.text)
+ self.assertEqual(ir_pb2.Function.LOWER_BOUND,
+ min_size_in_bits_field.read_transform.function.function)
+ # The correctness of $size_in_bits et al are tested much further down
+ # stream, in tests of the generated C++ code.
+
+ def test_adds_text_output_skip_attribute_to_size_in_bytes(self):
+ ir = self._make_ir("struct Foo:\n"
+ " 1 [+l] UInt:8[] bytes\n"
+ " 0 [+1] UInt length (l)\n")
+ self.assertEqual([], synthetics.synthesize_fields(ir))
+ size_in_bytes_field = ir.module[0].type[0].structure.field[2]
+ self.assertEqual("$size_in_bytes", size_in_bytes_field.name.name.text)
+ text_output_attribute = self._find_attribute(size_in_bytes_field,
+ "text_output")
+ self.assertEqual("Skip", text_output_attribute.value.string_constant.text)
+
+
+if __name__ == "__main__":
+ unittest.main()