mirror of
https://github.com/mnaberez/py65.git
synced 2024-05-31 12:41:31 +00:00
Compare commits
15 Commits
c8e63581fe
...
8bb47a45a0
Author | SHA1 | Date | |
---|---|---|---|
|
8bb47a45a0 | ||
|
74e2576894 | ||
|
9455a5c70e | ||
|
1870d65982 | ||
|
8dce37f6b8 | ||
|
85ed46fd68 | ||
|
2b837bbd4f | ||
|
6ccdbe9c07 | ||
|
95e152d6cb | ||
|
d547dbc07c | ||
|
9ae3871388 | ||
|
55eef25998 | ||
|
db247b9765 | ||
|
4e950d6ef5 | ||
|
edcdeceebe |
89
.github/workflows/main.yml
vendored
89
.github/workflows/main.yml
vendored
|
@ -2,26 +2,105 @@ name: Run all tests
|
||||||
|
|
||||||
on: [push, pull_request]
|
on: [push, pull_request]
|
||||||
|
|
||||||
|
env:
|
||||||
|
PIP: "env PIP_DISABLE_PIP_VERSION_CHECK=1
|
||||||
|
PYTHONWARNINGS=ignore:DEPRECATION
|
||||||
|
pip --no-cache-dir"
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
tests_py27:
|
||||||
|
runs-on: ubuntu-20.04
|
||||||
|
container: python:2.7
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Show Python version
|
||||||
|
run: python -V
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: $PIP install setuptools pexpect
|
||||||
|
|
||||||
|
- name: Run the tests
|
||||||
|
run: python setup.py test -q
|
||||||
|
|
||||||
|
- name: Run the end-to-end tests
|
||||||
|
run: END_TO_END=1 python setup.py test -q
|
||||||
|
|
||||||
|
build_py34:
|
||||||
|
runs-on: ubuntu-20.04
|
||||||
|
container: python:3.4
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
# does not work with actions/checkout@v4:
|
||||||
|
# /usr/bin/docker exec 289170dbefc90d2ba94a09f3dcb70c42c1e1b29a5e877cd533b26ebf73ca82fa sh -c "cat /etc/*release | grep ^ID"
|
||||||
|
# /__e/node20/bin/node: /lib/x86_64-linux-gnu/libm.so.6: version `GLIBC_2.27' not found (required by /__e/node20/bin/node)
|
||||||
|
# /__e/node20/bin/node: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.28' not found (required by /__e/node20/bin/node)
|
||||||
|
# /__e/node20/bin/node: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.25' not found (required by /__e/node20/bin/node)
|
||||||
|
|
||||||
|
- name: Show Python version
|
||||||
|
run: python -V
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: $PIP install setuptools pexpect
|
||||||
|
|
||||||
|
- name: Run the tests
|
||||||
|
run: python setup.py test -q
|
||||||
|
|
||||||
|
- name: Run the end-to-end tests
|
||||||
|
run: END_TO_END=1 python setup.py test -q
|
||||||
|
|
||||||
|
build_py35:
|
||||||
|
runs-on: ubuntu-20.04
|
||||||
|
container: python:3.5
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Show Python version
|
||||||
|
run: python -V
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: $PIP install setuptools pexpect
|
||||||
|
|
||||||
|
- name: Run the tests
|
||||||
|
run: python setup.py test -q
|
||||||
|
|
||||||
|
- name: Run the end-to-end tests
|
||||||
|
run: END_TO_END=1 python setup.py test -q
|
||||||
|
|
||||||
|
build_py3x:
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
python-version: [3.6, 3.7, 3.8, 3.9, "3.10", 3.11]
|
python-version: [3.6, 3.7, 3.8, 3.9, "3.10", 3.11, 3.12]
|
||||||
os: [ubuntu-20.04, windows-2019]
|
os: [ubuntu-20.04]
|
||||||
|
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Set up Python ${{ matrix.python-version }}
|
- name: Set up Python ${{ matrix.python-version }}
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v5
|
||||||
with:
|
with:
|
||||||
python-version: ${{ matrix.python-version }}
|
python-version: ${{ matrix.python-version }}
|
||||||
|
|
||||||
- name: Show Python version
|
- name: Show Python version
|
||||||
run: python -V
|
run: python -V
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: $PIP install setuptools pexpect
|
||||||
|
|
||||||
- name: Run the tests
|
- name: Run the tests
|
||||||
run: python setup.py test -q
|
run: python setup.py test -q
|
||||||
|
|
||||||
|
- name: Run the end-to-end tests
|
||||||
|
run: END_TO_END=1 python setup.py test -q
|
||||||
|
|
12
CHANGES.rst
12
CHANGES.rst
|
@ -1,13 +1,17 @@
|
||||||
2.0.0.dev0 (Next Release)
|
1.3.0.dev0 (Next Release)
|
||||||
-------------------------
|
-------------------------
|
||||||
|
|
||||||
- Support for some older Python versions has been dropped. Py65
|
1.2.0 (2024-04-12)
|
||||||
now requires Python 3.6 or later.
|
------------------
|
||||||
|
|
||||||
- Fixed a bug with character input that would cause characters to be
|
- Fixed a bug with character input that would cause characters to be
|
||||||
dropped when pasting in larger amounts of text. This makes it possible
|
dropped when pasting in larger amounts of text. This makes it possible
|
||||||
to paste programs into EhBASIC and Taliforth. Patch by SamCoVT.
|
to paste programs into EhBASIC and Taliforth. Patch by SamCoVT.
|
||||||
|
|
||||||
|
- Fixed interactive assembly on Python 3.
|
||||||
|
|
||||||
|
- Fixed regular expression warnings on Python 3.12.
|
||||||
|
|
||||||
- The ``fill`` command in the monitor now shows an error message if an
|
- The ``fill`` command in the monitor now shows an error message if an
|
||||||
address or value is out of range.
|
address or value is out of range.
|
||||||
|
|
||||||
|
@ -22,6 +26,8 @@
|
||||||
- Fixed assembly and disassembly of 65C02 instruction $64 (``STZ $12``).
|
- Fixed assembly and disassembly of 65C02 instruction $64 (``STZ $12``).
|
||||||
Patch by Patrick Surry.
|
Patch by Patrick Surry.
|
||||||
|
|
||||||
|
- Removed use of the ``asyncore`` module deprecated in Python 3.10.
|
||||||
|
|
||||||
1.1.0 (2018-07-01)
|
1.1.0 (2018-07-01)
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
BSD 3-Clause License
|
BSD 3-Clause License
|
||||||
|
|
||||||
Copyright (c) 2008-2018, Mike Naberezny and contributors.
|
Copyright (c) 2008-2024, Mike Naberezny and contributors.
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
|
|
@ -20,9 +20,9 @@ Installation
|
||||||
|
|
||||||
Py65 packages are `available <http://pypi.python.org/pypi/py65>`_ on the
|
Py65 packages are `available <http://pypi.python.org/pypi/py65>`_ on the
|
||||||
Python Package Index (PyPI). You download them from there or you can
|
Python Package Index (PyPI). You download them from there or you can
|
||||||
use ``pip3`` to automatically install or upgrade Py65::
|
use ``pip`` to install Py65::
|
||||||
|
|
||||||
$ pip3 install -U py65
|
$ pip install setuptools py65
|
||||||
|
|
||||||
Devices
|
Devices
|
||||||
-------
|
-------
|
||||||
|
|
|
@ -49,7 +49,7 @@ copyright = u'2008-%d, Mike Naberezny and contributors' % year
|
||||||
# built documents.
|
# built documents.
|
||||||
#
|
#
|
||||||
# The short X.Y version.
|
# The short X.Y version.
|
||||||
version = '1.1.0.dev0'
|
version = '1.3.0.dev0'
|
||||||
# The full version, including alpha/beta/rc tags.
|
# The full version, including alpha/beta/rc tags.
|
||||||
release = version
|
release = version
|
||||||
|
|
||||||
|
|
|
@ -92,7 +92,7 @@ class Assembler:
|
||||||
and parsing the address part using AddressParser. The result of
|
and parsing the address part using AddressParser. The result of
|
||||||
the normalization is a tuple of two strings (opcode, operand).
|
the normalization is a tuple of two strings (opcode, operand).
|
||||||
"""
|
"""
|
||||||
statement = ' '.join(str.split(statement))
|
statement = ' '.join(statement.split())
|
||||||
|
|
||||||
# normalize target in operand
|
# normalize target in operand
|
||||||
match = self.Statement.match(statement)
|
match = self.Statement.match(statement)
|
||||||
|
|
21
py65/compat.py
Normal file
21
py65/compat.py
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
import sys
|
||||||
|
|
||||||
|
PY2 = sys.version_info[0] == 2
|
||||||
|
|
||||||
|
if PY2:
|
||||||
|
unicode = unicode
|
||||||
|
|
||||||
|
def as_string(s, encoding='utf-8'):
|
||||||
|
if isinstance(s, unicode):
|
||||||
|
return s
|
||||||
|
else:
|
||||||
|
return s.decode(encoding)
|
||||||
|
|
||||||
|
else:
|
||||||
|
unicode = str
|
||||||
|
|
||||||
|
def as_string(s, encoding='utf-8'):
|
||||||
|
if isinstance(s, str):
|
||||||
|
return s
|
||||||
|
else:
|
||||||
|
return s.decode(encoding)
|
|
@ -22,8 +22,6 @@ import shlex
|
||||||
import sys
|
import sys
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
from urllib.request import urlopen
|
|
||||||
|
|
||||||
from py65.devices.mpu6502 import MPU as NMOS6502
|
from py65.devices.mpu6502 import MPU as NMOS6502
|
||||||
from py65.devices.mpu65c02 import MPU as CMOS65C02
|
from py65.devices.mpu65c02 import MPU as CMOS65C02
|
||||||
from py65.devices.mpu65org16 import MPU as V65Org16
|
from py65.devices.mpu65org16 import MPU as V65Org16
|
||||||
|
@ -34,6 +32,11 @@ from py65.utils import console
|
||||||
from py65.utils.conversions import itoa
|
from py65.utils.conversions import itoa
|
||||||
from py65.memory import ObservableMemory
|
from py65.memory import ObservableMemory
|
||||||
|
|
||||||
|
try:
|
||||||
|
from urllib2 import urlopen
|
||||||
|
except ImportError: # Python 3
|
||||||
|
from urllib.request import urlopen
|
||||||
|
|
||||||
class Monitor(cmd.Cmd):
|
class Monitor(cmd.Cmd):
|
||||||
|
|
||||||
Microprocessors = {'6502': NMOS6502, '65C02': CMOS65C02,
|
Microprocessors = {'6502': NMOS6502, '65C02': CMOS65C02,
|
||||||
|
@ -160,8 +163,8 @@ class Monitor(cmd.Cmd):
|
||||||
result = cmd.Cmd.onecmd(self, line)
|
result = cmd.Cmd.onecmd(self, line)
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
self._output("Interrupt")
|
self._output("Interrupt")
|
||||||
except Exception as e:
|
except Exception:
|
||||||
error = ''.join(traceback.format_exception(e))
|
error = ''.join(traceback.format_exception(*sys.exc_info()))
|
||||||
self._output(error)
|
self._output(error)
|
||||||
|
|
||||||
if not line.startswith("quit"):
|
if not line.startswith("quit"):
|
||||||
|
@ -199,6 +202,7 @@ class Monitor(cmd.Cmd):
|
||||||
'f': 'fill',
|
'f': 'fill',
|
||||||
'>': 'fill',
|
'>': 'fill',
|
||||||
'g': 'goto',
|
'g': 'goto',
|
||||||
|
'go': 'go',
|
||||||
'h': 'help',
|
'h': 'help',
|
||||||
'?': 'help',
|
'?': 'help',
|
||||||
'l': 'load',
|
'l': 'load',
|
||||||
|
@ -236,7 +240,7 @@ class Monitor(cmd.Cmd):
|
||||||
line = command
|
line = command
|
||||||
break
|
break
|
||||||
|
|
||||||
pattern = '^%s\s+' % re.escape(shortcut)
|
pattern = r'^%s\s+' % re.escape(shortcut)
|
||||||
matches = re.match(pattern, line)
|
matches = re.match(pattern, line)
|
||||||
if matches:
|
if matches:
|
||||||
start, end = matches.span()
|
start, end = matches.span()
|
||||||
|
@ -491,6 +495,14 @@ class Monitor(cmd.Cmd):
|
||||||
self._mpu.pc = self._address_parser.number(args)
|
self._mpu.pc = self._address_parser.number(args)
|
||||||
brks = [0x00] # BRK
|
brks = [0x00] # BRK
|
||||||
self._run(stopcodes=brks)
|
self._run(stopcodes=brks)
|
||||||
|
|
||||||
|
def help_go(self):
|
||||||
|
self._output("go")
|
||||||
|
self._output("Continue execution.")
|
||||||
|
|
||||||
|
def do_go(self, args):
|
||||||
|
brks = [0x00] # BRK
|
||||||
|
self._run(stopcodes=brks)
|
||||||
|
|
||||||
def _run(self, stopcodes):
|
def _run(self, stopcodes):
|
||||||
stopcodes = set(stopcodes)
|
stopcodes = set(stopcodes)
|
||||||
|
@ -577,7 +589,7 @@ class Monitor(cmd.Cmd):
|
||||||
if args == '':
|
if args == '':
|
||||||
return
|
return
|
||||||
|
|
||||||
pairs = re.findall('([^=,\s]*)=([^=,\s]*)', args)
|
pairs = re.findall(r'([^=,\s]*)=([^=,\s]*)', args)
|
||||||
if pairs == []:
|
if pairs == []:
|
||||||
return self._output("Syntax error: %s" % args)
|
return self._output("Syntax error: %s" % args)
|
||||||
|
|
||||||
|
|
88
py65/tests/end_to_end.py
Normal file
88
py65/tests/end_to_end.py
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
import os
|
||||||
|
import signal
|
||||||
|
import sys
|
||||||
|
import tempfile
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
from py65.compat import unicode
|
||||||
|
|
||||||
|
# end-to-test tests are slow so only run them when asked
|
||||||
|
if 'END_TO_END' in os.environ:
|
||||||
|
if sys.platform == "win32":
|
||||||
|
raise NotImplementedError()
|
||||||
|
else:
|
||||||
|
import pexpect
|
||||||
|
BaseTestCase = unittest.TestCase
|
||||||
|
else:
|
||||||
|
BaseTestCase = object
|
||||||
|
|
||||||
|
|
||||||
|
class EndToEndTests(BaseTestCase):
|
||||||
|
|
||||||
|
def _spawn(self):
|
||||||
|
mon = pexpect.spawn(
|
||||||
|
sys.executable,
|
||||||
|
['-u', '-m', 'py65.monitor'],
|
||||||
|
encoding='utf-8'
|
||||||
|
)
|
||||||
|
mon.expect_exact(unicode("Py65 Monitor"))
|
||||||
|
self.addCleanup(mon.kill, signal.SIGINT)
|
||||||
|
return mon
|
||||||
|
|
||||||
|
def test_putc(self):
|
||||||
|
mon = self._spawn()
|
||||||
|
|
||||||
|
mon.sendline(unicode("add_label f001 putc"))
|
||||||
|
|
||||||
|
mon.sendline(unicode("a c000 lda #'H"))
|
||||||
|
mon.sendline(unicode("a c002 sta putc"))
|
||||||
|
mon.sendline(unicode("a c005 lda #'I"))
|
||||||
|
mon.sendline(unicode("a c007 sta putc"))
|
||||||
|
mon.sendline(unicode("a c00a brk"))
|
||||||
|
|
||||||
|
mon.sendline(unicode("g c000"))
|
||||||
|
mon.expect_exact(unicode("HI"))
|
||||||
|
mon.sendline(unicode("q"))
|
||||||
|
|
||||||
|
def test_getc(self):
|
||||||
|
mon = self._spawn()
|
||||||
|
|
||||||
|
mon.sendline(unicode("add_label f004 getc"))
|
||||||
|
|
||||||
|
mon.sendline(unicode("a c000 ldx #0"))
|
||||||
|
mon.sendline(unicode("a c002 lda getc"))
|
||||||
|
mon.sendline(unicode("a c005 beq c002"))
|
||||||
|
mon.sendline(unicode("a c007 cmp #'!"))
|
||||||
|
mon.sendline(unicode("a c009 bne c00c"))
|
||||||
|
mon.sendline(unicode("a c00b brk"))
|
||||||
|
mon.sendline(unicode("a c00c sta 1000,x"))
|
||||||
|
mon.sendline(unicode("a c00f inx"))
|
||||||
|
mon.sendline(unicode("a c010 jmp c002"))
|
||||||
|
|
||||||
|
mon.sendline(unicode("g c000"))
|
||||||
|
mon.send(unicode("HELLO!"))
|
||||||
|
mon.expect_exact(unicode("6502:"))
|
||||||
|
mon.sendline(unicode("m 1000:1004"))
|
||||||
|
mon.expect_exact(unicode("48 45 4c 4c 4f"))
|
||||||
|
|
||||||
|
def test_assemble_interactive(self):
|
||||||
|
mon = self._spawn()
|
||||||
|
|
||||||
|
mon.sendline(unicode("assemble 0"))
|
||||||
|
mon.expect_exact(unicode("$0000"))
|
||||||
|
|
||||||
|
mon.sendline(unicode("lda $1234"))
|
||||||
|
mon.expect_exact(unicode("ad 34 12"))
|
||||||
|
|
||||||
|
mon.expect_exact(unicode("$0003"))
|
||||||
|
mon.sendline(unicode("sta $4567"))
|
||||||
|
mon.expect_exact(unicode("8d 67 45"))
|
||||||
|
|
||||||
|
mon.sendline(unicode("invalid"))
|
||||||
|
mon.expect_exact(unicode("?Syntax"))
|
||||||
|
|
||||||
|
mon.sendline()
|
||||||
|
mon.sendline(unicode("quit"))
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
|
@ -2,11 +2,13 @@ import unittest
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
import tempfile
|
import tempfile
|
||||||
|
|
||||||
from io import StringIO
|
|
||||||
|
|
||||||
from py65.monitor import Monitor
|
from py65.monitor import Monitor
|
||||||
|
|
||||||
|
try:
|
||||||
|
from StringIO import StringIO
|
||||||
|
except ImportError: # Python 3
|
||||||
|
from io import StringIO
|
||||||
|
|
||||||
|
|
||||||
class MonitorTests(unittest.TestCase):
|
class MonitorTests(unittest.TestCase):
|
||||||
|
|
||||||
|
@ -539,6 +541,46 @@ class MonitorTests(unittest.TestCase):
|
||||||
mon.do_goto('0')
|
mon.do_goto('0')
|
||||||
self.assertEqual(0x02, mon._mpu.pc)
|
self.assertEqual(0x02, mon._mpu.pc)
|
||||||
|
|
||||||
|
# go
|
||||||
|
|
||||||
|
def test_shortcut_for_go(self):
|
||||||
|
stdout = StringIO()
|
||||||
|
mon = Monitor(stdout=stdout)
|
||||||
|
mon.do_help('go')
|
||||||
|
|
||||||
|
out = stdout.getvalue()
|
||||||
|
self.assertTrue(out.startswith('go'))
|
||||||
|
|
||||||
|
def test_go_with_breakpoints_stops_execution_at_breakpoint(self):
|
||||||
|
stdout = StringIO()
|
||||||
|
mon = Monitor(stdout=stdout)
|
||||||
|
mon._breakpoints = [ 0x03 ]
|
||||||
|
mon._mpu.memory = [ 0xEA, 0xEA, 0xEA, 0xEA ]
|
||||||
|
mon._mpu.pc = 0x00
|
||||||
|
mon.do_go('')
|
||||||
|
out = stdout.getvalue()
|
||||||
|
self.assertTrue(out.startswith("Breakpoint 0 reached"))
|
||||||
|
self.assertEqual(0x03, mon._mpu.pc)
|
||||||
|
|
||||||
|
def test_go_with_breakpoints_stops_execution_at_brk(self):
|
||||||
|
stdout = StringIO()
|
||||||
|
mon = Monitor(stdout=stdout)
|
||||||
|
mon._breakpoints = [ 0x02 ]
|
||||||
|
mon._mpu.memory = [ 0xEA, 0xEA, 0x00, 0xEA ]
|
||||||
|
mon._mpu.pc = 0x00
|
||||||
|
mon.do_go('')
|
||||||
|
self.assertEqual(0x02, mon._mpu.pc)
|
||||||
|
|
||||||
|
def test_go_without_breakpoints_stops_execution_at_brk(self):
|
||||||
|
stdout = StringIO()
|
||||||
|
mon = Monitor(stdout=stdout)
|
||||||
|
mon._breakpoints = []
|
||||||
|
mon._mpu.memory = [ 0xEA, 0xEA, 0x00, 0xEA ]
|
||||||
|
mon._mpu.pc = 0x00
|
||||||
|
mon.do_go('')
|
||||||
|
self.assertEqual(0x02, mon._mpu.pc)
|
||||||
|
|
||||||
|
|
||||||
# help
|
# help
|
||||||
|
|
||||||
def test_help_without_args_shows_documented_commands(self):
|
def test_help_without_args_shows_documented_commands(self):
|
||||||
|
|
|
@ -61,7 +61,7 @@ class AddressParser(object):
|
||||||
return self.labels[num]
|
return self.labels[num]
|
||||||
|
|
||||||
else:
|
else:
|
||||||
matches = re.match('^([^\s+-]+)\s*([+\-])\s*([$+%]?\d+)$', num)
|
matches = re.match(r'^([^\s+-]+)\s*([+\-])\s*([$+%]?\d+)$', num)
|
||||||
if matches:
|
if matches:
|
||||||
label, sign, offset = matches.groups()
|
label, sign, offset = matches.groups()
|
||||||
|
|
||||||
|
@ -88,7 +88,7 @@ class AddressParser(object):
|
||||||
"""Parse a string containing an address or a range of addresses
|
"""Parse a string containing an address or a range of addresses
|
||||||
into a tuple of (start address, end address)
|
into a tuple of (start address, end address)
|
||||||
"""
|
"""
|
||||||
matches = re.match('^([^:,]+)\s*[:,]+\s*([^:,]+)$', addresses)
|
matches = re.match(r'^([^:,]+)\s*[:,]+\s*([^:,]+)$', addresses)
|
||||||
if matches:
|
if matches:
|
||||||
start, end = map(self.number, matches.groups(0))
|
start, end = map(self.number, matches.groups(0))
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
from py65.compat import as_string
|
||||||
|
|
||||||
if sys.platform[:3] == "win":
|
if sys.platform[:3] == "win":
|
||||||
import msvcrt
|
import msvcrt
|
||||||
|
|
||||||
|
@ -24,10 +26,7 @@ if sys.platform[:3] == "win":
|
||||||
is available. Does not echo the character. The stdin argument is
|
is available. Does not echo the character. The stdin argument is
|
||||||
for function signature compatibility and is ignored.
|
for function signature compatibility and is ignored.
|
||||||
"""
|
"""
|
||||||
c = msvcrt.getch()
|
return as_string(msvcrt.getch())
|
||||||
if isinstance(c, bytes): # Python 3
|
|
||||||
c = c.decode('latin-1')
|
|
||||||
return c
|
|
||||||
|
|
||||||
def getch_noblock(stdin):
|
def getch_noblock(stdin):
|
||||||
""" Read one character from the Windows console without blocking.
|
""" Read one character from the Windows console without blocking.
|
||||||
|
@ -36,8 +35,8 @@ if sys.platform[:3] == "win":
|
||||||
available, an empty string is returned.
|
available, an empty string is returned.
|
||||||
"""
|
"""
|
||||||
if msvcrt.kbhit():
|
if msvcrt.kbhit():
|
||||||
return getch(stdin)
|
return as_string(getch(stdin))
|
||||||
return ''
|
return u''
|
||||||
|
|
||||||
else:
|
else:
|
||||||
import termios
|
import termios
|
||||||
|
@ -157,7 +156,7 @@ else:
|
||||||
# use select to make sure there is at least one char to read.
|
# use select to make sure there is at least one char to read.
|
||||||
rd,wr,er = select([stdin], [], [], 0.01)
|
rd,wr,er = select([stdin], [], [], 0.01)
|
||||||
if rd != []:
|
if rd != []:
|
||||||
char = stdin.read(1)
|
char = as_string(stdin.read(1))
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
# Pass along a CTRL-C interrupt.
|
# Pass along a CTRL-C interrupt.
|
||||||
raise
|
raise
|
||||||
|
@ -180,7 +179,7 @@ else:
|
||||||
# use select to make sure there is at least one char to read.
|
# use select to make sure there is at least one char to read.
|
||||||
rd,wr,er = select([stdin], [], [], 0.01)
|
rd,wr,er = select([stdin], [], [], 0.01)
|
||||||
if rd != []:
|
if rd != []:
|
||||||
char = stdin.read(1)
|
char = as_string(stdin.read(1))
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
# Pass along a CTRL-C interrupt.
|
# Pass along a CTRL-C interrupt.
|
||||||
raise
|
raise
|
||||||
|
@ -200,6 +199,7 @@ def line_input(prompt='', stdin=sys.stdin, stdout=sys.stdout):
|
||||||
is useful in modes like the interactive assembler.
|
is useful in modes like the interactive assembler.
|
||||||
"""
|
"""
|
||||||
stdout.write(prompt)
|
stdout.write(prompt)
|
||||||
|
stdout.flush()
|
||||||
line = ''
|
line = ''
|
||||||
while True:
|
while True:
|
||||||
char = getch(stdin)
|
char = getch(stdin)
|
||||||
|
@ -211,6 +211,7 @@ def line_input(prompt='', stdin=sys.stdin, stdout=sys.stdout):
|
||||||
line = line[:-1]
|
line = line[:-1]
|
||||||
stdout.write("\r%s\r%s%s" %
|
stdout.write("\r%s\r%s%s" %
|
||||||
(' ' * (len(prompt + line) + 5), prompt, line))
|
(' ' * (len(prompt + line) + 5), prompt, line))
|
||||||
|
stdout.flush()
|
||||||
elif code == 0x1b: # escape
|
elif code == 0x1b: # escape
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
|
|
16
setup.py
16
setup.py
|
@ -1,11 +1,16 @@
|
||||||
__version__ = '2.0.0.dev0'
|
__version__ = '1.3.0.dev0'
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
py_version = sys.version_info[:2]
|
py_version = sys.version_info[:2]
|
||||||
|
PY3 = py_version[0] == 3
|
||||||
|
|
||||||
if py_version < (3, 6):
|
if PY3:
|
||||||
raise RuntimeError('On Python 3, Py65 requires Python 3.6 or later')
|
if py_version < (3, 4):
|
||||||
|
raise RuntimeError('On Python 3, Py65 requires Python 3.4 or later')
|
||||||
|
else:
|
||||||
|
if py_version < (2, 7):
|
||||||
|
raise RuntimeError('On Python 2, Py65 requires Python 2.7 or later')
|
||||||
|
|
||||||
from setuptools import setup, find_packages
|
from setuptools import setup, find_packages
|
||||||
|
|
||||||
|
@ -19,13 +24,18 @@ CLASSIFIERS = [
|
||||||
'Natural Language :: English',
|
'Natural Language :: English',
|
||||||
'Operating System :: POSIX',
|
'Operating System :: POSIX',
|
||||||
'Programming Language :: Python',
|
'Programming Language :: Python',
|
||||||
|
'Programming Language :: Python :: 2',
|
||||||
|
'Programming Language :: Python :: 2.7',
|
||||||
'Programming Language :: Python :: 3',
|
'Programming Language :: Python :: 3',
|
||||||
|
'Programming Language :: Python :: 3.4',
|
||||||
|
'Programming Language :: Python :: 3.5',
|
||||||
'Programming Language :: Python :: 3.6',
|
'Programming Language :: Python :: 3.6',
|
||||||
'Programming Language :: Python :: 3.7',
|
'Programming Language :: Python :: 3.7',
|
||||||
'Programming Language :: Python :: 3.8',
|
'Programming Language :: Python :: 3.8',
|
||||||
'Programming Language :: Python :: 3.9',
|
'Programming Language :: Python :: 3.9',
|
||||||
'Programming Language :: Python :: 3.10',
|
'Programming Language :: Python :: 3.10',
|
||||||
'Programming Language :: Python :: 3.11',
|
'Programming Language :: Python :: 3.11',
|
||||||
|
'Programming Language :: Python :: 3.12',
|
||||||
'Programming Language :: Assembly',
|
'Programming Language :: Assembly',
|
||||||
'Topic :: Software Development :: Assemblers',
|
'Topic :: Software Development :: Assemblers',
|
||||||
'Topic :: Software Development :: Disassemblers',
|
'Topic :: Software Development :: Disassemblers',
|
||||||
|
|
Loading…
Reference in New Issue
Block a user