mirror of
https://github.com/irmen/prog8.git
synced 2026-04-19 20:16:51 +00:00
moved
This commit is contained in:
@@ -0,0 +1 @@
|
||||
# package
|
||||
@@ -0,0 +1,60 @@
|
||||
import pytest
|
||||
from il65.datatypes import FLOAT_MAX_NEGATIVE, FLOAT_MAX_POSITIVE
|
||||
from il65.codegen.shared import to_hex, to_mflpt5
|
||||
|
||||
|
||||
def test_to_hex():
|
||||
assert to_hex(0) == "0"
|
||||
assert to_hex(1) == "1"
|
||||
assert to_hex(10) == "10"
|
||||
assert to_hex(15) == "15"
|
||||
assert to_hex(16) == "$10"
|
||||
assert to_hex(255) == "$ff"
|
||||
assert to_hex(256) == "$0100"
|
||||
assert to_hex(20060) == "$4e5c"
|
||||
assert to_hex(65535) == "$ffff"
|
||||
with pytest.raises(OverflowError):
|
||||
to_hex(-1)
|
||||
with pytest.raises(OverflowError):
|
||||
to_hex(65536)
|
||||
|
||||
|
||||
def test_float_to_mflpt5():
|
||||
mflpt = to_mflpt5(1.0)
|
||||
assert type(mflpt) is bytearray
|
||||
assert b"\x00\x00\x00\x00\x00" == to_mflpt5(0)
|
||||
assert b"\x82\x49\x0F\xDA\xA1" == to_mflpt5(3.141592653)
|
||||
assert b"\x82\x49\x0F\xDA\xA2" == to_mflpt5(3.141592653589793)
|
||||
assert b"\x90\x80\x00\x00\x00" == to_mflpt5(-32768)
|
||||
assert b"\x81\x00\x00\x00\x00" == to_mflpt5(1)
|
||||
assert b"\x80\x35\x04\xF3\x34" == to_mflpt5(0.7071067812)
|
||||
assert b"\x80\x35\x04\xF3\x33" == to_mflpt5(0.7071067811865476)
|
||||
assert b"\x81\x35\x04\xF3\x34" == to_mflpt5(1.4142135624)
|
||||
assert b"\x81\x35\x04\xF3\x33" == to_mflpt5(1.4142135623730951)
|
||||
assert b"\x80\x80\x00\x00\x00" == to_mflpt5(-.5)
|
||||
assert b"\x80\x31\x72\x17\xF8" == to_mflpt5(0.69314718061)
|
||||
assert b"\x80\x31\x72\x17\xF7" == to_mflpt5(0.6931471805599453)
|
||||
assert b"\x84\x20\x00\x00\x00" == to_mflpt5(10)
|
||||
assert b"\x9E\x6E\x6B\x28\x00" == to_mflpt5(1000000000)
|
||||
assert b"\x80\x00\x00\x00\x00" == to_mflpt5(.5)
|
||||
assert b"\x81\x38\xAA\x3B\x29" == to_mflpt5(1.4426950408889634)
|
||||
assert b"\x81\x49\x0F\xDA\xA2" == to_mflpt5(1.5707963267948966)
|
||||
assert b"\x83\x49\x0F\xDA\xA2" == to_mflpt5(6.283185307179586)
|
||||
assert b"\x7F\x00\x00\x00\x00" == to_mflpt5(.25)
|
||||
|
||||
|
||||
def test_float_range():
|
||||
assert b"\xff\x7f\xff\xff\xff" == to_mflpt5(FLOAT_MAX_POSITIVE)
|
||||
assert b"\xff\xff\xff\xff\xff" == to_mflpt5(FLOAT_MAX_NEGATIVE)
|
||||
with pytest.raises(OverflowError):
|
||||
to_mflpt5(1.7014118346e+38)
|
||||
with pytest.raises(OverflowError):
|
||||
to_mflpt5(-1.7014118346e+38)
|
||||
with pytest.raises(OverflowError):
|
||||
to_mflpt5(1.7014118347e+38)
|
||||
with pytest.raises(OverflowError):
|
||||
to_mflpt5(-1.7014118347e+38)
|
||||
assert b"\x03\x39\x1d\x15\x63" == to_mflpt5(1.7e-38)
|
||||
assert b"\x00\x00\x00\x00\x00" == to_mflpt5(1.7e-39)
|
||||
assert b"\x03\xb9\x1d\x15\x63" == to_mflpt5(-1.7e-38)
|
||||
assert b"\x00\x00\x00\x00\x00" == to_mflpt5(-1.7e-39)
|
||||
@@ -0,0 +1,102 @@
|
||||
import pytest
|
||||
from il65.datatypes import DataType, STRING_DATATYPES, char_to_bytevalue
|
||||
from il65.plyparse import coerce_constant_value, LiteralValue, Scope, SymbolName, VarDef
|
||||
from il65.compile import ParseError
|
||||
from il65.plylex import SourceRef
|
||||
|
||||
|
||||
def test_datatypes():
|
||||
assert all(isinstance(s, DataType) for s in STRING_DATATYPES)
|
||||
assert all(s.isstring() for s in STRING_DATATYPES)
|
||||
assert not any(s.isarray() or s.isnumeric() for s in STRING_DATATYPES)
|
||||
assert DataType.WORDARRAY.isarray()
|
||||
assert not DataType.WORDARRAY.isnumeric()
|
||||
assert not DataType.WORDARRAY.isstring()
|
||||
assert not DataType.WORD.isarray()
|
||||
assert DataType.WORD.isnumeric()
|
||||
assert not DataType.WORD.isstring()
|
||||
|
||||
|
||||
def test_sourceref():
|
||||
s = SourceRef("file", 99, 42)
|
||||
assert str(s) == "file:99:42"
|
||||
s = SourceRef("file", 99)
|
||||
assert str(s) == "file:99"
|
||||
|
||||
|
||||
def test_parseerror():
|
||||
p = ParseError("message", SourceRef("filename", 99, 42))
|
||||
assert p.args == ("message", )
|
||||
assert str(p) == "filename:99:42 message"
|
||||
|
||||
|
||||
def test_char_to_bytevalue():
|
||||
assert char_to_bytevalue('a') == 65
|
||||
assert char_to_bytevalue('\n') == 13
|
||||
assert char_to_bytevalue('π') == 126
|
||||
assert char_to_bytevalue('▒') == 230
|
||||
assert char_to_bytevalue('\x00') == 0
|
||||
assert char_to_bytevalue('\xff') == 255
|
||||
with pytest.raises(AssertionError):
|
||||
char_to_bytevalue('<undefined>')
|
||||
# screencodes not yet implemented: assert datatypes.char_to_bytevalue('a', False) == 65
|
||||
|
||||
|
||||
def test_coerce_value_novars():
|
||||
sref = SourceRef("test", 1, 1)
|
||||
def lv(v) -> LiteralValue:
|
||||
return LiteralValue(value=v, sourceref=sref) # type: ignore
|
||||
assert coerce_constant_value(DataType.BYTE, lv(0)) == (False, lv(0))
|
||||
assert coerce_constant_value(DataType.BYTE, lv(255)) == (False, lv(255))
|
||||
assert coerce_constant_value(DataType.BYTE, lv('@')) == (True, lv(64))
|
||||
assert coerce_constant_value(DataType.WORD, lv(0)) == (False, lv(0))
|
||||
assert coerce_constant_value(DataType.WORD, lv(65535)) == (False, lv(65535))
|
||||
assert coerce_constant_value(DataType.WORD, lv('@')) == (True, lv(64))
|
||||
assert coerce_constant_value(DataType.FLOAT, lv(-999.22)) == (False, lv(-999.22))
|
||||
assert coerce_constant_value(DataType.FLOAT, lv(123.45)) == (False, lv(123.45))
|
||||
assert coerce_constant_value(DataType.FLOAT, lv('@')) == (True, lv(64))
|
||||
assert coerce_constant_value(DataType.BYTE, lv(5.678)) == (True, lv(5))
|
||||
assert coerce_constant_value(DataType.WORD, lv(5.678)) == (True, lv(5))
|
||||
assert coerce_constant_value(DataType.WORD,
|
||||
lv("string")) == (False, lv("string")), "string (address) can be assigned to a word"
|
||||
assert coerce_constant_value(DataType.STRING, lv("string")) == (False, lv("string"))
|
||||
assert coerce_constant_value(DataType.STRING_P, lv("string")) == (False, lv("string"))
|
||||
assert coerce_constant_value(DataType.STRING_S, lv("string")) == (False, lv("string"))
|
||||
assert coerce_constant_value(DataType.STRING_PS, lv("string")) == (False, lv("string"))
|
||||
with pytest.raises(OverflowError):
|
||||
coerce_constant_value(DataType.BYTE, lv(-1))
|
||||
with pytest.raises(OverflowError):
|
||||
coerce_constant_value(DataType.BYTE, lv(256))
|
||||
with pytest.raises(OverflowError):
|
||||
coerce_constant_value(DataType.BYTE, lv(256.12345))
|
||||
with pytest.raises(OverflowError):
|
||||
coerce_constant_value(DataType.WORD, lv(-1))
|
||||
with pytest.raises(OverflowError):
|
||||
coerce_constant_value(DataType.WORD, lv(65536))
|
||||
with pytest.raises(OverflowError):
|
||||
coerce_constant_value(DataType.WORD, lv(65536.12345))
|
||||
with pytest.raises(OverflowError):
|
||||
coerce_constant_value(DataType.FLOAT, lv(-1.7014118346e+38))
|
||||
with pytest.raises(OverflowError):
|
||||
coerce_constant_value(DataType.FLOAT, lv(1.7014118347e+38))
|
||||
with pytest.raises(TypeError):
|
||||
coerce_constant_value(DataType.BYTE, lv("string"))
|
||||
with pytest.raises(TypeError):
|
||||
coerce_constant_value(DataType.FLOAT, lv("string"))
|
||||
|
||||
|
||||
def test_coerce_value_vars():
|
||||
sref = SourceRef("test", 1, 1)
|
||||
scope = Scope(nodes=[], level="block", sourceref=sref)
|
||||
vardef = VarDef(name="constantvar", vartype="const", datatype=None, sourceref=sref)
|
||||
vardef.value = LiteralValue(value=99, sourceref=sref)
|
||||
scope.add_node(vardef)
|
||||
vardef = VarDef(name="varvar", vartype="var", datatype=None, sourceref=sref)
|
||||
vardef.value = LiteralValue(value=42, sourceref=sref)
|
||||
scope.add_node(vardef)
|
||||
vardef = VarDef(name="memvar", vartype="memory", datatype=None, sourceref=sref)
|
||||
vardef.value = LiteralValue(value=0xc000, sourceref=sref)
|
||||
scope.add_node(vardef)
|
||||
value = SymbolName(name="constantvar", sourceref=sref)
|
||||
value.parent = scope
|
||||
assert coerce_constant_value(DataType.BYTE, value) == (True, LiteralValue(value=99, sourceref=sref))
|
||||
@@ -0,0 +1,92 @@
|
||||
import pytest
|
||||
from il65.plyparse import IncrDecr, AugAssignment, VarDef, SymbolName
|
||||
from il65.optimize import optimize
|
||||
from .test_parser import parse_source
|
||||
|
||||
|
||||
def test_incrdecr_joins_nonfloat():
|
||||
src = """~ test {
|
||||
X ++
|
||||
X ++
|
||||
X += 10
|
||||
Y--
|
||||
Y--
|
||||
Y-=20
|
||||
}"""
|
||||
result = parse_source(src)
|
||||
testscope = result.scope.nodes[0].nodes[0]
|
||||
assert len(testscope.nodes) == 6
|
||||
assert isinstance(testscope.nodes[0], IncrDecr)
|
||||
assert testscope.nodes[0].howmuch == 1
|
||||
assert isinstance(testscope.nodes[1], IncrDecr)
|
||||
assert testscope.nodes[1].howmuch == 1
|
||||
assert isinstance(testscope.nodes[2], AugAssignment)
|
||||
assert testscope.nodes[2].right.value == 10
|
||||
assert isinstance(testscope.nodes[3], IncrDecr)
|
||||
assert testscope.nodes[3].howmuch == 1
|
||||
assert isinstance(testscope.nodes[4], IncrDecr)
|
||||
assert testscope.nodes[4].howmuch == 1
|
||||
assert isinstance(testscope.nodes[5], AugAssignment)
|
||||
assert testscope.nodes[5].right.value == 20
|
||||
# now optimize the incrdecrs (joins them)
|
||||
optimize(result)
|
||||
testscope = result.scope.nodes[0].nodes[0]
|
||||
assert len(testscope.nodes) == 2 # @todo broken optimization right now
|
||||
assert isinstance(testscope.nodes[0], IncrDecr)
|
||||
assert testscope.nodes[0].operator == "++"
|
||||
assert testscope.nodes[0].howmuch == 12
|
||||
assert isinstance(testscope.nodes[1], IncrDecr)
|
||||
assert testscope.nodes[1].operator == "--"
|
||||
assert testscope.nodes[1].howmuch == 22
|
||||
|
||||
|
||||
def test_incrdecr_joins_float():
|
||||
src = """~ test {
|
||||
var .float flt = 0
|
||||
flt ++
|
||||
flt ++
|
||||
flt += 10
|
||||
flt --
|
||||
flt --
|
||||
flt --
|
||||
flt -= 5
|
||||
}"""
|
||||
result = parse_source(src)
|
||||
testscope = result.scope.nodes[0].nodes[0]
|
||||
assert len(testscope.nodes) == 8
|
||||
# now optimize the incrdecrs (joins them)
|
||||
optimize(result)
|
||||
testscope = result.scope.nodes[0].nodes[0]
|
||||
assert len(testscope.nodes) == 2
|
||||
assert isinstance(testscope.nodes[0], VarDef)
|
||||
assert isinstance(testscope.nodes[1], IncrDecr)
|
||||
assert testscope.nodes[1].operator == "++"
|
||||
assert testscope.nodes[1].howmuch == 4
|
||||
assert isinstance(testscope.nodes[1].target, SymbolName)
|
||||
assert testscope.nodes[1].target.name == "flt"
|
||||
|
||||
|
||||
def test_large_incrdecr_to_augassign():
|
||||
src = """~ test {
|
||||
X ++
|
||||
X ++
|
||||
X += 255
|
||||
Y --
|
||||
Y --
|
||||
Y -= 255
|
||||
}"""
|
||||
result = parse_source(src)
|
||||
testscope = result.scope.nodes[0].nodes[0]
|
||||
assert len(testscope.nodes) == 6
|
||||
# now optimize; joins the incrdecrs then converts to augassign because values are too large.
|
||||
optimize(result)
|
||||
testscope = result.scope.nodes[0].nodes[0]
|
||||
assert len(testscope.nodes) == 2
|
||||
assert isinstance(testscope.nodes[0], AugAssignment)
|
||||
assert testscope.nodes[0].left.name == "X"
|
||||
assert testscope.nodes[0].operator == "+="
|
||||
assert testscope.nodes[0].right.value == 257
|
||||
assert isinstance(testscope.nodes[1], AugAssignment)
|
||||
assert testscope.nodes[1].left.name == "Y"
|
||||
assert testscope.nodes[1].operator == "-="
|
||||
assert testscope.nodes[1].right.value == 257
|
||||
@@ -0,0 +1,544 @@
|
||||
import math
|
||||
import pytest
|
||||
from il65.plylex import lexer, tokens, find_tok_column, literals, reserved, SourceRef
|
||||
from il65.plyparse import *
|
||||
from il65.datatypes import DataType, VarType
|
||||
from il65.constantfold import ConstantFold
|
||||
|
||||
|
||||
def lexer_error(sourceref: SourceRef, fmtstring: str, *args: str) -> None:
|
||||
print("ERROR: {}: {}".format(sourceref, fmtstring.format(*args)))
|
||||
|
||||
|
||||
def parse_source(src: str) -> AstNode:
|
||||
lexer.lineno = 1
|
||||
lexer.source_filename = "sourcefile"
|
||||
tfilt = TokenFilter(lexer)
|
||||
result = parser.parse(input=src, tokenfunc=tfilt.token)
|
||||
connect_parents(result, None)
|
||||
return result
|
||||
|
||||
|
||||
lexer.error_function = lexer_error
|
||||
|
||||
|
||||
def test_lexer_definitions():
|
||||
assert "ENDL" in tokens
|
||||
assert "GOTO" in tokens
|
||||
assert '+' in literals
|
||||
assert ';' not in literals
|
||||
assert "return" in reserved
|
||||
assert "sub" in reserved
|
||||
assert "A" in reserved
|
||||
assert "if_cc" in reserved
|
||||
|
||||
|
||||
test_source_1 = """ %output prg, sys
|
||||
|
||||
; c1
|
||||
|
||||
; c2
|
||||
|
||||
|
||||
~ block $c000 {
|
||||
%import a,b
|
||||
|
||||
|
||||
; comment
|
||||
|
||||
var foo = 42+true
|
||||
var .matrix(20,30) m = 9.234556
|
||||
;comment2
|
||||
|
||||
|
||||
sub calculate () -> () {
|
||||
return
|
||||
}
|
||||
|
||||
;z
|
||||
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
def test_lexer():
|
||||
lexer.input(test_source_1)
|
||||
lexer.lineno = 1
|
||||
tokens = list(iter(lexer))
|
||||
token_types = list(t.type for t in tokens)
|
||||
assert token_types == ['DIRECTIVE', 'NAME', ',', 'NAME', 'ENDL', 'ENDL', 'ENDL',
|
||||
'BITINVERT', 'NAME', 'INTEGER', '{', 'ENDL',
|
||||
'DIRECTIVE', 'NAME', ',', 'NAME', 'ENDL', 'ENDL',
|
||||
'VARTYPE', 'NAME', 'IS', 'INTEGER', '+', 'BOOLEAN', 'ENDL',
|
||||
'VARTYPE', 'DATATYPE', '(', 'INTEGER', ',', 'INTEGER', ')', 'NAME', 'IS', 'FLOATINGPOINT', 'ENDL', 'ENDL',
|
||||
'SUB', 'NAME', '(', ')', 'RARROW', '(', ')', '{', 'ENDL', 'RETURN', 'ENDL', '}', 'ENDL', 'ENDL', 'ENDL', 'ENDL',
|
||||
'}', 'ENDL']
|
||||
directive_token = tokens[12]
|
||||
assert directive_token.type == "DIRECTIVE"
|
||||
assert directive_token.value == "import"
|
||||
assert directive_token.lineno == 9
|
||||
assert directive_token.lexpos == lexer.lexdata.index("%import")
|
||||
assert find_tok_column(directive_token) == 10
|
||||
bool_token = tokens[23]
|
||||
assert bool_token.type == "BOOLEAN"
|
||||
assert type(bool_token.value) is bool
|
||||
assert bool_token.value == True
|
||||
|
||||
|
||||
def test_lexer_strings():
|
||||
lexer.input(r"'hello\tbye\n\n' '\n'")
|
||||
lexer.lineno = 1
|
||||
tokens = list(iter(lexer))
|
||||
assert len(tokens) == 2
|
||||
st = tokens[0]
|
||||
assert st.type == "STRING"
|
||||
assert st.value == "hello\tbye\n\n"
|
||||
lexer.input(r"'hello\tbye\n\n'")
|
||||
st = tokens[1]
|
||||
assert st.type == "CHARACTER"
|
||||
assert st.value == '\n'
|
||||
|
||||
|
||||
def test_tokenfilter():
|
||||
lexer.input(test_source_1)
|
||||
lexer.lineno = 1
|
||||
filter = TokenFilter(lexer)
|
||||
tokens = []
|
||||
while True:
|
||||
token = filter.token()
|
||||
if not token:
|
||||
break
|
||||
tokens.append(token)
|
||||
token_types = list(t.type for t in tokens)
|
||||
assert token_types == ['DIRECTIVE', 'NAME', ',', 'NAME', 'ENDL',
|
||||
'BITINVERT', 'NAME', 'INTEGER', '{', 'ENDL',
|
||||
'DIRECTIVE', 'NAME', ',', 'NAME', 'ENDL',
|
||||
'VARTYPE', 'NAME', 'IS', 'INTEGER', '+', 'BOOLEAN', 'ENDL',
|
||||
'VARTYPE', 'DATATYPE', '(', 'INTEGER', ',', 'INTEGER', ')', 'NAME', 'IS', 'FLOATINGPOINT', 'ENDL',
|
||||
'SUB', 'NAME', '(', ')', 'RARROW', '(', ')', '{', 'ENDL', 'RETURN', 'ENDL', '}', 'ENDL',
|
||||
'}', 'ENDL']
|
||||
|
||||
|
||||
def test_parser():
|
||||
result = parse_source(test_source_1)
|
||||
assert isinstance(result, Module)
|
||||
assert result.name == "sourcefile"
|
||||
assert result.scope.name == "<sourcefile global scope>"
|
||||
assert result.subroutine_usage == {}
|
||||
assert result.scope.parent_scope is None
|
||||
sub = result.scope.lookup("block.calculate")
|
||||
assert isinstance(sub, Subroutine)
|
||||
assert sub.name == "calculate"
|
||||
block = result.scope.lookup("block")
|
||||
assert isinstance(block, Block)
|
||||
assert block.name == "block"
|
||||
bool_vdef = block.scope.nodes[1]
|
||||
assert isinstance(bool_vdef, VarDef)
|
||||
assert isinstance(bool_vdef.value, ExpressionWithOperator)
|
||||
assert isinstance(bool_vdef.value.right, LiteralValue)
|
||||
assert isinstance(bool_vdef.value.right.value, int)
|
||||
assert bool_vdef.value.right.value == 1
|
||||
assert block.address == 49152
|
||||
sub2 = block.scope.lookup("calculate")
|
||||
assert sub2 is sub
|
||||
assert sub2.lineref == "src l. 19"
|
||||
all_nodes = list(result.all_nodes())
|
||||
assert len(all_nodes) == 14
|
||||
all_nodes = list(result.all_nodes(Subroutine))
|
||||
assert len(all_nodes) == 1
|
||||
assert isinstance(all_nodes[0], Subroutine)
|
||||
assert isinstance(all_nodes[0].parent, Scope)
|
||||
assert all_nodes[0] in all_nodes[0].parent.nodes
|
||||
assert all_nodes[0].lineref == "src l. 19"
|
||||
assert all_nodes[0].parent.lineref == "src l. 8"
|
||||
|
||||
|
||||
def test_block_nodes():
|
||||
sref = SourceRef("file", 1, 1)
|
||||
sub1 = Subroutine(name="subaddr", param_spec=[], result_spec=[], address=0xc000, sourceref=sref)
|
||||
sub2 = Subroutine(name="subblock", param_spec=[], result_spec=[], sourceref=sref)
|
||||
sub2.scope = Scope(nodes=[Label(name="start", sourceref=sref)], level="block", sourceref=sref)
|
||||
assert sub1.scope is None
|
||||
assert sub1.nodes == []
|
||||
assert sub2.scope is not None
|
||||
assert len(sub2.scope.nodes) > 0
|
||||
|
||||
|
||||
def test_parser_2():
|
||||
src = """~ test {
|
||||
999(1,2)
|
||||
[zz]()
|
||||
}
|
||||
"""
|
||||
result = parse_source(src)
|
||||
block = result.scope.nodes[0]
|
||||
call = block.scope.nodes[0]
|
||||
assert isinstance(call, SubCall)
|
||||
assert len(call.arguments.nodes) == 2
|
||||
assert isinstance(call.target, LiteralValue)
|
||||
assert call.target.value == 999
|
||||
call = block.scope.nodes[1]
|
||||
assert isinstance(call, SubCall)
|
||||
assert len(call.arguments.nodes) == 0
|
||||
assert isinstance(call.target, Dereference)
|
||||
assert call.target.operand.name == "zz"
|
||||
|
||||
|
||||
def test_typespec():
|
||||
src = """~ test {
|
||||
[$c000.word] = 5
|
||||
[$c000 .byte] = 5
|
||||
[AX .word] = 5
|
||||
[AX .float] = 5
|
||||
}
|
||||
"""
|
||||
result = parse_source(src)
|
||||
block = result.scope.nodes[0]
|
||||
assignment1, assignment2, assignment3, assignment4 = block.scope.nodes
|
||||
assert assignment1.right.value == 5
|
||||
assert assignment2.right.value == 5
|
||||
assert assignment3.right.value == 5
|
||||
assert assignment4.right.value == 5
|
||||
assert len(assignment1.left.nodes) == 1
|
||||
assert len(assignment2.left.nodes) == 1
|
||||
assert len(assignment3.left.nodes) == 1
|
||||
assert len(assignment4.left.nodes) == 1
|
||||
t1 = assignment1.left
|
||||
t2 = assignment2.left
|
||||
t3 = assignment3.left
|
||||
t4 = assignment4.left
|
||||
assert isinstance(t1, Dereference)
|
||||
assert isinstance(t2, Dereference)
|
||||
assert isinstance(t3, Dereference)
|
||||
assert isinstance(t4, Dereference)
|
||||
assert isinstance(t1.operand, LiteralValue)
|
||||
assert isinstance(t2.operand, LiteralValue)
|
||||
assert isinstance(t3.operand, Register)
|
||||
assert isinstance(t4.operand, Register)
|
||||
assert t1.operand.value == 0xc000
|
||||
assert t2.operand.value == 0xc000
|
||||
assert t3.operand.name == "AX"
|
||||
assert t4.operand.name == "AX"
|
||||
assert t1.datatype == DataType.WORD
|
||||
assert t2.datatype == DataType.BYTE
|
||||
assert t3.datatype == DataType.WORD
|
||||
assert t4.datatype == DataType.FLOAT
|
||||
assert t1.size is None
|
||||
assert t2.size is None
|
||||
assert t3.size is None
|
||||
assert t4.size is None
|
||||
|
||||
|
||||
def test_char_string():
|
||||
src = """~ test {
|
||||
var x1 = '@'
|
||||
var x2 = 'π'
|
||||
var x3 = 'abc'
|
||||
A = '@'
|
||||
A = 'π'
|
||||
A = 'abc'
|
||||
}
|
||||
"""
|
||||
result = parse_source(src)
|
||||
block = result.scope.nodes[0]
|
||||
var1, var2, var3, assgn1, assgn2, assgn3, = block.scope.nodes
|
||||
assert var1.value.value == '@'
|
||||
assert var2.value.value == 'π'
|
||||
assert var3.value.value == "abc"
|
||||
assert assgn1.right.value == '@'
|
||||
assert assgn2.right.value == 'π'
|
||||
assert assgn3.right.value == "abc"
|
||||
# note: the actual one-charactor-to-bytevalue conversion is done at the very latest, when issuing an assignment statement
|
||||
|
||||
|
||||
def test_boolean_int():
|
||||
src = """~ test {
|
||||
var x1 = true
|
||||
var x2 = false
|
||||
A = true
|
||||
A = false
|
||||
}
|
||||
"""
|
||||
result = parse_source(src)
|
||||
block = result.scope.nodes[0]
|
||||
var1, var2, assgn1, assgn2, = block.scope.nodes
|
||||
assert type(var1.value.value) is int and var1.value.value == 1
|
||||
assert type(var2.value.value) is int and var2.value.value == 0
|
||||
assert type(assgn1.right.value) is int and assgn1.right.value == 1
|
||||
assert type(assgn2.right.value) is int and assgn2.right.value == 0
|
||||
|
||||
|
||||
def test_incrdecr_operators():
|
||||
sref = SourceRef("test", 1, 1)
|
||||
with pytest.raises(ValueError):
|
||||
IncrDecr(operator="??", sourceref=sref)
|
||||
i = IncrDecr(operator="++", sourceref=sref)
|
||||
assert i.howmuch == 1
|
||||
|
||||
|
||||
def test_symbol_lookup():
|
||||
sref = SourceRef("test", 1, 1)
|
||||
var1 = VarDef(name="var1", vartype="const", datatype=DataType.WORD, sourceref=sref)
|
||||
var1.value = LiteralValue(value=42, sourceref=sref)
|
||||
var1.value.parent = var1
|
||||
var2 = VarDef(name="var2", vartype="const", datatype=DataType.FLOAT, sourceref=sref)
|
||||
var2.value = LiteralValue(value=123.456, sourceref=sref)
|
||||
var2.value.parent = var2
|
||||
label1 = Label(name="outerlabel", sourceref=sref)
|
||||
label2 = Label(name="innerlabel", sourceref=sref)
|
||||
scope_inner = Scope(nodes=[
|
||||
label2,
|
||||
var2
|
||||
], level="block", sourceref=sref)
|
||||
scope_inner.name = "inner"
|
||||
var2.parent = label2.parent = scope_inner
|
||||
scope_outer = Scope(nodes=[
|
||||
label1,
|
||||
var1,
|
||||
scope_inner
|
||||
], level="block", sourceref=sref)
|
||||
scope_outer.name = "outer"
|
||||
var1.parent = label1.parent = scope_inner.parent = scope_outer
|
||||
scope_topmost = Scope(nodes=[scope_outer], level="module", sourceref=sref)
|
||||
scope_topmost.name = "topmost"
|
||||
scope_outer.parent = scope_topmost
|
||||
scope_topmost.define_builtin_functions()
|
||||
assert scope_inner.parent_scope is scope_outer
|
||||
assert scope_outer.parent_scope is scope_topmost
|
||||
assert scope_topmost.parent_scope is None
|
||||
assert label1.my_scope() is scope_outer
|
||||
assert var1.my_scope() is scope_outer
|
||||
assert scope_inner.my_scope() is scope_outer
|
||||
assert label2.my_scope() is scope_inner
|
||||
assert var2.my_scope() is scope_inner
|
||||
assert scope_outer.my_scope() is scope_topmost
|
||||
with pytest.raises(LookupError):
|
||||
scope_topmost.my_scope()
|
||||
with pytest.raises(UndefinedSymbolError):
|
||||
scope_inner.lookup("unexisting")
|
||||
with pytest.raises(UndefinedSymbolError):
|
||||
scope_outer.lookup("unexisting")
|
||||
assert scope_inner.lookup("innerlabel") is label2
|
||||
assert scope_inner.lookup("var2") is var2
|
||||
assert scope_inner.lookup("outerlabel") is label1
|
||||
assert scope_inner.lookup("var1") is var1
|
||||
with pytest.raises(UndefinedSymbolError):
|
||||
scope_outer.lookup("innerlabel")
|
||||
with pytest.raises(UndefinedSymbolError):
|
||||
scope_outer.lookup("var2")
|
||||
assert scope_outer.lookup("var1") is var1
|
||||
assert scope_outer.lookup("outerlabel") is label1
|
||||
math_func = scope_inner.lookup("sin")
|
||||
assert isinstance(math_func, BuiltinFunction)
|
||||
assert math_func.name == "sin" and math_func.func is math.sin
|
||||
builtin_func = scope_inner.lookup("abs")
|
||||
assert isinstance(builtin_func, BuiltinFunction)
|
||||
assert builtin_func.name == "abs" and builtin_func.func is abs
|
||||
# test dotted names:
|
||||
with pytest.raises(UndefinedSymbolError):
|
||||
scope_inner.lookup("noscope.nosymbol.nothing")
|
||||
assert scope_inner.lookup("outer.inner.var2") is var2
|
||||
with pytest.raises(UndefinedSymbolError):
|
||||
scope_inner.lookup("outer.inner.var1")
|
||||
with pytest.raises(UndefinedSymbolError):
|
||||
scope_inner.lookup("outer.var2")
|
||||
assert scope_inner.lookup("outer.var1") is var1
|
||||
|
||||
|
||||
def test_const_numeric_expressions():
|
||||
src = """~ test {
|
||||
A = 1+2+3+4+5
|
||||
X = 1+2*5+2
|
||||
Y = (1+2)*(5+2)
|
||||
A = (((10+20)/2)+5)**3
|
||||
X = -10-11-12
|
||||
Y = 1.234 mod (0.9 / 1.2)
|
||||
A = sin(1.234)
|
||||
X = round(4.567)-2
|
||||
Y = 1+abs(-100)
|
||||
A = ~1
|
||||
X = -1
|
||||
A = 4 << (9-3)
|
||||
X = 5000 >> 2
|
||||
Y = 999//88
|
||||
}
|
||||
"""
|
||||
result = parse_source(src)
|
||||
if isinstance(result, Module):
|
||||
result.scope.define_builtin_functions()
|
||||
assignments = list(result.all_nodes(Assignment))
|
||||
e = [a.nodes[1] for a in assignments]
|
||||
assert all(x.is_compiletime_const() for x in e)
|
||||
assert e[0].const_value() == 15 # 1+2+3+4+5
|
||||
assert e[1].const_value() == 13 # 1+2*5+2
|
||||
assert e[2].const_value() == 21 # (1+2)*(5+2)
|
||||
assert e[3].const_value() == 8000 # (((10+20)/2)+5)**3
|
||||
assert e[4].const_value() == -33 # -10-11-12
|
||||
assert e[5].const_value() == 0.484 # 1.234 mod (0.9 / 1.2)
|
||||
assert math.isclose(e[6].const_value(), 0.9438182093746337) # sin(1.234)
|
||||
assert e[7].const_value() == 3 # round(4.567)-2
|
||||
assert e[8].const_value() == 101 # 1+abs(-100)
|
||||
assert e[9].const_value() == -2 # ~1
|
||||
assert e[10].const_value() == -1 # -1
|
||||
assert e[11].const_value() == 256 # 4 << (9-3)
|
||||
assert e[12].const_value() == 1250 # 5000 >> 2
|
||||
assert e[13].const_value() == 11 # 999//88
|
||||
|
||||
|
||||
def test_const_logic_expressions():
|
||||
src = """~ test {
|
||||
A = true or false
|
||||
X = true and false
|
||||
Y = true xor false
|
||||
A = false and false or true
|
||||
X = (false and (false or true))
|
||||
Y = not (false or true)
|
||||
A = 1 < 2
|
||||
X = 1 >= 2
|
||||
Y = 1 == (2+3)
|
||||
}
|
||||
"""
|
||||
result = parse_source(src)
|
||||
assignments = list(result.all_nodes(Assignment))
|
||||
e = [a.nodes[1] for a in assignments]
|
||||
assert all(x.is_compiletime_const() for x in e)
|
||||
assert e[0].const_value() == True
|
||||
assert e[1].const_value() == False
|
||||
assert e[2].const_value() == True
|
||||
assert e[3].const_value() == True
|
||||
assert e[4].const_value() == False
|
||||
assert e[5].const_value() == False
|
||||
assert e[6].const_value() == True
|
||||
assert e[7].const_value() == False
|
||||
assert e[8].const_value() == False
|
||||
|
||||
|
||||
def test_const_other_expressions():
|
||||
src = """~ test {
|
||||
memory memvar = $c123
|
||||
A = &memvar ; constant
|
||||
X = &sin ; non-constant
|
||||
Y = [memvar] ; non-constant
|
||||
}
|
||||
"""
|
||||
result = parse_source(src)
|
||||
if isinstance(result, Module):
|
||||
result.scope.define_builtin_functions()
|
||||
assignments = list(result.all_nodes(Assignment))
|
||||
e = [a.nodes[1] for a in assignments]
|
||||
assert e[0].is_compiletime_const()
|
||||
assert e[0].const_value() == 0xc123
|
||||
assert not e[1].is_compiletime_const()
|
||||
with pytest.raises(TypeError):
|
||||
e[1].const_value()
|
||||
assert not e[2].is_compiletime_const()
|
||||
with pytest.raises(TypeError):
|
||||
e[2].const_value()
|
||||
|
||||
|
||||
def test_vdef_const_folds():
|
||||
src = """~ test {
|
||||
const cb1 = 123
|
||||
const cb2 = cb1
|
||||
const cb3 = cb1*3
|
||||
}
|
||||
"""
|
||||
result = parse_source(src)
|
||||
if isinstance(result, Module):
|
||||
result.scope.define_builtin_functions()
|
||||
vd = list(result.all_nodes(VarDef))
|
||||
assert vd[0].name == "cb1"
|
||||
assert vd[0].vartype == VarType.CONST
|
||||
assert vd[0].datatype == DataType.BYTE
|
||||
assert isinstance(vd[0].value, LiteralValue)
|
||||
assert vd[0].value.value == 123
|
||||
assert vd[1].name == "cb2"
|
||||
assert vd[1].vartype == VarType.CONST
|
||||
assert vd[1].datatype == DataType.BYTE
|
||||
assert isinstance(vd[1].value, SymbolName)
|
||||
assert vd[1].value.name == "cb1"
|
||||
assert vd[2].name == "cb3"
|
||||
assert vd[2].vartype == VarType.CONST
|
||||
assert vd[2].datatype == DataType.BYTE
|
||||
assert isinstance(vd[2].value, ExpressionWithOperator)
|
||||
cf = ConstantFold(result)
|
||||
cf.fold_constants()
|
||||
vd = list(result.all_nodes(VarDef))
|
||||
assert vd[0].name == "cb1"
|
||||
assert vd[0].vartype == VarType.CONST
|
||||
assert vd[0].datatype == DataType.BYTE
|
||||
assert isinstance(vd[0].value, LiteralValue)
|
||||
assert vd[0].value.value == 123
|
||||
assert vd[1].name == "cb2"
|
||||
assert vd[1].vartype == VarType.CONST
|
||||
assert vd[1].datatype == DataType.BYTE
|
||||
assert isinstance(vd[1].value, LiteralValue)
|
||||
assert vd[1].value.value == 123
|
||||
assert vd[2].name == "cb3"
|
||||
assert vd[2].vartype == VarType.CONST
|
||||
assert vd[2].datatype == DataType.BYTE
|
||||
assert isinstance(vd[2].value, LiteralValue)
|
||||
assert vd[2].value.value == 369
|
||||
|
||||
|
||||
def test_vdef_const_expressions():
|
||||
src = """~ test {
|
||||
var bvar = 99
|
||||
var .float fvar = sin(1.2-0.3)
|
||||
var .float flt2 = -9.87e-6
|
||||
|
||||
bvar ++
|
||||
fvar ++
|
||||
flt2 ++
|
||||
bvar += 2+2
|
||||
fvar += 2+3
|
||||
flt2 += 2+4
|
||||
bvar = 2+5
|
||||
fvar = 2+6
|
||||
flt2 = 2+7
|
||||
}
|
||||
"""
|
||||
result = parse_source(src)
|
||||
if isinstance(result, Module):
|
||||
result.scope.define_builtin_functions()
|
||||
cf = ConstantFold(result)
|
||||
cf.fold_constants()
|
||||
vd = list(result.all_nodes(VarDef))
|
||||
assert len(vd)==3
|
||||
assert vd[0].name == "bvar"
|
||||
assert isinstance(vd[0].value, LiteralValue)
|
||||
assert vd[0].value.value == 99
|
||||
assert vd[1].name == "fvar"
|
||||
assert isinstance(vd[1].value, LiteralValue)
|
||||
assert type(vd[1].value.value) is float
|
||||
assert math.isclose(vd[1].value.value, math.sin(0.9))
|
||||
assert vd[2].name == "flt2"
|
||||
assert isinstance(vd[2].value, LiteralValue)
|
||||
assert math.isclose(-9.87e-6, vd[2].value.value)
|
||||
# test incrdecr assignment target
|
||||
nodes = list(result.all_nodes(IncrDecr))
|
||||
assert len(nodes) == 3
|
||||
assert isinstance(nodes[0].target, SymbolName)
|
||||
assert nodes[0].target.name == "bvar"
|
||||
assert isinstance(nodes[1].target, SymbolName)
|
||||
assert nodes[1].target.name == "fvar"
|
||||
assert isinstance(nodes[2].target, SymbolName)
|
||||
assert nodes[2].target.name == "flt2"
|
||||
# test augassign assignment target
|
||||
nodes = list(result.all_nodes(AugAssignment))
|
||||
assert len(nodes) == 3
|
||||
assert isinstance(nodes[0].left, SymbolName)
|
||||
assert nodes[0].left.name == "bvar"
|
||||
assert isinstance(nodes[1].left, SymbolName)
|
||||
assert nodes[1].left.name == "fvar"
|
||||
assert isinstance(nodes[2].left, SymbolName)
|
||||
assert nodes[2].left.name == "flt2"
|
||||
# test assign assignment target
|
||||
nodes = list(result.all_nodes(Assignment))
|
||||
assert len(nodes) == 3
|
||||
assert isinstance(nodes[0].left, SymbolName)
|
||||
assert nodes[0].left.name == "bvar"
|
||||
assert isinstance(nodes[1].left, SymbolName)
|
||||
assert nodes[1].left.name == "fvar"
|
||||
assert isinstance(nodes[2].left, SymbolName)
|
||||
assert nodes[2].left.name == "flt2"
|
||||
@@ -0,0 +1,112 @@
|
||||
import pytest
|
||||
from il65.datatypes import DataType, VarType
|
||||
from il65.plyparse import (LiteralValue, VarDef, DatatypeNode, ExpressionWithOperator,
|
||||
Scope, AddressOf, SymbolName, UndefinedSymbolError)
|
||||
from il65.plylex import SourceRef
|
||||
|
||||
|
||||
def test_creation():
|
||||
sref = SourceRef("test", 1, 1)
|
||||
v = VarDef(name="v1", vartype="const", datatype=None, sourceref=sref)
|
||||
assert v.name == "v1"
|
||||
assert v.vartype == VarType.CONST
|
||||
assert v.datatype == DataType.BYTE
|
||||
assert v.size == [1]
|
||||
assert v.value is None
|
||||
assert v.zp_address is None
|
||||
v = VarDef(name="v2", vartype="memory", datatype=None, sourceref=sref)
|
||||
assert v.vartype == VarType.MEMORY
|
||||
assert isinstance(v.value, LiteralValue)
|
||||
assert v.value.value == 0
|
||||
dt = DatatypeNode(name="float", sourceref=sref)
|
||||
v = VarDef(name="v2", vartype="var", datatype=dt, sourceref=sref)
|
||||
assert v.vartype == VarType.VAR
|
||||
assert v.datatype == DataType.FLOAT
|
||||
assert isinstance(v.value, LiteralValue)
|
||||
assert v.value.value == 0
|
||||
dt = DatatypeNode(name="matrix", sourceref=sref)
|
||||
with pytest.raises(ValueError):
|
||||
VarDef(name="v2", vartype="var", datatype=dt, sourceref=sref)
|
||||
dt.dimensions = [2, 3]
|
||||
v = VarDef(name="v2", vartype="var", datatype=dt, sourceref=sref)
|
||||
assert v.vartype == VarType.VAR
|
||||
assert v.datatype == DataType.MATRIX
|
||||
assert v.size == [2, 3]
|
||||
assert isinstance(v.value, LiteralValue)
|
||||
assert v.value.value == 0
|
||||
dt = DatatypeNode(name="str", sourceref=sref)
|
||||
v = VarDef(name="v2", vartype="var", datatype=dt, sourceref=sref)
|
||||
assert v.vartype == VarType.VAR
|
||||
assert v.datatype == DataType.STRING
|
||||
assert v.size == [1]
|
||||
assert v.value is None
|
||||
|
||||
|
||||
def test_set_value():
|
||||
sref = SourceRef("test", 1, 1)
|
||||
v = VarDef(name="v1", vartype="var", datatype=DatatypeNode(name="word", sourceref=sref), sourceref=sref)
|
||||
assert v.datatype == DataType.WORD
|
||||
assert v.value.value == 0
|
||||
v.value = LiteralValue(value=42, sourceref=sref)
|
||||
assert v.value.value == 42
|
||||
v = VarDef(name="v1", vartype="var", datatype=DatatypeNode(name="str", sourceref=sref), sourceref=sref)
|
||||
assert v.datatype == DataType.STRING
|
||||
assert v.value is None
|
||||
v.value = LiteralValue(value="hello", sourceref=sref)
|
||||
assert v.value.value == "hello"
|
||||
e = ExpressionWithOperator(operator="-", sourceref=sref)
|
||||
e.left = LiteralValue(value=42, sourceref=sref)
|
||||
v.value = e
|
||||
assert v.value is e
|
||||
|
||||
|
||||
def test_const_value():
|
||||
sref = SourceRef("test", 1, 1)
|
||||
scope = Scope(nodes=[], level="block", sourceref=sref)
|
||||
vardef = VarDef(name="constvar", vartype="const", datatype=None, sourceref=sref)
|
||||
vardef.value = LiteralValue(value=43, sourceref=sref)
|
||||
scope.add_node(vardef)
|
||||
vardef = VarDef(name="varvar", vartype="var", datatype=None, sourceref=sref)
|
||||
vardef.value = LiteralValue(value=44, sourceref=sref)
|
||||
scope.add_node(vardef)
|
||||
vardef = VarDef(name="memvar", vartype="memory", datatype=None, sourceref=sref)
|
||||
vardef.value = LiteralValue(value=45, sourceref=sref)
|
||||
scope.add_node(vardef)
|
||||
v = VarDef(name="v1", vartype="var", datatype=DatatypeNode(name="word", sourceref=sref), sourceref=sref)
|
||||
with pytest.raises(TypeError):
|
||||
v.const_value()
|
||||
v = VarDef(name="v1", vartype="memory", datatype=DatatypeNode(name="word", sourceref=sref), sourceref=sref)
|
||||
with pytest.raises(TypeError):
|
||||
v.const_value()
|
||||
v = VarDef(name="v1", vartype="const", datatype=DatatypeNode(name="word", sourceref=sref), sourceref=sref)
|
||||
with pytest.raises(ValueError):
|
||||
v.const_value()
|
||||
v.value = LiteralValue(value=42, sourceref=sref)
|
||||
assert v.const_value() == 42
|
||||
v = VarDef(name="v1", vartype="const", datatype=DatatypeNode(name="float", sourceref=sref), sourceref=sref)
|
||||
with pytest.raises(ValueError):
|
||||
v.const_value()
|
||||
v.value = LiteralValue(value=42.9988, sourceref=sref)
|
||||
assert v.const_value() == 42.9988
|
||||
e = ExpressionWithOperator(operator="-", sourceref=sref)
|
||||
e.left = LiteralValue(value=42, sourceref=sref)
|
||||
v.value = e
|
||||
assert v.const_value() == -42
|
||||
s = SymbolName(name="unexisting", sourceref=sref)
|
||||
s.parent = scope
|
||||
v.value = s
|
||||
with pytest.raises(UndefinedSymbolError):
|
||||
v.const_value()
|
||||
s = SymbolName(name="constvar", sourceref=sref)
|
||||
s.parent = scope
|
||||
v.value = s
|
||||
assert v.const_value() == 43
|
||||
a = AddressOf(name="varvar", sourceref=sref)
|
||||
a.parent = scope
|
||||
v.value = a
|
||||
with pytest.raises(TypeError):
|
||||
v.const_value()
|
||||
a = AddressOf(name="memvar", sourceref=sref)
|
||||
a.parent = scope
|
||||
v.value = a
|
||||
assert v.const_value() == 45
|
||||
@@ -0,0 +1,60 @@
|
||||
import pytest
|
||||
from tinyvm.core import Memory
|
||||
|
||||
|
||||
def test_memory_unsigned():
|
||||
m = Memory()
|
||||
m.set_byte(1000, 1)
|
||||
m.set_byte(1001, 2)
|
||||
m.set_byte(1002, 3)
|
||||
m.set_byte(1003, 4)
|
||||
m.set_byte(2000, 252)
|
||||
m.set_byte(2001, 253)
|
||||
m.set_byte(2002, 254)
|
||||
m.set_byte(2003, 255)
|
||||
assert 1 == m.get_byte(1000)
|
||||
assert 2 == m.get_byte(1001)
|
||||
assert 3 == m.get_byte(1002)
|
||||
assert 4 == m.get_byte(1003)
|
||||
assert 252 == m.get_byte(2000)
|
||||
assert 253 == m.get_byte(2001)
|
||||
assert 254 == m.get_byte(2002)
|
||||
assert 255 == m.get_byte(2003)
|
||||
assert b"\x01\x02\x03\x04" == m.get_bytes(1000, 4)
|
||||
assert 0x0201 == m.get_word(1000)
|
||||
assert 0xfffe == m.get_word(2002)
|
||||
m.set_word(2002, 40000)
|
||||
assert 40000 == m.get_word(2002)
|
||||
assert 0x40 == m.get_byte(2002)
|
||||
assert 0x9c == m.get_byte(2003)
|
||||
|
||||
|
||||
def test_memory_signed():
|
||||
m = Memory()
|
||||
m.set_byte(1000, 1)
|
||||
m.set_byte(1001, 2)
|
||||
m.set_byte(1002, 3)
|
||||
m.set_byte(1003, 4)
|
||||
m.set_byte(2000, 252)
|
||||
m.set_byte(2001, 253)
|
||||
m.set_byte(2002, 254)
|
||||
m.set_byte(2003, 255)
|
||||
assert 1 == m.get_sbyte(1000)
|
||||
assert 2 == m.get_sbyte(1001)
|
||||
assert 3 == m.get_sbyte(1002)
|
||||
assert 4 == m.get_sbyte(1003)
|
||||
assert -4 == m.get_sbyte(2000)
|
||||
assert -3 == m.get_sbyte(2001)
|
||||
assert -2 == m.get_sbyte(2002)
|
||||
assert -1 == m.get_sbyte(2003)
|
||||
assert 0x0201 == m.get_sword(1000)
|
||||
assert -2 == m.get_sword(2002)
|
||||
m.set_sword(2002, 30000)
|
||||
assert 30000 == m.get_sword(2002)
|
||||
assert 0x30 == m.get_sbyte(2002)
|
||||
assert 0x75 == m.get_sbyte(2003)
|
||||
m.set_sword(2002, -30000)
|
||||
assert -30000 == m.get_sword(2002)
|
||||
assert 0x8ad0 == m.get_word(2002)
|
||||
assert 0xd0 == m.get_byte(2002)
|
||||
assert 0x8a == m.get_byte(2003)
|
||||
@@ -0,0 +1,83 @@
|
||||
import pytest
|
||||
from il65.compile import Zeropage, CompileError
|
||||
from il65.plyparse import ZpOptions, VarDef
|
||||
from il65.plylex import SourceRef
|
||||
from il65.datatypes import DataType
|
||||
|
||||
|
||||
def test_zp_names():
|
||||
sref = SourceRef("test", 1, 1)
|
||||
zp = Zeropage(ZpOptions.NOCLOBBER, False)
|
||||
with pytest.raises(AssertionError):
|
||||
zp.allocate(VarDef(name="", vartype="memory", datatype=DataType.BYTE, sourceref=sref))
|
||||
zp.allocate(VarDef(name="", vartype="var", datatype=DataType.BYTE, sourceref=sref))
|
||||
zp.allocate(VarDef(name="", vartype="var", datatype=DataType.BYTE, sourceref=sref))
|
||||
zp.allocate(VarDef(name="varname", vartype="var", datatype=DataType.BYTE, sourceref=sref))
|
||||
with pytest.raises(AssertionError):
|
||||
zp.allocate(VarDef(name="varname", vartype="var", datatype=DataType.BYTE, sourceref=sref))
|
||||
zp.allocate(VarDef(name="varname2", vartype="var", datatype=DataType.BYTE, sourceref=sref))
|
||||
|
||||
|
||||
def test_zp_noclobber_allocation():
|
||||
sref = SourceRef("test", 1, 1)
|
||||
zp = Zeropage(ZpOptions.NOCLOBBER, True)
|
||||
assert zp.available() == 9
|
||||
with pytest.raises(CompileError):
|
||||
# in regular zp there aren't 5 sequential bytes free
|
||||
zp.allocate(VarDef(name="impossible", vartype="var", datatype=DataType.FLOAT, sourceref=sref))
|
||||
for i in range(zp.available()):
|
||||
loc = zp.allocate(VarDef(name="bvar"+str(i), vartype="var", datatype=DataType.BYTE, sourceref=sref))
|
||||
assert loc > 0
|
||||
assert zp.available() == 0
|
||||
with pytest.raises(CompileError):
|
||||
zp.allocate(VarDef(name="", vartype="var", datatype=DataType.BYTE, sourceref=sref))
|
||||
with pytest.raises(CompileError):
|
||||
zp.allocate(VarDef(name="", vartype="var", datatype=DataType.WORD, sourceref=sref))
|
||||
|
||||
|
||||
def test_zp_float_enable():
|
||||
sref = SourceRef("test", 1, 1)
|
||||
zp = Zeropage(ZpOptions.CLOBBER, False)
|
||||
with pytest.raises(TypeError):
|
||||
zp.allocate(VarDef(name="", vartype="var", datatype=DataType.FLOAT, sourceref=sref))
|
||||
zp = Zeropage(ZpOptions.CLOBBER, True)
|
||||
zp.allocate(VarDef(name="", vartype="var", datatype=DataType.FLOAT, sourceref=sref))
|
||||
|
||||
|
||||
def test_zp_clobber_allocation():
|
||||
sref = SourceRef("test", 1, 1)
|
||||
zp = Zeropage(ZpOptions.CLOBBER, True)
|
||||
assert zp.available() == 239
|
||||
loc = zp.allocate(VarDef(name="", vartype="var", datatype=DataType.FLOAT, sourceref=sref))
|
||||
assert loc > 3 and loc not in zp.free
|
||||
num, rest = divmod(zp.available(), 5)
|
||||
for _ in range(num-3):
|
||||
zp.allocate(VarDef(name="", vartype="var", datatype=DataType.FLOAT, sourceref=sref))
|
||||
assert zp.available() == 19
|
||||
with pytest.raises(CompileError):
|
||||
# can't allocate because no more sequential bytes, only fragmented
|
||||
zp.allocate(VarDef(name="", vartype="var", datatype=DataType.FLOAT, sourceref=sref))
|
||||
for _ in range(14):
|
||||
zp.allocate(VarDef(name="", vartype="var", datatype=DataType.BYTE, sourceref=sref))
|
||||
zp.allocate(VarDef(name="", vartype="var", datatype=DataType.WORD, sourceref=sref))
|
||||
zp.allocate(VarDef(name="", vartype="var", datatype=DataType.WORD, sourceref=sref))
|
||||
with pytest.raises(CompileError):
|
||||
zp.allocate(VarDef(name="", vartype="var", datatype=DataType.WORD, sourceref=sref))
|
||||
assert zp.available() == 1
|
||||
zp.allocate(VarDef(name="last", vartype="var", datatype=DataType.BYTE, sourceref=sref))
|
||||
with pytest.raises(CompileError):
|
||||
zp.allocate(VarDef(name="impossible", vartype="var", datatype=DataType.BYTE, sourceref=sref))
|
||||
|
||||
|
||||
def test_zp_efficient_allocation():
|
||||
# free = [0x04, 0x05, 0x06, 0x2a, 0x52, 0xf7, 0xf8, 0xf9, 0xfa]
|
||||
sref = SourceRef("test", 1, 1)
|
||||
zp = Zeropage(ZpOptions.NOCLOBBER, False)
|
||||
assert zp.available() == 9
|
||||
assert 0x2a == zp.allocate(VarDef(name="", vartype="var", datatype=DataType.BYTE, sourceref=sref))
|
||||
assert 0x52 == zp.allocate(VarDef(name="", vartype="var", datatype=DataType.BYTE, sourceref=sref))
|
||||
assert 0x04 == zp.allocate(VarDef(name="", vartype="var", datatype=DataType.WORD, sourceref=sref))
|
||||
assert 0xf7 == zp.allocate(VarDef(name="", vartype="var", datatype=DataType.WORD, sourceref=sref))
|
||||
assert 0x06 == zp.allocate(VarDef(name="", vartype="var", datatype=DataType.BYTE, sourceref=sref))
|
||||
assert 0xf9 == zp.allocate(VarDef(name="", vartype="var", datatype=DataType.WORD, sourceref=sref))
|
||||
assert zp.available() == 0
|
||||
Reference in New Issue
Block a user