1# Copyright 2019 Google LLC 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# https://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14 15"""Tests for ...emboss.front_end.write_inference.""" 16 17import unittest 18from compiler.front_end import glue 19from compiler.front_end import write_inference 20from compiler.util import ir_data 21from compiler.util import test_util 22 23 24class WriteInferenceTest(unittest.TestCase): 25 26 def _make_ir(self, emb_text): 27 ir, unused_debug_info, errors = glue.parse_emboss_file( 28 "m.emb", 29 test_util.dict_file_reader({"m.emb": emb_text}), 30 stop_before_step="set_write_methods") 31 assert not errors, errors 32 return ir 33 34 def test_adds_physical_write_method(self): 35 ir = self._make_ir("struct Foo:\n" 36 " 0 [+1] UInt x\n") 37 self.assertEqual([], write_inference.set_write_methods(ir)) 38 self.assertTrue( 39 ir.module[0].type[0].structure.field[0].write_method.physical) 40 41 def test_adds_read_only_write_method_to_non_alias_virtual(self): 42 ir = self._make_ir("struct Foo:\n" 43 " let x = 5\n") 44 self.assertEqual([], write_inference.set_write_methods(ir)) 45 self.assertTrue( 46 ir.module[0].type[0].structure.field[0].write_method.read_only) 47 48 def test_adds_alias_write_method_to_alias_of_physical_field(self): 49 ir = self._make_ir("struct Foo:\n" 50 " let x = y\n" 51 " 0 [+1] UInt y\n") 52 self.assertEqual([], write_inference.set_write_methods(ir)) 53 field = ir.module[0].type[0].structure.field[0] 54 self.assertTrue(field.write_method.HasField("alias")) 55 self.assertEqual( 56 "y", field.write_method.alias.path[0].canonical_name.object_path[-1]) 57 58 def test_adds_alias_write_method_to_alias_of_alias_of_physical_field(self): 59 ir = self._make_ir("struct Foo:\n" 60 " let x = z\n" 61 " let z = y\n" 62 " 0 [+1] UInt y\n") 63 self.assertEqual([], write_inference.set_write_methods(ir)) 64 field = ir.module[0].type[0].structure.field[0] 65 self.assertTrue(field.write_method.HasField("alias")) 66 self.assertEqual( 67 "z", field.write_method.alias.path[0].canonical_name.object_path[-1]) 68 69 def test_adds_read_only_write_method_to_alias_of_read_only(self): 70 ir = self._make_ir("struct Foo:\n" 71 " let x = y\n" 72 " let y = 5\n") 73 self.assertEqual([], write_inference.set_write_methods(ir)) 74 field = ir.module[0].type[0].structure.field[0] 75 self.assertTrue(field.write_method.read_only) 76 77 def test_adds_read_only_write_method_to_alias_of_alias_of_read_only(self): 78 ir = self._make_ir("struct Foo:\n" 79 " let x = z\n" 80 " let z = y\n" 81 " let y = 5\n") 82 self.assertEqual([], write_inference.set_write_methods(ir)) 83 field = ir.module[0].type[0].structure.field[0] 84 self.assertTrue(field.write_method.read_only) 85 86 def test_adds_read_only_write_method_to_alias_of_parameter(self): 87 ir = self._make_ir("struct Foo(x: UInt:8):\n" 88 " let y = x\n") 89 self.assertEqual([], write_inference.set_write_methods(ir)) 90 field = ir.module[0].type[0].structure.field[0] 91 self.assertTrue(field.write_method.read_only) 92 93 def test_adds_transform_write_method_to_base_value_field(self): 94 ir = self._make_ir("struct Foo:\n" 95 " 0 [+1] UInt x\n" 96 " let y = x + 50\n") 97 self.assertEqual([], write_inference.set_write_methods(ir)) 98 field = ir.module[0].type[0].structure.field[1] 99 transform = field.write_method.transform 100 self.assertTrue(transform) 101 self.assertEqual( 102 "x", 103 transform.destination.path[0].canonical_name.object_path[-1]) 104 self.assertEqual(ir_data.FunctionMapping.SUBTRACTION, 105 transform.function_body.function.function) 106 arg0, arg1 = transform.function_body.function.args 107 self.assertEqual("$logical_value", 108 arg0.builtin_reference.canonical_name.object_path[0]) 109 self.assertEqual("50", arg1.constant.value) 110 111 def test_adds_transform_write_method_to_negative_base_value_field(self): 112 ir = self._make_ir("struct Foo:\n" 113 " 0 [+1] UInt x\n" 114 " let y = x - 50\n") 115 self.assertEqual([], write_inference.set_write_methods(ir)) 116 field = ir.module[0].type[0].structure.field[1] 117 transform = field.write_method.transform 118 self.assertTrue(transform) 119 self.assertEqual( 120 "x", 121 transform.destination.path[0].canonical_name.object_path[-1]) 122 self.assertEqual(ir_data.FunctionMapping.ADDITION, 123 transform.function_body.function.function) 124 arg0, arg1 = transform.function_body.function.args 125 self.assertEqual("$logical_value", 126 arg0.builtin_reference.canonical_name.object_path[0]) 127 self.assertEqual("50", arg1.constant.value) 128 129 def test_adds_transform_write_method_to_reversed_base_value_field(self): 130 ir = self._make_ir("struct Foo:\n" 131 " 0 [+1] UInt x\n" 132 " let y = 50 + x\n") 133 self.assertEqual([], write_inference.set_write_methods(ir)) 134 field = ir.module[0].type[0].structure.field[1] 135 transform = field.write_method.transform 136 self.assertTrue(transform) 137 self.assertEqual( 138 "x", 139 transform.destination.path[0].canonical_name.object_path[-1]) 140 self.assertEqual(ir_data.FunctionMapping.SUBTRACTION, 141 transform.function_body.function.function) 142 arg0, arg1 = transform.function_body.function.args 143 self.assertEqual("$logical_value", 144 arg0.builtin_reference.canonical_name.object_path[0]) 145 self.assertEqual("50", arg1.constant.value) 146 147 def test_adds_transform_write_method_to_reversed_negative_base_value_field( 148 self): 149 ir = self._make_ir("struct Foo:\n" 150 " 0 [+1] UInt x\n" 151 " let y = 50 - x\n") 152 self.assertEqual([], write_inference.set_write_methods(ir)) 153 field = ir.module[0].type[0].structure.field[1] 154 transform = field.write_method.transform 155 self.assertTrue(transform) 156 self.assertEqual( 157 "x", 158 transform.destination.path[0].canonical_name.object_path[-1]) 159 self.assertEqual(ir_data.FunctionMapping.SUBTRACTION, 160 transform.function_body.function.function) 161 arg0, arg1 = transform.function_body.function.args 162 self.assertEqual("50", arg0.constant.value) 163 self.assertEqual("$logical_value", 164 arg1.builtin_reference.canonical_name.object_path[0]) 165 166 def test_adds_transform_write_method_to_nested_invertible_field(self): 167 ir = self._make_ir("struct Foo:\n" 168 " 0 [+1] UInt x\n" 169 " let y = 30 + (50 - x)\n") 170 self.assertEqual([], write_inference.set_write_methods(ir)) 171 field = ir.module[0].type[0].structure.field[1] 172 transform = field.write_method.transform 173 self.assertTrue(transform) 174 self.assertEqual( 175 "x", 176 transform.destination.path[0].canonical_name.object_path[-1]) 177 self.assertEqual(ir_data.FunctionMapping.SUBTRACTION, 178 transform.function_body.function.function) 179 arg0, arg1 = transform.function_body.function.args 180 self.assertEqual("50", arg0.constant.value) 181 self.assertEqual(ir_data.FunctionMapping.SUBTRACTION, arg1.function.function) 182 arg10, arg11 = arg1.function.args 183 self.assertEqual("$logical_value", 184 arg10.builtin_reference.canonical_name.object_path[0]) 185 self.assertEqual("30", arg11.constant.value) 186 187 def test_does_not_add_transform_write_method_for_parameter_target(self): 188 ir = self._make_ir("struct Foo(x: UInt:8):\n" 189 " let y = 50 + x\n") 190 self.assertEqual([], write_inference.set_write_methods(ir)) 191 field = ir.module[0].type[0].structure.field[0] 192 self.assertEqual("read_only", field.write_method.WhichOneof("method")) 193 194 def test_adds_transform_write_method_with_complex_auxiliary_subexpression( 195 self): 196 ir = self._make_ir("struct Foo:\n" 197 " 0 [+1] UInt x\n" 198 " let y = x - $max(Foo.$size_in_bytes, Foo.z)\n" 199 " let z = 500\n") 200 self.assertEqual([], write_inference.set_write_methods(ir)) 201 field = ir.module[0].type[0].structure.field[1] 202 transform = field.write_method.transform 203 self.assertTrue(transform) 204 self.assertEqual( 205 "x", 206 transform.destination.path[0].canonical_name.object_path[-1]) 207 self.assertEqual(ir_data.FunctionMapping.ADDITION, 208 transform.function_body.function.function) 209 args = transform.function_body.function.args 210 self.assertEqual("$logical_value", 211 args[0].builtin_reference.canonical_name.object_path[0]) 212 self.assertEqual(field.read_transform.function.args[1], args[1]) 213 214 215if __name__ == "__main__": 216 unittest.main() 217