A working TI-BASIC interpreter, written in Python.
pip install pitybas
Use pb -i vt100 to run programs which need a working home screen.
If you run pb with no filename, it launches an interactive shell.
Usage: pb [options] filename
Options:
-h, --help show this help message and exit
-a, --ast parse, print ast, and quit
-d, --dump dump variables in stacktrace
-s, --stacktrace always stacktrace
-v, --verbose verbose output
-i IO, --io=IO select an IO system: simple (default), vt100
-x, --strict raise ERR:UNDEFINED instead of silently defaulting unset variables to 0
You can also run it as a module without installing the console script:
python -m pitybas -i vt100
pitybas ships a ScriptedIO backend that lets you drive programs in tests
without touching stdin/stdout. Pass it as the io argument to
Interpreter, pre-supply canned inputs (consumed by Input, Prompt, and
Menu instructions in order), and inspect the recorded output afterwards.
from pitybas.interpret import Interpreter
from pitybas.io.scripted import ScriptedIO
vm = Interpreter.from_string(
'Input A\nDisp A*2',
io=lambda vm: ScriptedIO(vm, inputs=['21']),
)
vm.execute()
assert vm.io.disps == [42] # recorded disp outputScriptedIO also accepts a keys list for programs that poll getKey; once
the list is exhausted, getKey returns 0 (no key held), which naturally
lets timeout-based polling loops run out.
Recorded attributes:
| Attribute | Contents |
|---|---|
disps |
Values passed to Disp, in order |
outputs |
(row, col, msg) tuples from Output() calls |
clears |
Number of ClrHome calls |
- The graph screen only renders with the
vt100IO backend. Commands that draw to the TI-83/84 graph screen (e.g.Circle(,Line(,Pt-On(,Shade() update the pixel buffer under any backend, but onlyvt100(pb -i vt100) visibly renders it, as a 48x16 grid of Unicode Braille characters below the text screen. Thesimple(default) backend tracks pixel state without drawing anything. If the graph screen is still the most recently drawn-to screen when a program ends,vt100holds it and waits for a keypress before exiting, mirroring how a real TI-83/84 leaves the last screen up until dismissed; if a laterDisp/Output(/Pause/etc. switched back to the text screen first, nothing holds. Text(doesn't render visibly yet under any backend. It validates itsrow/colarguments and notifies the IO backend viadraw_text_graph, but no backend draws the glyphs: Braille's 2x4 dot resolution is too coarse for pixel-accurate small-font text (see prototyping notes on THO-16), so realvt100rendering is deferred to a follow-up.
This repository ships a uv.lock for a reproducible dev environment. Clone the
repository and install the runtime, test, and lint dependencies from the lockfile
with uv:
uv sync --all-extras
If you change dependencies in pyproject.toml, run uv lock and commit the updated
uv.lock. (Plain pip install -e ".[test,lint]" still works if you'd rather not use
uv, but it resolves unpinned versions instead of the locked ones.)
uv run pytest
Check for lint violations:
uv run ruff check src/ tests/
Fix auto-fixable violations:
uv run ruff check --fix src/ tests/
Check formatting without making changes:
uv run ruff format --check src/ tests/
Apply formatting:
uv run ruff format src/ tests/