diff --git a/CHANGES.txt b/CHANGES.txt index 0916816..5c28a59 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,5 +1,8 @@ 0.13-dev *Next Release* + - Fixed a bug where negative numbers could be entered + for addresses in the monitor. + 0.12 (2012-02-16) - Fixed a bug that caused ``help cd`` to raise an exception diff --git a/py65/tests/test_monitor.py b/py65/tests/test_monitor.py index a93f9d6..9900c58 100644 --- a/py65/tests/test_monitor.py +++ b/py65/tests/test_monitor.py @@ -132,6 +132,14 @@ class MonitorTests(unittest.TestCase): out = stdout.getvalue() self.assertEqual("$4000 70 03 BVS $4005\n", out) + def test_do_assemble_constrains_address_to_valid_range(self): + stdout = StringIO() + mon = Monitor(stdout=stdout) + mon.do_assemble("-1 lda #$ab") + + out = stdout.getvalue() + self.assertEqual("$0000 a9 ab LDA #$ab\n", out) + def test_help_assemble(self): stdout = StringIO() mon = Monitor(stdout=stdout) diff --git a/py65/tests/utils/test_addressing.py b/py65/tests/utils/test_addressing.py index 5975cfb..2281f8f 100644 --- a/py65/tests/utils/test_addressing.py +++ b/py65/tests/utils/test_addressing.py @@ -97,12 +97,16 @@ class AddressParserTests(unittest.TestCase): except KeyError, why: self.assertEqual('Label not found: bad_label', why[0]) - def test_number_truncates_address_at_maxwidth_16(self): + def test_number_constrains_address_at_zero_or_above(self): + parser = AddressParser() + self.assertEqual(0x0000, parser.number('-1')) + + def test_number_constrains_address_at_maxwidth_16(self): parser = AddressParser() parser.labels = {'foo': 0xFFFF} self.assertEqual(0xFFFF, parser.number('foo+5')) - def test_number_truncates_address_at_maxwidth_24(self): + def test_number_constrains_address_at_maxwidth_24(self): parser = AddressParser() parser.maxwidth = 24 parser.labels = {'foo': 0xFFFFFF} diff --git a/py65/utils/addressing.py b/py65/utils/addressing.py index bc577d7..607d084 100644 --- a/py65/utils/addressing.py +++ b/py65/utils/addressing.py @@ -11,18 +11,21 @@ class AddressParser(object): names that can be substituted for addresses. """ self.radix = radix - self.labels = labels self.maxwidth = maxwidth - + + self.labels = {} + for k, v in labels.items(): + self.labels[k] = self._constrain(v) + def _get_maxwidth(self): - return self._maxwidth + return self._maxwidth def _set_maxwidth(self, width): self._maxwidth = width self._maxaddr = pow(2, width) - 1 maxwidth = property(_get_maxwidth, _set_maxwidth) - + def label_for(self, address, default=None): """Given an address, return the corresponding label or a default. """ @@ -35,17 +38,17 @@ class AddressParser(object): """Parse a string containing a label or number into an address. """ if num.startswith('$'): - return int(num[1:], 16) + return self._constrain(int(num[1:], 16)) elif num.startswith('+'): - return int(num[1:], 10) + return self._constrain(int(num[1:], 10)) elif num.startswith('%'): - return int(num[1:], 2) + return self._constrain(int(num[1:], 2)) elif num in self.labels: return self.labels[num] - + else: matches = re.match('^([^\s+-]+)\s*([+\-])\s*([$+%]?\d+)$', num) if matches: @@ -62,15 +65,11 @@ class AddressParser(object): else: address = base - offset - if address < 0: - address = 0 - if address > self._maxaddr: - address = self._maxaddr - return address + return self._constrain(address) else: try: - return int(num, self.radix) + return self._constrain(int(num, self.radix)) except ValueError: raise KeyError("Label not found: %s" % num) @@ -85,5 +84,11 @@ class AddressParser(object): start = end = self.number(addresses) if start > end: - start, end = end, start + start, end = end, start return (start, end) + + def _constrain(self, address): + """Constrains a number to be within the address range""" + address = max(address, 0) + address = min(address, self._maxaddr) + return address