tipy-asm 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- tipy_asm-1.0.0/LICENSE +21 -0
- tipy_asm-1.0.0/PKG-INFO +185 -0
- tipy_asm-1.0.0/README.md +173 -0
- tipy_asm-1.0.0/pyproject.toml +28 -0
- tipy_asm-1.0.0/setup.cfg +4 -0
- tipy_asm-1.0.0/tests/test_api.py +113 -0
- tipy_asm-1.0.0/tests/test_cli.py +457 -0
- tipy_asm-1.0.0/tests/test_convbin.py +65 -0
- tipy_asm-1.0.0/tests/test_convfont.py +183 -0
- tipy_asm-1.0.0/tests/test_convimg.py +98 -0
- tipy_asm-1.0.0/tests/test_runtime.py +473 -0
- tipy_asm-1.0.0/ti84/__init__.py +5 -0
- tipy_asm-1.0.0/ti84/__init__.pyi +14 -0
- tipy_asm-1.0.0/ti84/color.pyi +37 -0
- tipy_asm-1.0.0/ti84/file.pyi +11 -0
- tipy_asm-1.0.0/ti84/font.pyi +13 -0
- tipy_asm-1.0.0/ti84/graph.pyi +4 -0
- tipy_asm-1.0.0/ti84/graphics.pyi +60 -0
- tipy_asm-1.0.0/ti84/keyboard.pyi +73 -0
- tipy_asm-1.0.0/ti84/math.pyi +11 -0
- tipy_asm-1.0.0/ti84/py.typed +1 -0
- tipy_asm-1.0.0/ti84/random.pyi +5 -0
- tipy_asm-1.0.0/ti84/sprite.pyi +10 -0
- tipy_asm-1.0.0/ti84/storage.pyi +11 -0
- tipy_asm-1.0.0/ti84asm/__init__.py +1 -0
- tipy_asm-1.0.0/ti84asm/__main__.py +3 -0
- tipy_asm-1.0.0/ti84asm/cedev_config.py +58 -0
- tipy_asm-1.0.0/ti84asm/cgen.py +1029 -0
- tipy_asm-1.0.0/ti84asm/cli.py +451 -0
- tipy_asm-1.0.0/ti84asm/compiler.py +1105 -0
- tipy_asm-1.0.0/ti84asm/convbin.py +208 -0
- tipy_asm-1.0.0/ti84asm/convfont.py +1073 -0
- tipy_asm-1.0.0/ti84asm/convimg.py +156 -0
- tipy_asm-1.0.0/ti84asm/errors.py +2 -0
- tipy_asm-1.0.0/ti84asm/fasmg.py +143 -0
- tipy_asm-1.0.0/ti84asm/flash_ce.py +740 -0
- tipy_asm-1.0.0/ti84asm/flashapp.py +100 -0
- tipy_asm-1.0.0/ti84asm/image.py +58 -0
- tipy_asm-1.0.0/ti84asm/project.py +433 -0
- tipy_asm-1.0.0/ti84asm/project_convert/__init__.py +19 -0
- tipy_asm-1.0.0/ti84asm/project_convert/c_like.py +803 -0
- tipy_asm-1.0.0/ti84asm/project_convert/cedev_convert.py +24 -0
- tipy_asm-1.0.0/ti84asm/project_convert/ice_convert.py +27 -0
- tipy_asm-1.0.0/ti84asm/project_convert/project_converter.py +251 -0
- tipy_asm-1.0.0/ti84asm/runtime.py +1043 -0
- tipy_asm-1.0.0/ti84asm/toolchain/bin/fasmg +0 -0
- tipy_asm-1.0.0/ti84asm/toolchain/bin/fasmg.exe +0 -0
- tipy_asm-1.0.0/ti84asm/toolchain/bin/fasmg.x64 +0 -0
- tipy_asm-1.0.0/ti84asm/toolchain/fasmg-license.txt +24 -0
- tipy_asm-1.0.0/ti84asm/toolchain/include/commands.alm +99 -0
- tipy_asm-1.0.0/ti84asm/toolchain/include/ez80.alm +1505 -0
- tipy_asm-1.0.0/ti84asm/toolchain/include/ez80.inc +2 -0
- tipy_asm-1.0.0/ti84asm/toolchain/include/ti84pceg.inc +6997 -0
- tipy_asm-1.0.0/ti84asm/toolchain/include/tiformat.inc +105 -0
- tipy_asm-1.0.0/ti84libs/__init__.py +107 -0
- tipy_asm-1.0.0/ti84libs/api.py +199 -0
- tipy_asm-1.0.0/ti84libs/color.py +309 -0
- tipy_asm-1.0.0/ti84libs/graph.py +10 -0
- tipy_asm-1.0.0/ti84libs/graphics.py +840 -0
- tipy_asm-1.0.0/ti84libs/keyboard.py +62 -0
- tipy_asm-1.0.0/ti84libs/math.py +45 -0
- tipy_asm-1.0.0/ti84libs/random.py +16 -0
- tipy_asm-1.0.0/ti84libs/sprite.py +32 -0
- tipy_asm-1.0.0/ti84libs/storage.py +56 -0
- tipy_asm-1.0.0/tipy_asm.egg-info/PKG-INFO +185 -0
- tipy_asm-1.0.0/tipy_asm.egg-info/SOURCES.txt +68 -0
- tipy_asm-1.0.0/tipy_asm.egg-info/dependency_links.txt +1 -0
- tipy_asm-1.0.0/tipy_asm.egg-info/entry_points.txt +6 -0
- tipy_asm-1.0.0/tipy_asm.egg-info/requires.txt +6 -0
- tipy_asm-1.0.0/tipy_asm.egg-info/top_level.txt +3 -0
tipy_asm-1.0.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Voblit
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
tipy_asm-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: tipy-asm
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: TIpy-asm: Python compiler for TI-84 Z80/eZ80 calculators
|
|
5
|
+
Requires-Python: >=3.10
|
|
6
|
+
Description-Content-Type: text/markdown
|
|
7
|
+
License-File: LICENSE
|
|
8
|
+
Requires-Dist: tomli>=2; python_version < "3.11"
|
|
9
|
+
Provides-Extra: images
|
|
10
|
+
Requires-Dist: Pillow>=10; extra == "images"
|
|
11
|
+
Dynamic: license-file
|
|
12
|
+
|
|
13
|
+
# TIpy-asm
|
|
14
|
+
|
|
15
|
+
TIpy-asm is a Python-based fork of [Voblit/py2ez80](https://github.com/Voblit/py2ez80),
|
|
16
|
+
a compiler for writing TI calculator programs in a restricted, Python-like
|
|
17
|
+
language. It compiles source on a computer; Python itself does not run on the
|
|
18
|
+
calculator.
|
|
19
|
+
|
|
20
|
+
## Quick start
|
|
21
|
+
|
|
22
|
+
Requires Python 3.10 or newer:
|
|
23
|
+
|
|
24
|
+
```powershell
|
|
25
|
+
python -m pip install .
|
|
26
|
+
tipy-asm new mygame
|
|
27
|
+
cd mygame
|
|
28
|
+
tipy-asm build
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
That creates a program you can move around with the arrow keys, and writes
|
|
32
|
+
`bin\MYGAME.8xp`. CE builds need nothing else and work offline: the package
|
|
33
|
+
includes fasmg for Windows and Linux (x64 and x86), plus its CE includes. On other
|
|
34
|
+
systems, put fasmg on PATH. Run `tipy-asm doctor` to see what is installed.
|
|
35
|
+
|
|
36
|
+
`examples\catch` is a complete small game. The package also installs the shorter
|
|
37
|
+
command alias `ti84py`.
|
|
38
|
+
|
|
39
|
+
## Targets
|
|
40
|
+
|
|
41
|
+
- **TI-84 Plus CE assembly:** eZ80 assembly, or a `.8xp` program built with the
|
|
42
|
+
bundled fasmg.
|
|
43
|
+
- **Classic TI-83+/TI-84 Plus:** Z80 assembly, or a `.8xp` program built with
|
|
44
|
+
SPASM-ng, which you install yourself.
|
|
45
|
+
- **TI-84 Plus CE Flash App:** translated to C, then built and packaged with
|
|
46
|
+
CEdev and an installer project that you provide.
|
|
47
|
+
|
|
48
|
+
## Commands
|
|
49
|
+
|
|
50
|
+
| Command | What it does |
|
|
51
|
+
|---|---|
|
|
52
|
+
| `tipy-asm new FOLDER` | Create a project that builds straight away |
|
|
53
|
+
| `tipy-asm build [SOURCE]` | Build `.8xp` programs and assets. Add `--watch` to rebuild on save, or `--keep-asm` to keep the assembly |
|
|
54
|
+
| `tipy-asm check [SOURCE]` | Report errors on each target without writing files. `--target flash` checks the Flash App backend |
|
|
55
|
+
| `tipy-asm compile [SOURCE]` | Write assembly without assembling it |
|
|
56
|
+
| `tipy-asm flash-app [SOURCE]` | Build a CE Flash App and its installer |
|
|
57
|
+
| `tipy-asm api [LIBRARY]` | List library methods and the targets that support them |
|
|
58
|
+
| `tipy-asm doctor` | Show installed tools and the project's setup |
|
|
59
|
+
| `tipy-asm clean` | Delete the project's build folder |
|
|
60
|
+
| `tipy-asm convert-project PATH` | Convert a CEdev or ICE project into a TIpy-asm project |
|
|
61
|
+
| `tipy-asm convbin`, `convimg`, `convert-image` | Convert data and images by hand |
|
|
62
|
+
| `tipy-asm convfont` | Convert `.fnt` and text-format fonts, matching CEdev's `convfont` byte for byte |
|
|
63
|
+
|
|
64
|
+
With no source, commands use the project in the current folder or the nearest
|
|
65
|
+
parent folder. Errors are printed as `FILE:LINE: error: MESSAGE` with the source
|
|
66
|
+
line, in the original file, so editors can link to them.
|
|
67
|
+
|
|
68
|
+
## Projects
|
|
69
|
+
|
|
70
|
+
A project is configured under `[tool.tipy]` in its `pyproject.toml`:
|
|
71
|
+
|
|
72
|
+
```toml
|
|
73
|
+
[tool.tipy]
|
|
74
|
+
name = "BOUNCE" # calculator program name, 1-8 letters or digits
|
|
75
|
+
main = "src/main.py" # default
|
|
76
|
+
target = "ce" # classic, ce, or both; default ce
|
|
77
|
+
bindir = "bin" # default
|
|
78
|
+
keep_asm = false
|
|
79
|
+
|
|
80
|
+
[tool.tipy.toolchain] # optional; the default is to search PATH
|
|
81
|
+
ce_assembler = "tools/fasmg.exe"
|
|
82
|
+
classic_assembler = "tools/spasm.exe"
|
|
83
|
+
|
|
84
|
+
[tool.tipy.flash] # used by `tipy-asm flash-app`
|
|
85
|
+
project_dir = "flash" # folder containing installer/makefile
|
|
86
|
+
optimize = "speed" # or size
|
|
87
|
+
|
|
88
|
+
[[tool.tipy.assets]] # converted into bindir by each build, when out of date
|
|
89
|
+
source = "assets/hero.png"
|
|
90
|
+
name = "HERO" # AppVar name; the default comes from the file name
|
|
91
|
+
kind = "sprite" # sprite, image, font, or binary; guessed from the suffix
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
`from settings import SPEED` includes `settings.py` from the main file's folder,
|
|
95
|
+
and `from game.player import move` includes `game/player.py`.
|
|
96
|
+
|
|
97
|
+
Image assets need Pillow: `python -m pip install "tipy-asm[images]"`. Send the
|
|
98
|
+
asset's `.8xv` to the calculator along with the program:
|
|
99
|
+
|
|
100
|
+
```python
|
|
101
|
+
from ti84 import sprite
|
|
102
|
+
hero = sprite.load("HERO") # 0 if the AppVar is missing
|
|
103
|
+
sprite.draw(hero, x, y)
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## Language on the assembly targets
|
|
107
|
+
|
|
108
|
+
The Flash App backend supports more of Python. The assembly targets support:
|
|
109
|
+
|
|
110
|
+
- Functions with parameters, defaults, keyword arguments, return values, and
|
|
111
|
+
`global`. Recursion is rejected, because function variables are static.
|
|
112
|
+
- `if`/`elif`/`else`, `while`, `for ... in range()` with runtime bounds, `break`,
|
|
113
|
+
`continue`, and `exit()`.
|
|
114
|
+
- `+ - * // % << >> & | ^ ~`, comparisons, `and`, `or`, `not`, and `a if c else b`.
|
|
115
|
+
Integers are signed, 24-bit on CE and 16-bit on classic, and wrap on overflow.
|
|
116
|
+
`x // 0` is 0 and `x % 0` is `x`, because a calculator program cannot raise.
|
|
117
|
+
- Module-level arrays: `TABLE = (1, 2, 3)` is read-only, and `scores = [0] * 10`
|
|
118
|
+
is writable. Runtime indexes are not bounds-checked.
|
|
119
|
+
- `print()` of string literals and integers, and `abs`, `min`, and `max`.
|
|
120
|
+
|
|
121
|
+
Strings exist only as literals, and there are no floats, classes, or lists of
|
|
122
|
+
lists.
|
|
123
|
+
|
|
124
|
+
## Libraries
|
|
125
|
+
|
|
126
|
+
Import them with `from ti84 import graphics, keyboard`. Run `tipy-asm api NAME`
|
|
127
|
+
for each method's signature and targets. The `ti84` package also has stubs, so
|
|
128
|
+
VS Code/Pylance can complete these names.
|
|
129
|
+
|
|
130
|
+
| Library | Provides |
|
|
131
|
+
|---|---|
|
|
132
|
+
| `graphics` | Pixels, lines, rectangles, circles, triangles, text, and sprites. Coordinates and colors can be runtime values, and are clipped to the screen |
|
|
133
|
+
| `keyboard` | `read()` waits for a key, `get()` returns at once, `is_down(key)` tests a held key |
|
|
134
|
+
| `math` | `abs min max clamp sign sqrt pow sin cos`, all integer; `sin` and `cos` take degrees and scale by 256 |
|
|
135
|
+
| `random` | `seed randrange randint` |
|
|
136
|
+
| `storage`, `file` | AppVar bytes that persist between runs |
|
|
137
|
+
| `sprite` | AppVar sprites from project assets (CE only) |
|
|
138
|
+
| `color` | Color constants and conversions. On classic, colors are 0 (white) or 1 (black) |
|
|
139
|
+
| `graph` | The Flash App's graph screen (Flash App only) |
|
|
140
|
+
|
|
141
|
+
Not implemented: FontLibC fonts (`ti84.font` has only color constants, so use
|
|
142
|
+
`graphics.text()`), and scaled or rotated sprites. Calling these gives an error
|
|
143
|
+
rather than doing nothing. Text with runtime coordinates and `text_int()` need
|
|
144
|
+
the CE target. A failed `storage` read or write, such as a missing AppVar or a
|
|
145
|
+
bad offset, ends the program.
|
|
146
|
+
|
|
147
|
+
## Converting CEdev and ICE projects
|
|
148
|
+
|
|
149
|
+
```powershell
|
|
150
|
+
tipy-asm convert-project path\to\project -o converted
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
This writes a normal project, then compiles it and tells you whether it worked.
|
|
154
|
+
Code with no TIpy equivalent, such as pointers, structs, and `switch`, becomes a
|
|
155
|
+
`# TODO(convert)` comment and is listed in `CONVERSION_NOTES.md`. CEdev palette
|
|
156
|
+
indices are not RGB565 colors, so check the colors of a converted program.
|
|
157
|
+
|
|
158
|
+
## Tests
|
|
159
|
+
|
|
160
|
+
```powershell
|
|
161
|
+
python -m unittest discover -s tests
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
`tests/asm_sim.py` runs generated assembly on a model of both CPUs, with the OS
|
|
165
|
+
stubbed, and compares results with CPython. It is not an emulator, so test on
|
|
166
|
+
CEmu or a calculator as well.
|
|
167
|
+
|
|
168
|
+
## Documentation
|
|
169
|
+
|
|
170
|
+
The guide and method reference live on the
|
|
171
|
+
[`docs` branch](https://github.com/XSamuraiCoder/TIpy-asm/tree/docs). That branch holds
|
|
172
|
+
only the documentation, and this one holds only the package.
|
|
173
|
+
|
|
174
|
+
## Repository layout
|
|
175
|
+
|
|
176
|
+
- `ti84asm/` contains the compiler, runtime helpers, CLI, and build drivers.
|
|
177
|
+
- `ti84asm/toolchain/` contains the bundled [fasmg](https://flatassembler.net/) (see
|
|
178
|
+
`fasmg-license.txt`) and CE includes from
|
|
179
|
+
[CE-Programming/asm-docs](https://github.com/CE-Programming/asm-docs).
|
|
180
|
+
- `ti84libs/` contains the built-in libraries; `ti84libs/api.py` is the table of
|
|
181
|
+
public methods.
|
|
182
|
+
- `ti84/` contains the editor stubs.
|
|
183
|
+
- `examples/` contains example projects.
|
|
184
|
+
|
|
185
|
+
This fork retains the upstream [MIT license](LICENSE).
|
tipy_asm-1.0.0/README.md
ADDED
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
# TIpy-asm
|
|
2
|
+
|
|
3
|
+
TIpy-asm is a Python-based fork of [Voblit/py2ez80](https://github.com/Voblit/py2ez80),
|
|
4
|
+
a compiler for writing TI calculator programs in a restricted, Python-like
|
|
5
|
+
language. It compiles source on a computer; Python itself does not run on the
|
|
6
|
+
calculator.
|
|
7
|
+
|
|
8
|
+
## Quick start
|
|
9
|
+
|
|
10
|
+
Requires Python 3.10 or newer:
|
|
11
|
+
|
|
12
|
+
```powershell
|
|
13
|
+
python -m pip install .
|
|
14
|
+
tipy-asm new mygame
|
|
15
|
+
cd mygame
|
|
16
|
+
tipy-asm build
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
That creates a program you can move around with the arrow keys, and writes
|
|
20
|
+
`bin\MYGAME.8xp`. CE builds need nothing else and work offline: the package
|
|
21
|
+
includes fasmg for Windows and Linux (x64 and x86), plus its CE includes. On other
|
|
22
|
+
systems, put fasmg on PATH. Run `tipy-asm doctor` to see what is installed.
|
|
23
|
+
|
|
24
|
+
`examples\catch` is a complete small game. The package also installs the shorter
|
|
25
|
+
command alias `ti84py`.
|
|
26
|
+
|
|
27
|
+
## Targets
|
|
28
|
+
|
|
29
|
+
- **TI-84 Plus CE assembly:** eZ80 assembly, or a `.8xp` program built with the
|
|
30
|
+
bundled fasmg.
|
|
31
|
+
- **Classic TI-83+/TI-84 Plus:** Z80 assembly, or a `.8xp` program built with
|
|
32
|
+
SPASM-ng, which you install yourself.
|
|
33
|
+
- **TI-84 Plus CE Flash App:** translated to C, then built and packaged with
|
|
34
|
+
CEdev and an installer project that you provide.
|
|
35
|
+
|
|
36
|
+
## Commands
|
|
37
|
+
|
|
38
|
+
| Command | What it does |
|
|
39
|
+
|---|---|
|
|
40
|
+
| `tipy-asm new FOLDER` | Create a project that builds straight away |
|
|
41
|
+
| `tipy-asm build [SOURCE]` | Build `.8xp` programs and assets. Add `--watch` to rebuild on save, or `--keep-asm` to keep the assembly |
|
|
42
|
+
| `tipy-asm check [SOURCE]` | Report errors on each target without writing files. `--target flash` checks the Flash App backend |
|
|
43
|
+
| `tipy-asm compile [SOURCE]` | Write assembly without assembling it |
|
|
44
|
+
| `tipy-asm flash-app [SOURCE]` | Build a CE Flash App and its installer |
|
|
45
|
+
| `tipy-asm api [LIBRARY]` | List library methods and the targets that support them |
|
|
46
|
+
| `tipy-asm doctor` | Show installed tools and the project's setup |
|
|
47
|
+
| `tipy-asm clean` | Delete the project's build folder |
|
|
48
|
+
| `tipy-asm convert-project PATH` | Convert a CEdev or ICE project into a TIpy-asm project |
|
|
49
|
+
| `tipy-asm convbin`, `convimg`, `convert-image` | Convert data and images by hand |
|
|
50
|
+
| `tipy-asm convfont` | Convert `.fnt` and text-format fonts, matching CEdev's `convfont` byte for byte |
|
|
51
|
+
|
|
52
|
+
With no source, commands use the project in the current folder or the nearest
|
|
53
|
+
parent folder. Errors are printed as `FILE:LINE: error: MESSAGE` with the source
|
|
54
|
+
line, in the original file, so editors can link to them.
|
|
55
|
+
|
|
56
|
+
## Projects
|
|
57
|
+
|
|
58
|
+
A project is configured under `[tool.tipy]` in its `pyproject.toml`:
|
|
59
|
+
|
|
60
|
+
```toml
|
|
61
|
+
[tool.tipy]
|
|
62
|
+
name = "BOUNCE" # calculator program name, 1-8 letters or digits
|
|
63
|
+
main = "src/main.py" # default
|
|
64
|
+
target = "ce" # classic, ce, or both; default ce
|
|
65
|
+
bindir = "bin" # default
|
|
66
|
+
keep_asm = false
|
|
67
|
+
|
|
68
|
+
[tool.tipy.toolchain] # optional; the default is to search PATH
|
|
69
|
+
ce_assembler = "tools/fasmg.exe"
|
|
70
|
+
classic_assembler = "tools/spasm.exe"
|
|
71
|
+
|
|
72
|
+
[tool.tipy.flash] # used by `tipy-asm flash-app`
|
|
73
|
+
project_dir = "flash" # folder containing installer/makefile
|
|
74
|
+
optimize = "speed" # or size
|
|
75
|
+
|
|
76
|
+
[[tool.tipy.assets]] # converted into bindir by each build, when out of date
|
|
77
|
+
source = "assets/hero.png"
|
|
78
|
+
name = "HERO" # AppVar name; the default comes from the file name
|
|
79
|
+
kind = "sprite" # sprite, image, font, or binary; guessed from the suffix
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
`from settings import SPEED` includes `settings.py` from the main file's folder,
|
|
83
|
+
and `from game.player import move` includes `game/player.py`.
|
|
84
|
+
|
|
85
|
+
Image assets need Pillow: `python -m pip install "tipy-asm[images]"`. Send the
|
|
86
|
+
asset's `.8xv` to the calculator along with the program:
|
|
87
|
+
|
|
88
|
+
```python
|
|
89
|
+
from ti84 import sprite
|
|
90
|
+
hero = sprite.load("HERO") # 0 if the AppVar is missing
|
|
91
|
+
sprite.draw(hero, x, y)
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Language on the assembly targets
|
|
95
|
+
|
|
96
|
+
The Flash App backend supports more of Python. The assembly targets support:
|
|
97
|
+
|
|
98
|
+
- Functions with parameters, defaults, keyword arguments, return values, and
|
|
99
|
+
`global`. Recursion is rejected, because function variables are static.
|
|
100
|
+
- `if`/`elif`/`else`, `while`, `for ... in range()` with runtime bounds, `break`,
|
|
101
|
+
`continue`, and `exit()`.
|
|
102
|
+
- `+ - * // % << >> & | ^ ~`, comparisons, `and`, `or`, `not`, and `a if c else b`.
|
|
103
|
+
Integers are signed, 24-bit on CE and 16-bit on classic, and wrap on overflow.
|
|
104
|
+
`x // 0` is 0 and `x % 0` is `x`, because a calculator program cannot raise.
|
|
105
|
+
- Module-level arrays: `TABLE = (1, 2, 3)` is read-only, and `scores = [0] * 10`
|
|
106
|
+
is writable. Runtime indexes are not bounds-checked.
|
|
107
|
+
- `print()` of string literals and integers, and `abs`, `min`, and `max`.
|
|
108
|
+
|
|
109
|
+
Strings exist only as literals, and there are no floats, classes, or lists of
|
|
110
|
+
lists.
|
|
111
|
+
|
|
112
|
+
## Libraries
|
|
113
|
+
|
|
114
|
+
Import them with `from ti84 import graphics, keyboard`. Run `tipy-asm api NAME`
|
|
115
|
+
for each method's signature and targets. The `ti84` package also has stubs, so
|
|
116
|
+
VS Code/Pylance can complete these names.
|
|
117
|
+
|
|
118
|
+
| Library | Provides |
|
|
119
|
+
|---|---|
|
|
120
|
+
| `graphics` | Pixels, lines, rectangles, circles, triangles, text, and sprites. Coordinates and colors can be runtime values, and are clipped to the screen |
|
|
121
|
+
| `keyboard` | `read()` waits for a key, `get()` returns at once, `is_down(key)` tests a held key |
|
|
122
|
+
| `math` | `abs min max clamp sign sqrt pow sin cos`, all integer; `sin` and `cos` take degrees and scale by 256 |
|
|
123
|
+
| `random` | `seed randrange randint` |
|
|
124
|
+
| `storage`, `file` | AppVar bytes that persist between runs |
|
|
125
|
+
| `sprite` | AppVar sprites from project assets (CE only) |
|
|
126
|
+
| `color` | Color constants and conversions. On classic, colors are 0 (white) or 1 (black) |
|
|
127
|
+
| `graph` | The Flash App's graph screen (Flash App only) |
|
|
128
|
+
|
|
129
|
+
Not implemented: FontLibC fonts (`ti84.font` has only color constants, so use
|
|
130
|
+
`graphics.text()`), and scaled or rotated sprites. Calling these gives an error
|
|
131
|
+
rather than doing nothing. Text with runtime coordinates and `text_int()` need
|
|
132
|
+
the CE target. A failed `storage` read or write, such as a missing AppVar or a
|
|
133
|
+
bad offset, ends the program.
|
|
134
|
+
|
|
135
|
+
## Converting CEdev and ICE projects
|
|
136
|
+
|
|
137
|
+
```powershell
|
|
138
|
+
tipy-asm convert-project path\to\project -o converted
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
This writes a normal project, then compiles it and tells you whether it worked.
|
|
142
|
+
Code with no TIpy equivalent, such as pointers, structs, and `switch`, becomes a
|
|
143
|
+
`# TODO(convert)` comment and is listed in `CONVERSION_NOTES.md`. CEdev palette
|
|
144
|
+
indices are not RGB565 colors, so check the colors of a converted program.
|
|
145
|
+
|
|
146
|
+
## Tests
|
|
147
|
+
|
|
148
|
+
```powershell
|
|
149
|
+
python -m unittest discover -s tests
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
`tests/asm_sim.py` runs generated assembly on a model of both CPUs, with the OS
|
|
153
|
+
stubbed, and compares results with CPython. It is not an emulator, so test on
|
|
154
|
+
CEmu or a calculator as well.
|
|
155
|
+
|
|
156
|
+
## Documentation
|
|
157
|
+
|
|
158
|
+
The guide and method reference live on the
|
|
159
|
+
[`docs` branch](https://github.com/XSamuraiCoder/TIpy-asm/tree/docs). That branch holds
|
|
160
|
+
only the documentation, and this one holds only the package.
|
|
161
|
+
|
|
162
|
+
## Repository layout
|
|
163
|
+
|
|
164
|
+
- `ti84asm/` contains the compiler, runtime helpers, CLI, and build drivers.
|
|
165
|
+
- `ti84asm/toolchain/` contains the bundled [fasmg](https://flatassembler.net/) (see
|
|
166
|
+
`fasmg-license.txt`) and CE includes from
|
|
167
|
+
[CE-Programming/asm-docs](https://github.com/CE-Programming/asm-docs).
|
|
168
|
+
- `ti84libs/` contains the built-in libraries; `ti84libs/api.py` is the table of
|
|
169
|
+
public methods.
|
|
170
|
+
- `ti84/` contains the editor stubs.
|
|
171
|
+
- `examples/` contains example projects.
|
|
172
|
+
|
|
173
|
+
This fork retains the upstream [MIT license](LICENSE).
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "tipy-asm"
|
|
7
|
+
version = "1.0.0"
|
|
8
|
+
description = "TIpy-asm: Python compiler for TI-84 Z80/eZ80 calculators"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
dependencies = ["tomli>=2; python_version < '3.11'"]
|
|
12
|
+
|
|
13
|
+
[project.optional-dependencies]
|
|
14
|
+
images = ["Pillow>=10"]
|
|
15
|
+
|
|
16
|
+
[project.scripts]
|
|
17
|
+
tipy-asm = "ti84asm.cli:main"
|
|
18
|
+
ti84py = "ti84asm.cli:main"
|
|
19
|
+
convbin = "ti84asm.convbin:run_with_args"
|
|
20
|
+
convimg = "ti84asm.convimg:run_with_args"
|
|
21
|
+
convfont = "ti84asm.convfont:run_with_args"
|
|
22
|
+
|
|
23
|
+
[tool.setuptools]
|
|
24
|
+
packages = ["ti84asm", "ti84asm.project_convert", "ti84libs", "ti84"]
|
|
25
|
+
|
|
26
|
+
[tool.setuptools.package-data]
|
|
27
|
+
ti84asm = ["toolchain/bin/*", "toolchain/include/*", "toolchain/*.txt"]
|
|
28
|
+
ti84 = ["*.pyi", "py.typed"]
|
tipy_asm-1.0.0/setup.cfg
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
"""The API table, the compiler, the assembler, and the editor stubs must agree.
|
|
2
|
+
|
|
3
|
+
Run with: python -m unittest discover -s tests -v
|
|
4
|
+
"""
|
|
5
|
+
import ast
|
|
6
|
+
import subprocess
|
|
7
|
+
import tempfile
|
|
8
|
+
import unittest
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
|
|
11
|
+
from ti84asm.compiler import Compiler
|
|
12
|
+
from ti84asm.errors import CompileError
|
|
13
|
+
from ti84libs.api import API
|
|
14
|
+
|
|
15
|
+
STUBS = Path(__file__).resolve().parent.parent / "ti84"
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def program(library: str, example: str) -> str:
|
|
19
|
+
imports = sorted({library, "keyboard", "color"})
|
|
20
|
+
lines = [f"from ti84 import {name}" for name in imports]
|
|
21
|
+
return "\n".join((*lines, "x = 3", "y = 4", "z = 0", "score = 5", "hero = 0", example, ""))
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def examples():
|
|
25
|
+
for library, methods in API.items():
|
|
26
|
+
for name, method in methods.items():
|
|
27
|
+
if method.example:
|
|
28
|
+
yield library, name, method
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class ApiTableTests(unittest.TestCase):
|
|
32
|
+
def test_every_example_compiles_on_its_targets(self):
|
|
33
|
+
for library, name, method in examples():
|
|
34
|
+
for target in method.targets:
|
|
35
|
+
with self.subTest(library=library, method=name, target=target):
|
|
36
|
+
assembly = Compiler("T", target).compile(program(library, method.example))
|
|
37
|
+
self.assertNotIn("TODO", assembly)
|
|
38
|
+
|
|
39
|
+
def test_every_ce_example_assembles_with_fasmg(self):
|
|
40
|
+
from ti84asm.fasmg import ensure_ce_includes, ensure_fasmg
|
|
41
|
+
|
|
42
|
+
root, fasmg = ensure_ce_includes(), ensure_fasmg()
|
|
43
|
+
for library, name, method in examples():
|
|
44
|
+
if "ce" not in method.targets:
|
|
45
|
+
continue
|
|
46
|
+
with self.subTest(library=library, method=name), tempfile.TemporaryDirectory() as folder:
|
|
47
|
+
source, output = Path(folder) / "t.asm", Path(folder) / "t.8xp"
|
|
48
|
+
source.write_text(Compiler("T", "ce").compile(program(library, method.example)), encoding="ascii")
|
|
49
|
+
result = subprocess.run([fasmg, str(source), str(output)], cwd=root,
|
|
50
|
+
text=True, capture_output=True)
|
|
51
|
+
self.assertEqual(result.returncode, 0, result.stdout + result.stderr)
|
|
52
|
+
self.assertTrue(output.is_file())
|
|
53
|
+
|
|
54
|
+
def test_methods_unavailable_on_a_target_say_so(self):
|
|
55
|
+
for library, name, method in examples():
|
|
56
|
+
for target in {"ce", "classic"} - set(method.targets):
|
|
57
|
+
with self.subTest(library=library, method=name, target=target):
|
|
58
|
+
with self.assertRaisesRegex(CompileError, "not available on the"):
|
|
59
|
+
Compiler("T", target).compile(program(library, method.example))
|
|
60
|
+
|
|
61
|
+
def test_stubs_declare_exactly_the_public_api(self):
|
|
62
|
+
for library, methods in API.items():
|
|
63
|
+
if library == "graph":
|
|
64
|
+
continue
|
|
65
|
+
tree = ast.parse((STUBS / f"{library}.pyi").read_text(encoding="utf-8"))
|
|
66
|
+
declared = {node.name for node in tree.body if isinstance(node, ast.FunctionDef)}
|
|
67
|
+
with self.subTest(library=library):
|
|
68
|
+
self.assertTrue({name for name, method in methods.items() if method.targets} <= declared,
|
|
69
|
+
f"missing from the stub: {sorted(set(methods) - declared)}")
|
|
70
|
+
from ti84libs.api import flash_available
|
|
71
|
+
extra = {name for name in declared - set(methods) if not flash_available(library, name)}
|
|
72
|
+
self.assertFalse(extra, f"stub declares methods nothing implements: {sorted(extra)}")
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
class ErrorMessageTests(unittest.TestCase):
|
|
76
|
+
def error(self, source: str, target: str = "ce") -> str:
|
|
77
|
+
with self.assertRaises(CompileError) as caught:
|
|
78
|
+
Compiler("T", target).compile(source)
|
|
79
|
+
return str(caught.exception)
|
|
80
|
+
|
|
81
|
+
def test_misspelled_method_gets_a_suggestion(self):
|
|
82
|
+
message = self.error("from ti84 import graphics\ngraphics.pixl(1, 2)\n")
|
|
83
|
+
self.assertIn("line 2:", message)
|
|
84
|
+
self.assertIn("did you mean graphics.pixel()", message)
|
|
85
|
+
|
|
86
|
+
def test_missing_import_says_what_to_add(self):
|
|
87
|
+
self.assertIn("from ti84 import graphics", self.error("graphics.clear()\n"))
|
|
88
|
+
|
|
89
|
+
def test_misspelled_library_and_function_get_suggestions(self):
|
|
90
|
+
self.assertIn("did you mean graphics", self.error("from ti84 import grafics\n"))
|
|
91
|
+
self.assertIn("did you mean spin()", self.error("def spin():\n pass\nspinn()\n"))
|
|
92
|
+
|
|
93
|
+
def test_void_method_cannot_be_used_as_a_value(self):
|
|
94
|
+
self.assertIn("does not return a value", self.error("from ti84 import graphics\nx = graphics.clear()\n"))
|
|
95
|
+
|
|
96
|
+
def test_retired_and_flash_only_libraries_point_elsewhere(self):
|
|
97
|
+
self.assertIn("ti84.storage", self.error("from ti84 import fileioc\n"))
|
|
98
|
+
self.assertIn("flash-app", self.error("from ti84 import graph\n"))
|
|
99
|
+
|
|
100
|
+
def test_font_methods_point_to_graphics_text(self):
|
|
101
|
+
self.assertIn("graphics.text", self.error('from ti84 import font\nx = font.load("F")\n'))
|
|
102
|
+
|
|
103
|
+
def test_unsupported_syntax_names_the_feature_and_line(self):
|
|
104
|
+
message = self.error("x = 1\ny = x / 2\n")
|
|
105
|
+
self.assertTrue(message.startswith("line 2:"), message)
|
|
106
|
+
self.assertIn("true division", message)
|
|
107
|
+
|
|
108
|
+
def test_undefined_variable_gets_a_suggestion(self):
|
|
109
|
+
self.assertIn("did you mean 'score'", self.error("score = 1\nx = scor + 1\n"))
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
if __name__ == "__main__":
|
|
113
|
+
unittest.main()
|