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()