this repo has no description

Check record size in pattern match

authored by bernsteinbear.com and committed by

Max Bernstein d235b060 04f292fb

+10 -2
+3 -2
compiler.py
··· 231 231 if isinstance(pattern, Record): 232 232 self._emit(f"if (!is_record({arg})) {{ goto {fallthrough}; }}") 233 233 updates = {} 234 + use_spread = False 234 235 for key, pattern_value in pattern.data.items(): 235 236 assert not isinstance(pattern_value, Spread), "record spread not yet supported" 236 237 key_idx = self.record_key(key) 237 238 record_value = self._mktemp(f"record_get({arg}, {key_idx})") 238 239 self._emit(f"if ({record_value} == NULL) {{ goto {fallthrough}; }}") 239 240 updates.update(self.try_match(env, record_value, pattern_value, fallthrough)) 240 - # TODO(max): Check that there are no other fields in the record, 241 - # perhaps by length check 241 + if not use_spread: 242 + self._emit(f"if (record_num_fields({arg}) != {len(pattern.data)}) {{ goto {fallthrough}; }}") 242 243 return updates 243 244 raise NotImplementedError("try_match", pattern) 244 245
+3
compiler_tests.py
··· 105 105 def test_match_record(self) -> None: 106 106 self.assertEqual(self._run("f {a = 4, b = 5} . f = | {a = 1, b = 2} -> 3 | {a = 4, b = 5} -> 6"), "6\n") 107 107 108 + def test_match_record_too_few_keys(self) -> None: 109 + self.assertEqual(self._run("f {a = 4, b = 5} . f = | {a = _} -> 3 | {a = _, b = _} -> 6"), "6\n") 110 + 108 111 @unittest.skip("TODO") 109 112 def test_match_record_spread(self) -> None: 110 113 self.assertEqual(self._run("f {a=1, b=2, c=3} . f = | {a=1, ...rest} -> rest"), "[5]\n")
+4
runtime.c
··· 484 484 return result; 485 485 } 486 486 487 + size_t record_num_fields(struct object* record) { 488 + return as_record(record)->size; 489 + } 490 + 487 491 void record_set(struct object* record, size_t index, 488 492 struct record_field field) { 489 493 struct record* r = as_record(record);