# 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 ...emboss.front_end.write_inference.""" import unittest from compiler.front_end import glue from compiler.front_end import write_inference from compiler.util import ir_data from compiler.util import test_util class WriteInferenceTest(unittest.TestCase): 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="set_write_methods") assert not errors, errors return ir def test_adds_physical_write_method(self): ir = self._make_ir("struct Foo:\n" " 0 [+1] UInt x\n") self.assertEqual([], write_inference.set_write_methods(ir)) self.assertTrue( ir.module[0].type[0].structure.field[0].write_method.physical) def test_adds_read_only_write_method_to_non_alias_virtual(self): ir = self._make_ir("struct Foo:\n" " let x = 5\n") self.assertEqual([], write_inference.set_write_methods(ir)) self.assertTrue( ir.module[0].type[0].structure.field[0].write_method.read_only) def test_adds_alias_write_method_to_alias_of_physical_field(self): ir = self._make_ir("struct Foo:\n" " let x = y\n" " 0 [+1] UInt y\n") self.assertEqual([], write_inference.set_write_methods(ir)) field = ir.module[0].type[0].structure.field[0] self.assertTrue(field.write_method.HasField("alias")) self.assertEqual( "y", field.write_method.alias.path[0].canonical_name.object_path[-1]) def test_adds_alias_write_method_to_alias_of_alias_of_physical_field(self): ir = self._make_ir("struct Foo:\n" " let x = z\n" " let z = y\n" " 0 [+1] UInt y\n") self.assertEqual([], write_inference.set_write_methods(ir)) field = ir.module[0].type[0].structure.field[0] self.assertTrue(field.write_method.HasField("alias")) self.assertEqual( "z", field.write_method.alias.path[0].canonical_name.object_path[-1]) def test_adds_read_only_write_method_to_alias_of_read_only(self): ir = self._make_ir("struct Foo:\n" " let x = y\n" " let y = 5\n") self.assertEqual([], write_inference.set_write_methods(ir)) field = ir.module[0].type[0].structure.field[0] self.assertTrue(field.write_method.read_only) def test_adds_read_only_write_method_to_alias_of_alias_of_read_only(self): ir = self._make_ir("struct Foo:\n" " let x = z\n" " let z = y\n" " let y = 5\n") self.assertEqual([], write_inference.set_write_methods(ir)) field = ir.module[0].type[0].structure.field[0] self.assertTrue(field.write_method.read_only) def test_adds_read_only_write_method_to_alias_of_parameter(self): ir = self._make_ir("struct Foo(x: UInt:8):\n" " let y = x\n") self.assertEqual([], write_inference.set_write_methods(ir)) field = ir.module[0].type[0].structure.field[0] self.assertTrue(field.write_method.read_only) def test_adds_transform_write_method_to_base_value_field(self): ir = self._make_ir("struct Foo:\n" " 0 [+1] UInt x\n" " let y = x + 50\n") self.assertEqual([], write_inference.set_write_methods(ir)) field = ir.module[0].type[0].structure.field[1] transform = field.write_method.transform self.assertTrue(transform) self.assertEqual( "x", transform.destination.path[0].canonical_name.object_path[-1]) self.assertEqual(ir_data.FunctionMapping.SUBTRACTION, transform.function_body.function.function) arg0, arg1 = transform.function_body.function.args self.assertEqual("$logical_value", arg0.builtin_reference.canonical_name.object_path[0]) self.assertEqual("50", arg1.constant.value) def test_adds_transform_write_method_to_negative_base_value_field(self): ir = self._make_ir("struct Foo:\n" " 0 [+1] UInt x\n" " let y = x - 50\n") self.assertEqual([], write_inference.set_write_methods(ir)) field = ir.module[0].type[0].structure.field[1] transform = field.write_method.transform self.assertTrue(transform) self.assertEqual( "x", transform.destination.path[0].canonical_name.object_path[-1]) self.assertEqual(ir_data.FunctionMapping.ADDITION, transform.function_body.function.function) arg0, arg1 = transform.function_body.function.args self.assertEqual("$logical_value", arg0.builtin_reference.canonical_name.object_path[0]) self.assertEqual("50", arg1.constant.value) def test_adds_transform_write_method_to_reversed_base_value_field(self): ir = self._make_ir("struct Foo:\n" " 0 [+1] UInt x\n" " let y = 50 + x\n") self.assertEqual([], write_inference.set_write_methods(ir)) field = ir.module[0].type[0].structure.field[1] transform = field.write_method.transform self.assertTrue(transform) self.assertEqual( "x", transform.destination.path[0].canonical_name.object_path[-1]) self.assertEqual(ir_data.FunctionMapping.SUBTRACTION, transform.function_body.function.function) arg0, arg1 = transform.function_body.function.args self.assertEqual("$logical_value", arg0.builtin_reference.canonical_name.object_path[0]) self.assertEqual("50", arg1.constant.value) def test_adds_transform_write_method_to_reversed_negative_base_value_field( self): ir = self._make_ir("struct Foo:\n" " 0 [+1] UInt x\n" " let y = 50 - x\n") self.assertEqual([], write_inference.set_write_methods(ir)) field = ir.module[0].type[0].structure.field[1] transform = field.write_method.transform self.assertTrue(transform) self.assertEqual( "x", transform.destination.path[0].canonical_name.object_path[-1]) self.assertEqual(ir_data.FunctionMapping.SUBTRACTION, transform.function_body.function.function) arg0, arg1 = transform.function_body.function.args self.assertEqual("50", arg0.constant.value) self.assertEqual("$logical_value", arg1.builtin_reference.canonical_name.object_path[0]) def test_adds_transform_write_method_to_nested_invertible_field(self): ir = self._make_ir("struct Foo:\n" " 0 [+1] UInt x\n" " let y = 30 + (50 - x)\n") self.assertEqual([], write_inference.set_write_methods(ir)) field = ir.module[0].type[0].structure.field[1] transform = field.write_method.transform self.assertTrue(transform) self.assertEqual( "x", transform.destination.path[0].canonical_name.object_path[-1]) self.assertEqual(ir_data.FunctionMapping.SUBTRACTION, transform.function_body.function.function) arg0, arg1 = transform.function_body.function.args self.assertEqual("50", arg0.constant.value) self.assertEqual(ir_data.FunctionMapping.SUBTRACTION, arg1.function.function) arg10, arg11 = arg1.function.args self.assertEqual("$logical_value", arg10.builtin_reference.canonical_name.object_path[0]) self.assertEqual("30", arg11.constant.value) def test_does_not_add_transform_write_method_for_parameter_target(self): ir = self._make_ir("struct Foo(x: UInt:8):\n" " let y = 50 + x\n") self.assertEqual([], write_inference.set_write_methods(ir)) field = ir.module[0].type[0].structure.field[0] self.assertEqual("read_only", field.write_method.WhichOneof("method")) def test_adds_transform_write_method_with_complex_auxiliary_subexpression( self): ir = self._make_ir("struct Foo:\n" " 0 [+1] UInt x\n" " let y = x - $max(Foo.$size_in_bytes, Foo.z)\n" " let z = 500\n") self.assertEqual([], write_inference.set_write_methods(ir)) field = ir.module[0].type[0].structure.field[1] transform = field.write_method.transform self.assertTrue(transform) self.assertEqual( "x", transform.destination.path[0].canonical_name.object_path[-1]) self.assertEqual(ir_data.FunctionMapping.ADDITION, transform.function_body.function.function) args = transform.function_body.function.args self.assertEqual("$logical_value", args[0].builtin_reference.canonical_name.object_path[0]) self.assertEqual(field.read_transform.function.args[1], args[1]) if __name__ == "__main__": unittest.main()