Skip to content

Commit

Permalink
Tidy up name fields
Browse files Browse the repository at this point in the history
  • Loading branch information
kg583 committed May 28, 2024
1 parent fd8c04d commit 3ed832a
Show file tree
Hide file tree
Showing 9 changed files with 84 additions and 92 deletions.
2 changes: 1 addition & 1 deletion tests/tivars.py
Original file line number Diff line number Diff line change
Expand Up @@ -601,7 +601,7 @@ def test_group(self):

ungrouped = test_group.ungroup()

self.assertEqual(ungrouped[0], TIEquation("10sin(theta", name="R1"))
self.assertEqual(ungrouped[0], TIEquation("10sin(theta", name="r1"))
self.assertEqual(type(ungrouped[1]), TIWindowSettings)

self.assertEqual(TIGroup.group(ungrouped).ungroup(), ungrouped)
Expand Down
2 changes: 1 addition & 1 deletion tivars/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -386,7 +386,7 @@ def __call__(self, func: Callable) -> 'Section':
signature = inspect.signature(func)
match len(signature.parameters):
case 1: pass
case 2: new._set = lambda value, _set=new._set, *, instance=None, **kwargs:\
case 2: new._set = lambda value, _set=self._set, *, instance=None, **kwargs:\
_set(func(instance, value), instance=instance, **kwargs)
case _: raise TypeError("Section and View function definitions can only take 1 or 2 parameters.")

Expand Down
13 changes: 11 additions & 2 deletions tivars/tokenizer/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
"""


import re
from warnings import warn

from tivars.data import String
from tivars.models import *
from tivars.tokens.scripts import *
Expand All @@ -24,8 +27,14 @@ def get(cls, data: bytes, **kwargs) -> _T:
return decode(data.ljust(8, b'\x00'))[0]

@classmethod
def set(cls, value: _T, **kwargs) -> bytes:
return encode(value, mode="string")[0].rstrip(b'\x00')
def set(cls, value: _T, *, instance=None, **kwargs) -> bytes:
data = encode(re.sub(r"[\u0398\u03F4\u1DBF]", "θ", value), mode="string")[0].rstrip(b'\x00')

if instance is None or not data.startswith(instance.leading_name_byte):
warn(f"Entry has an invalid name: '{value}'.",
BytesWarning)

return data


__all__ = ["decode", "encode", "TokenizedString",
Expand Down
24 changes: 18 additions & 6 deletions tivars/types/gdb.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from tivars.flags import *
from tivars.data import *
from tivars.models import *
from tivars.tokenizer import decode
from tivars.var import TIEntry, SizedEntry
from .real import *
from .tokenized import TIEquation
Expand Down Expand Up @@ -194,7 +195,7 @@ class IndexedEquationConverter(Converter):
_T = TIGraphedEquation

@classmethod
def get(cls, data: bytes, *, instance=None, **kwargs) -> _T:
def get(cls, data: bytes, *, instance=None) -> _T:
"""
Converts ``bytes`` -> `TIGraphedEquation` by finding the equation at ``index`` within a GDB
Expand Down Expand Up @@ -276,6 +277,14 @@ def length(self) -> int:
The length of this entry's user data section
"""

@property
def json_name(self) -> str:
"""
:return: The name of this equation used in the GDB JSON format
"""

return decode(self.raw.name, mode="accessible")[0].strip("{}|")

def load_data_section(self, data: BytesIO):
flag_byte = data.read(1)
data_length = int.from_bytes(length_bytes := data.read(2), 'little')
Expand Down Expand Up @@ -369,12 +378,15 @@ class TIMonoGDB(SizedEntry, register=True):
TI_83P: "8xd"
}

min_data_length = 61

leading_name_byte = b'\x61'

mode_byte = 0x00
"""
The byte which identifies the GDB type
"""

min_data_length = 61
has_color = False
"""
Whether this GDB type carries color information
Expand Down Expand Up @@ -920,7 +932,7 @@ def dict(self) -> dict:
"Xres": int(self.Xres)
},
"equations": {
equation.name: equation.dict() for equation in self.equations
equation.json_name: equation.dict() for equation in self.equations
}
}
}
Expand Down Expand Up @@ -1102,7 +1114,7 @@ def dict(self) -> dict:
"Tstep": self.Tstep.json_number(),
},
"equations": {
equation.name: equation.dict() for equation in self.equations
equation.json_name: equation.dict() for equation in self.equations
}
}
}
Expand Down Expand Up @@ -1238,7 +1250,7 @@ def dict(self) -> dict:
"Thetastep": self.Thetastep.json_number(),
},
"equations": {
equation.name: equation.dict() for equation in self.equations
equation.json_name: equation.dict() for equation in self.equations
}
}
}
Expand Down Expand Up @@ -1486,7 +1498,7 @@ def dict(self) -> dict:
"wnMinp1": self.wnMinp1.json_number()
},
"equations": {
equation.name: equation.dict() for equation in self.equations
equation.json_name: equation.dict() for equation in self.equations
}
}
}
Expand Down
19 changes: 9 additions & 10 deletions tivars/types/list.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,23 +56,22 @@ def set(cls, value: _T, **kwargs) -> bytes:
:return: The name encoding of ``value``
"""

varname = value[:7].upper()
varname = re.sub(r"(\u03b8|\u0398|\u03F4|\u1DBF)", "θ", varname)
varname = value.upper()
varname = re.sub(r"[\u0398\u03F4\u1DBF]", "θ", varname)
varname = re.sub(r"]", "|L", varname)
varname = re.sub(r"[^θa-zA-Z0-9]", "", varname)

if varname != value:
warn(f"List name '{value}' was transformed to '{varname}'.",
UserWarning)
if not re.fullmatch(r"(L\d)|(\|L|.)?([A-Z]|\u03b8)([0-9A-Z]|\u03b8){,4}|IDList", varname):
warn(f"List has an invalid name: '{varname}'.",
BytesWarning)

if "IDList" in varname:
return b']@'
return b'\x5D\x40'

elif varname.startswith("|L"):
return super().set(varname[-5:])
elif re.fullmatch(r"L\d", varname):
return super().set(varname[:2])

else:
return super().set(varname[:2])
return super().set(varname[-5:])


class ListEntry(TIEntry):
Expand Down
2 changes: 2 additions & 0 deletions tivars/types/matrix.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ class TIMatrix(TIEntry, register=True):

min_data_length = 2

leading_name_byte = b'\x5C'

_type_id = 0x02

def __init__(self, init=None, *,
Expand Down
10 changes: 8 additions & 2 deletions tivars/types/picture.py
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,8 @@ class TIMonoPicture(PictureEntry):

has_color = False

leading_name_byte = b'\x60'

_type_id = 0x07

def __init__(self, init=None, *,
Expand Down Expand Up @@ -302,6 +304,8 @@ class TIPicture(PictureEntry, register=True):
pixel_type = RGB
np_shape = (height, width, 3)

leading_name_byte = b'\x60'

_type_id = 0x07

def __init__(self, init=None, *,
Expand Down Expand Up @@ -341,7 +345,8 @@ def get(cls, data: bytes, **kwargs) -> _T:
@classmethod
def set(cls, value: _T, **kwargs) -> bytes:
if not re.fullmatch(r"(Image)?\d", value):
warn(f"'{value}' is not a valid image name; defaulting to 'Image1'.")
warn(f"'{value}' is not a valid image name; defaulting to 'Image1'.",
BytesWarning)
value = "Image1"

return b"\x3C" + bytes([int(value[-1], 16) - 1])
Expand Down Expand Up @@ -378,7 +383,8 @@ class TIImage(PictureEntry, register=True):
pixel_type = RGB
np_shape = (height, width, 3)

leading_bytes = b'\x81'
leading_name_byte = b'\x3C'
leading_data_bytes = b'\x81'

_type_id = 0x1A

Expand Down
87 changes: 23 additions & 64 deletions tivars/types/tokenized.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,58 +153,6 @@ def string(self) -> str:
return format(self, "")


class EquationName(TokenizedString):
"""
Converter for the name section of equations
Equation names can be any of the following:
- ``Y1`` - ``Y0``
- ``X1T`` - ``X6T``
- ``Y1T`` - ``Y6T``
- ``r1`` - ``r6``
- ``u``, ``v``, or ``w``.
"""

_T = str

@classmethod
def get(cls, data: bytes, **kwargs) -> _T:
"""
Converts ``bytes`` -> ``str`` as done by the memory viewer
:param data: The raw bytes to convert
:return: The equation name contained in ``data``
"""

varname = super().get(data)

if varname.startswith("|"):
return varname[1:]

else:
return varname.upper().strip("{}")

@classmethod
def set(cls, value: _T, **kwargs) -> bytes:
"""
Converts ``str`` -> ``bytes`` to match appearance in the memory viewer
:param value: The value to convert
:return: The name encoding of ``value``
"""

varname = value[:8].lower()

if varname.startswith("|") or varname in ("u", "v", "w"):
varname = "|" + varname[-1]

elif varname[0] != "{" and varname[-1] != "}":
varname = "{" + varname + "}"

return super().set(varname)


class TIEquation(TokenizedEntry, register=True):
"""
Parser for equations
Expand All @@ -219,6 +167,8 @@ class TIEquation(TokenizedEntry, register=True):
TI_83P: "8xy"
}

leading_name_byte = b'\x5E'

_type_id = 0x03

def __init__(self, init=None, *,
Expand All @@ -228,14 +178,24 @@ def __init__(self, init=None, *,

super().__init__(init, for_flash=for_flash, name=name, version=version, archived=archived, data=data)

@Section(8, EquationName)
def name(self) -> str:
@Section(8, TokenizedString)
def name(self, value) -> str:
"""
The name of the entry
Must be one of the equation names
Must be an equation name used in function, parametric, polar, or sequence mode.
(See https://ti-toolkit.github.io/tokens-wiki/categories/Y%3D%20Functions.html)
"""

varname = value
if varname in ("u", "v", "w"):
varname = "|" + varname

elif match := re.fullmatch(r"\{?([XYr]\dT?)}?", varname):
varname = "{" + match[1] + "}"

return varname


class TINewEquation(TIEquation, register=True):
"""
Expand All @@ -261,6 +221,8 @@ class TIString(TokenizedEntry, register=True):
TI_83P: "8xs"
}

leading_name_byte = b'\xAA'

_type_id = 0x04

def __init__(self, init=None, *,
Expand All @@ -275,11 +237,11 @@ def name(self, value) -> str:
"""
The name of the entry
Must be one of the string names: ``Str1`` - ``Str0``
Must be one of the string names: ``Str1`` - ``Str0``.
"""

if not re.fullmatch(r"Str\d", varname := value[:4].capitalize()):
warn(f"String has an invalid name: {varname}.",
if not re.fullmatch(r"Str\d", varname := value.capitalize()):
warn(f"String has an invalid name: '{varname}'.",
BytesWarning)

return varname
Expand Down Expand Up @@ -335,12 +297,9 @@ def name(self, value) -> str:
The name cannot start with a digit.
"""

varname = value[:8].upper()
varname = re.sub(r"(\u03b8|\u0398|\u03F4|\u1DBF)", "θ", varname)
varname = re.sub(r"[^θa-zA-Z0-9]", "", varname)

if not varname or varname[0].isnumeric():
warn(f"Program has an invalid name: {varname}.",
varname = re.sub(r"[\u0398\u03F4\u1DBF]", "θ", value.upper())
if not re.fullmatch(r"([A-Z]|\u03b8)([0-9A-Z]|\u03b8){,7}", varname):
warn(f"Program has an invalid name: '{varname}'.",
BytesWarning)

return varname
Expand Down
17 changes: 11 additions & 6 deletions tivars/var.py
Original file line number Diff line number Diff line change
Expand Up @@ -275,9 +275,14 @@ class TIEntry(Dock, Converter):
If an entry's data is fixed in size, this value is necessarily the length of the data
"""

leading_bytes = b''
leading_name_byte = b''
"""
Bytes that always occur at the start of this entry's data
Byte that always begins the name of this entry
"""

leading_data_bytes = b''
"""
Bytes that always begin this entry's data
"""

_type_id = None
Expand Down Expand Up @@ -612,7 +617,7 @@ def clear(self):
Clears this entry's data
"""

self.raw.calc_data = bytearray(self.leading_bytes)
self.raw.calc_data = bytearray(self.leading_data_bytes)
self.raw.calc_data.extend(bytearray(self.min_data_length - self.calc_data_length))

def get_min_os(self, data: bytes = None) -> OsVersion:
Expand Down Expand Up @@ -1231,15 +1236,15 @@ def data(self) -> bytes:
pass

def clear(self):
self.raw.calc_data = bytearray([0, 0, *self.leading_bytes])
self.raw.calc_data = bytearray([0, 0, *self.leading_data_bytes])
self.raw.calc_data.extend(bytearray(self.min_data_length - self.calc_data_length))
self.length = len(self.leading_bytes) + len(self.data)
self.length = len(self.leading_data_bytes) + len(self.data)

@Loader[bytes, bytearray, BytesIO]
def load_bytes(self, data: bytes | BytesIO):
super().load_bytes(data)

if self.length != (data_length := len(self.leading_bytes) + len(self.data)):
if self.length != (data_length := len(self.leading_data_bytes) + len(self.data)):
warn(f"The entry has an unexpected data length (expected {self.length}, got {data_length}).",
BytesWarning)

Expand Down

0 comments on commit 3ed832a

Please sign in to comment.