Skip to content

Commit

Permalink
do the ' <-> :' and ELSE <-> :ELSE replacement internaly
Browse files Browse the repository at this point in the history
  • Loading branch information
jedie committed Aug 20, 2014
1 parent d64f5c0 commit ce12148
Show file tree
Hide file tree
Showing 6 changed files with 313 additions and 43 deletions.
6 changes: 5 additions & 1 deletion dragonlib/api.py
Expand Up @@ -49,10 +49,14 @@ def ascii_listing2program_dump(self, basic_program_ascii, program_start=None):
"""
if program_start is None:
program_start = self.DEFAULT_PROGRAM_START
# return self.listing.ascii_listing2program_dump(basic_program_ascii, program_start)

parser = BASICParser()
parsed_lines = parser.parse(basic_program_ascii)
if not parsed_lines:
log.critical("No parsed lines %s from %s ?!?" % (
repr(parsed_lines), repr(basic_program_ascii)
))
log.info("Parsed BASIC: %s", repr(parsed_lines))

basic_lines = []
for line_no, code_objects in sorted(parsed_lines.items()):
Expand Down
58 changes: 53 additions & 5 deletions dragonlib/core/basic.py
Expand Up @@ -14,7 +14,9 @@
import re

from dragonlib.core import basic_parser
from dragonlib.utils.logging_utils import log, log_program_dump
from dragonlib.utils.iter_utils import list_replace
from dragonlib.utils.logging_utils import log, log_program_dump,\
pformat_byte_hex_list
from dragonpy.utils.byte_word_values import word2bytes


Expand Down Expand Up @@ -74,7 +76,20 @@ def code_objects2token(self, code_objects):
for code_object in code_objects:
if code_object.PART_TYPE == basic_parser.CODE_TYPE_CODE:
# Code part
tokens += self.ascii2token(code_object.content)
content = code_object.content
"""
NOTE: The BASIC interpreter changed REM shortcut and ELSE
internaly:
"'" <-> ":'"
"ELSE" <-> ":ELSE"
See also:
http://archive.worldofdragon.org/phpBB3/viewtopic.php?f=8&t=4310&p=11632#p11630
"""
log.info("replace ' and ELSE with :' and :ELSE")
content=content.replace("'", ":'")
content=content.replace("ELSE", ":ELSE")
tokens += self.ascii2token(content)
else:
# Strings, Comments or DATA
tokens += self.chars2tokens(code_object.content)
Expand Down Expand Up @@ -112,12 +127,41 @@ def __init__(self, token_util):
self.token_util = token_util
self.line_number = None
self.line_code = None

try:
colon_token = self.token_util.ascii2token_dict[":"]
except KeyError: # XXX: Always not defined as token?
colon_token = ord(":")
rem_token = self.token_util.ascii2token_dict["'"]
else_token = self.token_util.ascii2token_dict["ELSE"]
self.tokens_replace_rules = (
((colon_token, rem_token), rem_token),
((colon_token, else_token), else_token),
)

def token_load(self, line_number, tokens):
self.line_number = line_number
assert tokens[-1] == 0x00, "line code %s doesn't ends with \\x00: %s" % (
repr(tokens), repr(tokens[-1])
)

"""
NOTE: The BASIC interpreter changed REM shortcut and ELSE
internaly:
"'" <-> ":'"
"ELSE" <-> ":ELSE"
See also:
http://archive.worldofdragon.org/phpBB3/viewtopic.php?f=8&t=4310&p=11632#p11630
"""
for src, dst in self.tokens_replace_rules:
log.info("Relace tokens %s with $%02x",
pformat_byte_hex_list(src), dst
)
log.debug("Before..: %s", pformat_byte_hex_list(tokens) )
tokens = list_replace(tokens, src, dst)
log.debug("After...: %s", pformat_byte_hex_list(tokens) )

self.line_code = tokens[:-1] # rstrip \x00

def ascii_load(self, line_ascii):
Expand Down Expand Up @@ -177,6 +221,11 @@ def dump2basic_lines(self, dump, program_start, basic_lines=None):
# program end
log.critical("return: %s", repr(basic_lines))
return basic_lines

assert next_address>program_start, "Next address $%04x not bigger than program start $%04x ?!?" % (
next_address,program_start
)

line_number = (dump[2] << 8) + dump[3]
log.critical("line_number: %i", line_number)
length = next_address - program_start
Expand Down Expand Up @@ -253,9 +302,8 @@ def pformat_program_dump(self, program_dump, program_start, formated_dump=None):
tokens = program_dump[4:length]
formated_dump.append("tokens:")
formated_dump += self.token_util.pformat_tokens(tokens)
rest = program_dump[length:]
print rest, next_address, formated_dump
return self.pformat_program_dump(rest, next_address, formated_dump)

return self.pformat_program_dump(program_dump[length:], next_address, formated_dump)

def debug_listing(self, basic_lines):
for line in basic_lines:
Expand Down
25 changes: 25 additions & 0 deletions dragonlib/tests/run_all_dragonlib_tests.py
@@ -0,0 +1,25 @@
#!/usr/bin/env python

"""
DragonPy - Dragon 32 emulator in Python
=======================================
:copyleft: 2014 by the DragonPy team, see AUTHORS for more details.
:license: GNU GPL v3 or above, see LICENSE for more details.
"""

import unittest

from dragonpy.tests.test_base import TextTestRunner2


if __name__ == "__main__":
loader = unittest.TestLoader()
tests = loader.discover('dragonlib')

test_runner = TextTestRunner2(verbosity=2,
# failfast=True,
)

test_runner.run(tests)
print " --- END --- "
188 changes: 153 additions & 35 deletions dragonlib/tests/test_api.py
Expand Up @@ -17,7 +17,9 @@
from dragonlib.api import Dragon32API
from dragonlib.core.basic import BasicLine
from dragonlib.tests.test_base import BaseTestCase
from dragonlib.utils.logging_utils import log, setup_logging, log_program_dump
from dragonlib.utils.logging_utils import log, setup_logging, log_program_dump,\
pformat_program_dump
from dragonpy.tests.test_base import TextTestRunner2


class BaseDragon32ApiTestCase(BaseTestCase):
Expand All @@ -29,6 +31,43 @@ def assertEqualProgramDump(self, first, second, msg=None):
second = self.dragon32api.pformat_program_dump(second)
self.assertEqual(first, second, msg)

def assertListing2Dump(self, ascii_listing,program_dump,debug=False):
if debug:
print "\n"+"_"*79
print " *** Debug Listing:\n%s" % ascii_listing
print " -"*39
print " *** Debug Dump:\n%s\n" % (
pformat_program_dump(program_dump)
)
print " -"*39

created_program_dump = self.dragon32api.ascii_listing2program_dump(
ascii_listing
)
if debug:
print " *** Created dump from listing:\n%s\n" % (
pformat_program_dump(created_program_dump)
)
print " -"*39

if not created_program_dump:
log.critical("Created dump empty? repr: %s", repr(created_program_dump))

if debug:
print " *** Full Dump:\n%s" % "\n".join(
self.dragon32api.pformat_program_dump(created_program_dump)
)
self.assertEqualProgramDump(created_program_dump, program_dump)

def assertDump2Listing(self, ascii_listing,program_dump):
# log_program_dump(created_program_dump)
# print "\n".join(
# self.dragon32api.pformat_program_dump(created_program_dump)
# )
created_listing = self.dragon32api.program_dump2ascii_lines(program_dump)
ascii_listing=ascii_listing.splitlines()
self.assertEqual(created_listing, ascii_listing)

def _prepare_text(self, txt):
"""
prepare the multiline, indentation text.
Expand Down Expand Up @@ -183,22 +222,13 @@ def test_ascii2RAM02(self):

def test_listing2program_strings_dont_in_comment(self):
"""
TODO: Don't replace tokens in comments
NOTE: The REM shortcut >'< would be replace by >:'< internally from
the BASIC Interpreter.
See also:
http://archive.worldofdragon.org/phpBB3/viewtopic.php?f=8&t=4310&p=11632#p11630
Don't replace tokens in comments
"""
program_dump = self.dragon32api.ascii_listing2program_dump(
"10 :'IF THEN ELSE"
)
print "\n".join(
self.dragon32api.pformat_program_dump(program_dump)
)
self.assertEqualProgramDump(program_dump, (
0x1e, 0x14, # next address
ascii_listing = self._prepare_text("""
10 'IF THEN ELSE"
""")
program_dump= (
0x1e, 0x15, # next address
0x00, 0x0a, # 10
0x3a, # :
0x83, # '
Expand All @@ -207,33 +237,120 @@ def test_listing2program_strings_dont_in_comment(self):
0x54, 0x48, 0x45, 0x4e, # T, H, E, N
0x20, # " "
0x45, 0x4c, 0x53, 0x45, # E, L, S, E
0x22, # "
0x00, # end of line
0x00, 0x00, # program end
))
)
self.assertListing2Dump(ascii_listing,program_dump,
# debug=True
)
self.assertDump2Listing(ascii_listing,program_dump)

def test_listing2program_strings_dont_in_strings(self):
"""
Don't replace tokens in strings
"""
program_dump = self.dragon32api.ascii_listing2program_dump(
'10 PRINT"FOR NEXT'
ascii_listing = self._prepare_text("""
10 PRINT"FOR NEXT
""")
program_dump= (
0x1e, 0x10, # next address
0x00, 0x0a, # 10
0x87, # PRINT
0x22, # "
0x46, 0x4f, 0x52, # F, O, R
0x20, # " "
0x4e, 0x45, 0x58, 0x54, # N, E, X, T
0x00, # end of line
0x00, 0x00, # program end
)
log_program_dump(program_dump)
print "\n".join(
self.dragon32api.pformat_program_dump(program_dump)
self.assertListing2Dump(ascii_listing,program_dump,
# debug=True
)
self.assertEqualProgramDump(program_dump, (
0x1e, 0x10, # start address
0x00, # line start
0x0a, # 10
0x87, # PRINT
0x22, # "
0x46, 0x4f, 0x52, # F, O, R
0x20, # " "
0x4e, 0x45, 0x58, 0x54, # N, E, X, T
self.assertDump2Listing(ascii_listing,program_dump)


def test_ascii_listing2program_dump_with_bigger_line_number(self):
"""
Don't replace tokens in strings
"""
ascii_listing = self._prepare_text("""
65000 CLS
""")
program_dump = (
0x1e, 0x07, # start address
0xfd, 0xe8, # 65000
0xa0, # CLS
0x00, # end of line
0x00, 0x00, # program end
))
)
self.assertListing2Dump(ascii_listing,program_dump)
self.assertDump2Listing(ascii_listing,program_dump)

def test_auto_add_colon_before_comment(self):
"""
NOTE: The REM shortcut >'< would be replace by >:'< internally from
the BASIC Interpreter.
See also:
http://archive.worldofdragon.org/phpBB3/viewtopic.php?f=8&t=4310&p=11632#p11630
"""
ascii_listing = self._prepare_text("""
100 'FOO
""")
program_dump = (
0x1e, 0x0b, # next address (length: 10)
0x00, 0x64, # 100 (line number)
0x3a, # : ===> Insert/remove it automaticly
0x83, # '
0x46, # F
0x4f, # O
0x4f, # O
0x00, # EOL
0x00, 0x00, # end address
)
self.assertListing2Dump(ascii_listing,program_dump,
debug=True
)
self.assertDump2Listing(ascii_listing,program_dump)

def test_auto_add_colon_before_else(self):
"""
NOTE: The REM shortcut >'< would be replace by >:'< internally from
the BASIC Interpreter.
See also:
http://archive.worldofdragon.org/phpBB3/viewtopic.php?f=8&t=4310&p=11632#p11630
"""
ascii_listing = self._prepare_text("""
100 IF A=1 THEN 10 ELSE 20
""")
program_dump = (
0x1e, 0x16, # -> next address (length: 21)
0x00, 0x64, # -> 100 (line number)
0x85, # -> 'IF'
0x20, # -> ' '
0x41, # -> 'A'
0xcb, # -> '='
0x31, # -> '1'
0x20, # -> ' '
0xbf, # -> 'THEN'
0x20, # -> ' '
0x31, # -> '1'
0x30, # -> '0'
0x20, # -> ' '
0x3a, # : ===> Insert/remove it automaticly
0x84, # -> 'ELSE'
0x20, # -> ' '
0x32, # -> '2'
0x30, # -> '0'
0x00, # -> EOL
0x00, 0x00, # -> end address
)
self.assertListing2Dump(ascii_listing,program_dump,
debug=True
)
self.assertDump2Listing(ascii_listing,program_dump)


class RenumTests(BaseDragon32ApiTestCase):
Expand Down Expand Up @@ -339,17 +456,18 @@ def test_on_gosub_dont_exists(self):
if __name__ == '__main__':
setup_logging(log,
# level=1 # hardcore debug ;)
# level=10 # DEBUG
# level=20 # INFO
# level=10 # DEBUG
# level=20 # INFO
# level=30 # WARNING
# level=40 # ERROR
level=50 # CRITICAL/FATAL
)

unittest.main(
testRunner= TextTestRunner2,
argv=(
sys.argv[0],
# "Dragon32BASIC_HighLevel_ApiTest",
# "Dragon32BASIC_HighLevel_ApiTest.test_listing2program_strings_dont_in_comment",
),
# verbosity=1,
verbosity=2,
Expand Down

0 comments on commit ce12148

Please sign in to comment.