mirror of
https://github.com/mnaberez/py65.git
synced 2024-09-27 09:55:23 +00:00
Fix interactive assembly on Python 3
Closes #81 Closes #78 Closes #65 Closes #64 Closes #63
This commit is contained in:
parent
8dce37f6b8
commit
1870d65982
20
.github/workflows/main.yml
vendored
20
.github/workflows/main.yml
vendored
@ -21,11 +21,14 @@ jobs:
|
|||||||
run: python -V
|
run: python -V
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: $PIP install setuptools
|
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
|
||||||
|
|
||||||
build_py34:
|
build_py34:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
container: python:3.4
|
container: python:3.4
|
||||||
@ -44,11 +47,14 @@ jobs:
|
|||||||
run: python -V
|
run: python -V
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: $PIP install setuptools
|
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
|
||||||
|
|
||||||
build_py35:
|
build_py35:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
container: python:3.5
|
container: python:3.5
|
||||||
@ -62,11 +68,14 @@ jobs:
|
|||||||
run: python -V
|
run: python -V
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: $PIP install setuptools
|
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
|
||||||
|
|
||||||
build_py3x:
|
build_py3x:
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
@ -88,7 +97,10 @@ jobs:
|
|||||||
run: python -V
|
run: python -V
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: $PIP install setuptools
|
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
|
||||||
|
@ -5,6 +5,8 @@
|
|||||||
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.
|
- 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
|
||||||
|
@ -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)
|
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()
|
@ -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:
|
||||||
|
Loading…
Reference in New Issue
Block a user