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.
Files changed (70) hide show
  1. tipy_asm-1.0.0/LICENSE +21 -0
  2. tipy_asm-1.0.0/PKG-INFO +185 -0
  3. tipy_asm-1.0.0/README.md +173 -0
  4. tipy_asm-1.0.0/pyproject.toml +28 -0
  5. tipy_asm-1.0.0/setup.cfg +4 -0
  6. tipy_asm-1.0.0/tests/test_api.py +113 -0
  7. tipy_asm-1.0.0/tests/test_cli.py +457 -0
  8. tipy_asm-1.0.0/tests/test_convbin.py +65 -0
  9. tipy_asm-1.0.0/tests/test_convfont.py +183 -0
  10. tipy_asm-1.0.0/tests/test_convimg.py +98 -0
  11. tipy_asm-1.0.0/tests/test_runtime.py +473 -0
  12. tipy_asm-1.0.0/ti84/__init__.py +5 -0
  13. tipy_asm-1.0.0/ti84/__init__.pyi +14 -0
  14. tipy_asm-1.0.0/ti84/color.pyi +37 -0
  15. tipy_asm-1.0.0/ti84/file.pyi +11 -0
  16. tipy_asm-1.0.0/ti84/font.pyi +13 -0
  17. tipy_asm-1.0.0/ti84/graph.pyi +4 -0
  18. tipy_asm-1.0.0/ti84/graphics.pyi +60 -0
  19. tipy_asm-1.0.0/ti84/keyboard.pyi +73 -0
  20. tipy_asm-1.0.0/ti84/math.pyi +11 -0
  21. tipy_asm-1.0.0/ti84/py.typed +1 -0
  22. tipy_asm-1.0.0/ti84/random.pyi +5 -0
  23. tipy_asm-1.0.0/ti84/sprite.pyi +10 -0
  24. tipy_asm-1.0.0/ti84/storage.pyi +11 -0
  25. tipy_asm-1.0.0/ti84asm/__init__.py +1 -0
  26. tipy_asm-1.0.0/ti84asm/__main__.py +3 -0
  27. tipy_asm-1.0.0/ti84asm/cedev_config.py +58 -0
  28. tipy_asm-1.0.0/ti84asm/cgen.py +1029 -0
  29. tipy_asm-1.0.0/ti84asm/cli.py +451 -0
  30. tipy_asm-1.0.0/ti84asm/compiler.py +1105 -0
  31. tipy_asm-1.0.0/ti84asm/convbin.py +208 -0
  32. tipy_asm-1.0.0/ti84asm/convfont.py +1073 -0
  33. tipy_asm-1.0.0/ti84asm/convimg.py +156 -0
  34. tipy_asm-1.0.0/ti84asm/errors.py +2 -0
  35. tipy_asm-1.0.0/ti84asm/fasmg.py +143 -0
  36. tipy_asm-1.0.0/ti84asm/flash_ce.py +740 -0
  37. tipy_asm-1.0.0/ti84asm/flashapp.py +100 -0
  38. tipy_asm-1.0.0/ti84asm/image.py +58 -0
  39. tipy_asm-1.0.0/ti84asm/project.py +433 -0
  40. tipy_asm-1.0.0/ti84asm/project_convert/__init__.py +19 -0
  41. tipy_asm-1.0.0/ti84asm/project_convert/c_like.py +803 -0
  42. tipy_asm-1.0.0/ti84asm/project_convert/cedev_convert.py +24 -0
  43. tipy_asm-1.0.0/ti84asm/project_convert/ice_convert.py +27 -0
  44. tipy_asm-1.0.0/ti84asm/project_convert/project_converter.py +251 -0
  45. tipy_asm-1.0.0/ti84asm/runtime.py +1043 -0
  46. tipy_asm-1.0.0/ti84asm/toolchain/bin/fasmg +0 -0
  47. tipy_asm-1.0.0/ti84asm/toolchain/bin/fasmg.exe +0 -0
  48. tipy_asm-1.0.0/ti84asm/toolchain/bin/fasmg.x64 +0 -0
  49. tipy_asm-1.0.0/ti84asm/toolchain/fasmg-license.txt +24 -0
  50. tipy_asm-1.0.0/ti84asm/toolchain/include/commands.alm +99 -0
  51. tipy_asm-1.0.0/ti84asm/toolchain/include/ez80.alm +1505 -0
  52. tipy_asm-1.0.0/ti84asm/toolchain/include/ez80.inc +2 -0
  53. tipy_asm-1.0.0/ti84asm/toolchain/include/ti84pceg.inc +6997 -0
  54. tipy_asm-1.0.0/ti84asm/toolchain/include/tiformat.inc +105 -0
  55. tipy_asm-1.0.0/ti84libs/__init__.py +107 -0
  56. tipy_asm-1.0.0/ti84libs/api.py +199 -0
  57. tipy_asm-1.0.0/ti84libs/color.py +309 -0
  58. tipy_asm-1.0.0/ti84libs/graph.py +10 -0
  59. tipy_asm-1.0.0/ti84libs/graphics.py +840 -0
  60. tipy_asm-1.0.0/ti84libs/keyboard.py +62 -0
  61. tipy_asm-1.0.0/ti84libs/math.py +45 -0
  62. tipy_asm-1.0.0/ti84libs/random.py +16 -0
  63. tipy_asm-1.0.0/ti84libs/sprite.py +32 -0
  64. tipy_asm-1.0.0/ti84libs/storage.py +56 -0
  65. tipy_asm-1.0.0/tipy_asm.egg-info/PKG-INFO +185 -0
  66. tipy_asm-1.0.0/tipy_asm.egg-info/SOURCES.txt +68 -0
  67. tipy_asm-1.0.0/tipy_asm.egg-info/dependency_links.txt +1 -0
  68. tipy_asm-1.0.0/tipy_asm.egg-info/entry_points.txt +6 -0
  69. tipy_asm-1.0.0/tipy_asm.egg-info/requires.txt +6 -0
  70. 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.
@@ -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).
@@ -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"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -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()