Metadata-Version: 2.4
Name: esolangs
Version: 0.1.0
Summary: A comprehensive collection of esoteric programming language interpreters and compilers
Author-email: Bangyen Pham <bangyenp@gmail.com>
License-Expression: GPL-3.0-or-later
Project-URL: Homepage, https://github.com/bangyen/esolangs
Project-URL: Repository, https://github.com/bangyen/esolangs
Project-URL: Issues, https://github.com/bangyen/esolangs/issues
Keywords: esoteric,programming,languages,interpreters,compilers,brainfuck,esolangs
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Interpreters
Classifier: Topic :: Software Development :: Compilers
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: sympy>=1.12.0
Provides-Extra: dev
Requires-Dist: pytest>=9.0.3; extra == "dev"
Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
Requires-Dist: pytest-xdist>=3.8.0; extra == "dev"
Requires-Dist: click>=8.3.3; extra == "dev"
Requires-Dist: pygments>=2.20.0; extra == "dev"
Requires-Dist: urllib3>=2.7.0; extra == "dev"
Requires-Dist: unicorn>=2.1.4; extra == "dev"
Requires-Dist: ruff==0.16.2; extra == "dev"
Requires-Dist: mypy==2.3.0; extra == "dev"
Requires-Dist: pre-commit>=3.0.0; extra == "dev"
Requires-Dist: types-requests; extra == "dev"
Requires-Dist: types-setuptools; extra == "dev"
Dynamic: license-file

# Esolang Interpreters

[![Python](https://img.shields.io/badge/Python-3.10+-blue.svg)](https://python.org)
[![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0)
[![Coverage](coverage-badge.svg)](coverage-badge.svg)

## Table of Contents

- [About](#about)
- [Usage](#usage)
  - [Examples](#examples)
- [Implemented Languages](#implemented-languages)
- [Extra Implementations](#extra-implementations)
- [Compilers](#compilers)
- [Transpilers](#transpilers)
- [Tools](#tools)
- [Contributing](#contributing)
- [License](#license)

## About

Working interpreters, compilers, and transpilers for esoteric programming
languages, each verified against its spec.  Most interpreters read the
program file from the first command-line argument.

Planned work is tracked in [`docs/roadmap.md`](docs/roadmap.md); documented
limitations and ruled-out ideas live in [`docs/limitations.md`](docs/limitations.md),
with the full wall arguments in [`docs/walls.md`](docs/walls.md).
Annotated example programs — one per state model (tape, stack, OISC, and 2D
grid), each traced command by command — are in
[`docs/walkthroughs/`](docs/walkthroughs/).

## Usage

### Installation

```bash
git clone https://github.com/bangyen/esolangs.git
cd esolangs
just install-dev
```

### Running a Program

Interpreters run as modules, with the program file as the first argument
(categories: `grid_based`, `stack_based`, `queue_based`, `tape_based`,
`register_based`, `other`), or
through the `esolangs` command:

```bash
python -m esolangs.interpreters.<category>.<language> program.txt
esolangs run <language> program.txt
esolangs list                          # list the supported languages
esolangs generate <language> "Hello"   # print a program that outputs "Hello"
esolangs transpile BIO BF program.txt  # rewrite between languages
```

Most generators emit one long line.  `--width` (optionally `--width N`,
default 80) bounds a program to that many columns for readability — this is
how the [committed examples](examples/) are written.  Usually that means wrapping the
finished program, breaking only between whole commands so it still does the
same thing.  A generator that builds a *shape* takes the width itself
instead: Clockwise lays its code around a rectangle's perimeter, so it
picks the squarest ring that fits rather than being reflowed after the fact
(the square is also its default, since that minimises the bounding box).
Streetcode and WII2D fold their instruction line into a boustrophedon the
pointer walks in the same order, and LaserFuck steers its beam down and
back so a long run of tape commands costs rows instead of columns.

Languages whose newlines carry meaning and that cannot re-shape ignore the
flag rather than producing a broken program: the remaining 2D grid
languages, where a newline starts a new row, and NoComment, which rejects
any character that is not a command.  A single token longer than the width
(a Polynomial coefficient) gets its own line rather than being split, and a
shape with an irreducible size — a Clockwise ring, or a LaserFuck decision
tree — comes out as wide as it has to be.

Assembly compilers run the same way and write `output.asm`:

```bash
python -m esolangs.compilers.<language> program.txt
```

### Examples

Ready-to-run programs are committed under [`examples/`](examples/):
`examples/hello-world/` holds a "Hello, World!" for each of the 45
languages with a text generator, and `examples/boolean/` holds a
truth-table program for each of the 54 with a boolean generator (plus one
hand-written Minifuck program).  Both sets are regenerated by
`scripts/write_hello_world_examples.py` and
`scripts/write_boolean_examples.py`.

```bash
esolangs run Suffolk examples/hello-world/suffolk.txt
```

Annotated walkthroughs of a few representative programs live in
[`docs/walkthroughs/`](docs/walkthroughs).

### Public API

The package exposes a small typed API:

```python
import esolangs

program = esolangs.generate("Suffolk", "Hello, World!")
output = esolangs.run("Suffolk", program)
esolangs.list_languages()
bf = esolangs.transpile("BIO", "brainfuck", bio_program)
```

### Running the Tests

```bash
just test
```

## Implemented Languages

<details>
<!-- IMPLEMENTED:START -->

<summary>Show all 59 languages</summary>

The full capability matrix (generators, cross-check and boolean support, examples) is in [`docs/languages.md`](docs/languages.md).

### Grid-based Languages

Languages that move a pointer or beam across a 2D grid.

- [A Painter Ant](https://esolangs.org/wiki/A_Painter_Ant) ([code](https://github.com/bangyen/esolangs/blob/main/src/esolangs/interpreters/grid_based/a_painter_ant.py))
- [ArrowQueue](https://esolangs.org/wiki/ArrowQueue) ([code](https://github.com/bangyen/esolangs/blob/main/src/esolangs/interpreters/grid_based/arrowqueue.py))
- [COD](https://esolangs.org/wiki/COD) ([code](https://github.com/bangyen/esolangs/blob/main/src/esolangs/interpreters/grid_based/cod.py))
- [Circuit Diagram](https://esolangs.org/wiki/Circuit_Diagram) ([code](https://github.com/bangyen/esolangs/blob/main/src/esolangs/interpreters/grid_based/circuit_diagram.py))
- [Clockwise](https://esolangs.org/wiki/Clockwise) ([code](https://github.com/bangyen/esolangs/blob/main/src/esolangs/interpreters/grid_based/clockwise.py))
- [Dig](https://esolangs.org/wiki/Dig) ([code](https://github.com/bangyen/esolangs/blob/main/src/esolangs/interpreters/grid_based/dig.py))
- [Flowchart](https://esolangs.org/wiki/Flowchart) ([code](https://github.com/bangyen/esolangs/blob/main/src/esolangs/interpreters/grid_based/flowchart.py))
- [LaserFuck](https://esolangs.org/wiki/LaserFuck) ([code](https://github.com/bangyen/esolangs/blob/main/src/esolangs/interpreters/grid_based/laserfuck.py))
- [Streetcode](https://esolangs.org/wiki/Streetcode) ([code](https://github.com/bangyen/esolangs/blob/main/src/esolangs/interpreters/grid_based/streetcode.py))
- [WII2D](https://esolangs.org/wiki/WII2D) ([code](https://github.com/bangyen/esolangs/blob/main/src/esolangs/interpreters/grid_based/wii2d.py))

### Stack-based Languages

Languages that use a stack for data manipulation.

- [3x](https://esolangs.org/wiki/3x) ([code](https://github.com/bangyen/esolangs/blob/main/src/esolangs/interpreters/stack_based/three_x.py))
- [BF-PDA](https://esolangs.org/wiki/BF-PDA) ([code](https://github.com/bangyen/esolangs/blob/main/src/esolangs/interpreters/stack_based/bf_pda.py))
- [BFStack](https://esolangs.org/wiki/BFStack) ([code](https://github.com/bangyen/esolangs/blob/main/src/esolangs/interpreters/stack_based/bfstack.py))
- [Eval](https://esolangs.org/wiki/Eval) ([code](https://github.com/bangyen/esolangs/blob/main/src/esolangs/interpreters/stack_based/eval.py))
- [Forþ](https://esolangs.org/wiki/Forþ) ([code](https://github.com/bangyen/esolangs/blob/main/src/esolangs/interpreters/stack_based/forth.py))
- [Grapheme](https://esolangs.org/wiki/Grapheme) ([code](https://github.com/bangyen/esolangs/blob/main/src/esolangs/interpreters/stack_based/grapheme.py))
- [Modulous](https://esolangs.org/wiki/Modulous) ([code](https://github.com/bangyen/esolangs/blob/main/src/esolangs/interpreters/stack_based/modulous.py))
- [Unsquare](https://esolangs.org/wiki/Unsquare) ([code](https://github.com/bangyen/esolangs/blob/main/src/esolangs/interpreters/stack_based/unsquare.py))

### Queue-based Languages

Languages whose primary data structure is a queue or deque.

- [Bitdeque](https://esolangs.org/wiki/Bitdeque) ([code](https://github.com/bangyen/esolangs/blob/main/src/esolangs/interpreters/queue_based/bitdeque.py))
- [Taglate](https://esolangs.org/wiki/Taglate) ([code](https://github.com/bangyen/esolangs/blob/main/src/esolangs/interpreters/queue_based/taglate.py))

### Tape-based Languages

Languages that operate on a tape (similar to Turing machines).

- [123](https://esolangs.org/wiki/123) ([code](https://github.com/bangyen/esolangs/blob/main/src/esolangs/interpreters/tape_based/one_two_three.py))
- [3D Brainfuck](https://esolangs.org/wiki/3D_Brainfuck) ([code](https://github.com/bangyen/esolangs/blob/main/src/esolangs/interpreters/tape_based/three_d_brainfuck.py))
- [6-5](https://esolangs.org/wiki/6-5) ([code](https://github.com/bangyen/esolangs/blob/main/src/esolangs/interpreters/tape_based/six_five.py))
- [Back](https://esolangs.org/wiki/Back) ([code](https://github.com/bangyen/esolangs/blob/main/src/esolangs/interpreters/tape_based/back.py))
- [Basicfuck](https://esolangs.org/wiki/Basicfuck) ([code](https://github.com/bangyen/esolangs/blob/main/src/esolangs/interpreters/tape_based/basicfuck.py))
- [BrainIf](https://esolangs.org/wiki/BrainIf) ([code](https://github.com/bangyen/esolangs/blob/main/src/esolangs/interpreters/tape_based/brainif.py))
- [Circlefuck](https://esolangs.org/wiki/Circlefuck) ([code](https://github.com/bangyen/esolangs/blob/main/src/esolangs/interpreters/tape_based/circlefuck.py))
- [Dimensional](https://esolangs.org/wiki/Dimensional) ([code](https://github.com/bangyen/esolangs/blob/main/src/esolangs/interpreters/tape_based/dimensional.py))
- [Factor](https://esolangs.org/wiki/Factor) ([code](https://github.com/bangyen/esolangs/blob/main/src/esolangs/interpreters/tape_based/factor.py))
- [Home Row](https://esolangs.org/wiki/Home_Row) ([code](https://github.com/bangyen/esolangs/blob/main/src/esolangs/interpreters/tape_based/home_row.py))
- [Jaune](https://esolangs.org/wiki/Jaune) ([code](https://github.com/bangyen/esolangs/blob/main/src/esolangs/interpreters/tape_based/jaune.py))
- [Minifuck](https://esolangs.org/wiki/Minifuck) ([code](https://github.com/bangyen/esolangs/blob/main/src/esolangs/interpreters/tape_based/minifuck.py))
- [NoComment](https://esolangs.org/wiki/NoComment) ([code](https://github.com/bangyen/esolangs/blob/main/src/esolangs/interpreters/tape_based/nocomment.py))
- [Painfuck](https://esolangs.org/wiki/Painfuck) ([code](https://github.com/bangyen/esolangs/blob/main/src/esolangs/interpreters/tape_based/painfuck.py))
- [ROTfuck](https://esolangs.org/wiki/ROTfuck) ([code](https://github.com/bangyen/esolangs/blob/main/src/esolangs/interpreters/tape_based/rotfuck.py))
- [S*bleq](https://esolangs.org/wiki/S*bleq) ([code](https://github.com/bangyen/esolangs/blob/main/src/esolangs/interpreters/tape_based/sbleq.py))
- [SLOW ACV MAMMALIAN](https://esolangs.org/wiki/SLOW_ACV_MAMMALIAN) ([code](https://github.com/bangyen/esolangs/blob/main/src/esolangs/interpreters/tape_based/slow_acv_mammalian.py))
- [Suffolk](https://esolangs.org/wiki/Suffolk) ([code](https://github.com/bangyen/esolangs/blob/main/src/esolangs/interpreters/tape_based/suffolk.py))
- [bit~](https://esolangs.org/wiki/bit~) ([code](https://github.com/bangyen/esolangs/blob/main/src/esolangs/interpreters/tape_based/bit_tilde.py))
- [brainfuck](https://esolangs.org/wiki/brainfuck) ([code](https://github.com/bangyen/esolangs/blob/main/src/esolangs/interpreters/tape_based/brainfuck.py))

### Register-based Languages

Languages that use registers to store and manipulate data.

- [%^2^-1](https://esolangs.org/wiki/%^2^-1) ([code](https://github.com/bangyen/esolangs/blob/main/src/esolangs/interpreters/register_based/pct_squared_minus_one.py))
- [AddSubJump](https://esolangs.org/wiki/AddSubJump) ([code](https://github.com/bangyen/esolangs/blob/main/src/esolangs/interpreters/register_based/addsubjump.py))
- [BIO](https://esolangs.org/wiki/BIO) ([code](https://github.com/bangyen/esolangs/blob/main/src/esolangs/interpreters/register_based/bio.py))
- [Between](https://esolangs.org/wiki/Between) ([code](https://github.com/bangyen/esolangs/blob/main/src/esolangs/interpreters/register_based/between.py))
- [Collatz Multiverse](https://esolangs.org/wiki/Collatz_Multiverse) ([code](https://github.com/bangyen/esolangs/blob/main/src/esolangs/interpreters/register_based/collatz_multiverse.py))
- [Decleq](https://esolangs.org/wiki/Decleq) ([code](https://github.com/bangyen/esolangs/blob/main/src/esolangs/interpreters/register_based/decleq.py))
- [Minsky Swap](https://esolangs.org/wiki/Minsky_Swap) ([code](https://github.com/bangyen/esolangs/blob/main/src/esolangs/interpreters/register_based/minsky_swap.py))
- [MyScript](https://esolangs.org/wiki/MyScript) ([code](https://github.com/bangyen/esolangs/blob/main/src/esolangs/interpreters/register_based/myscript.py))
- [Nevermind](https://esolangs.org/wiki/Nevermind) ([code](https://github.com/bangyen/esolangs/blob/main/src/esolangs/interpreters/register_based/nevermind.py))
- [Point Break](https://esolangs.org/wiki/Point_Break) ([code](https://github.com/bangyen/esolangs/blob/main/src/esolangs/interpreters/register_based/point_break.py))
- [Polynomial](https://esolangs.org/wiki/Polynomial) ([code](https://github.com/bangyen/esolangs/blob/main/src/esolangs/interpreters/register_based/polynomial.py))
- [Qoibl](https://esolangs.org/wiki/Qoibl) ([code](https://github.com/bangyen/esolangs/blob/main/src/esolangs/interpreters/register_based/qoibl.py))
- [RAM0](https://esolangs.org/wiki/RAM0) ([code](https://github.com/bangyen/esolangs/blob/main/src/esolangs/interpreters/register_based/ram0.py))
- [Sophie](https://esolangs.org/wiki/Sophie) ([code](https://github.com/bangyen/esolangs/blob/main/src/esolangs/interpreters/register_based/sophie.py))

### Other Languages

Languages that don't fit into the above categories.

- [Container](https://esolangs.org/wiki/Container) ([code](https://github.com/bangyen/esolangs/blob/main/src/esolangs/interpreters/other/container.py))
- [Forbin](https://esolangs.org/wiki/Forbin) ([code](https://github.com/bangyen/esolangs/blob/main/src/esolangs/interpreters/other/forbin.py))
- [Lamfunc](https://esolangs.org/wiki/Lamfunc) ([code](https://github.com/bangyen/esolangs/blob/main/src/esolangs/interpreters/other/lamfunc.py))
- [Suptiftam](https://esolangs.org/wiki/Suptiftam) ([code](https://github.com/bangyen/esolangs/blob/main/src/esolangs/interpreters/other/suptiftam.py))
- [ZTOALC L](https://esolangs.org/wiki/ZTOALC_L) ([code](https://github.com/bangyen/esolangs/blob/main/src/esolangs/interpreters/other/ztoalc_l.py))

<!-- IMPLEMENTED:END -->

</details>

## Extra Implementations

<details>
<!-- EXTRA:START -->

<summary>Show all 13 implementations</summary>

Implementations written in languages other than Python, used as cross-check references in CI: most generators are round-trip verified against them.  The cross-checks share an exit-code convention mirroring the Python interpreters: 0 = success, 2 = malformed program, 3 = invalid runtime operation.

### RISC-V Assembly Implementations

- [BF-PDA](https://esolangs.org/wiki/BF-PDA)
- [BIO](https://esolangs.org/wiki/BIO)
- [Minsky Swap](https://esolangs.org/wiki/Minsky_Swap)
- [NoComment](https://esolangs.org/wiki/NoComment)
- [RAM0](https://esolangs.org/wiki/RAM0)

### Rust Implementations

- [%^2^-1](https://esolangs.org/wiki/%25%5E2%5E-1)
- [3x](https://esolangs.org/wiki/3x)
- [Basicfuck](https://esolangs.org/wiki/Basicfuck)
- [bit~](https://esolangs.org/wiki/Bit~)
- [Forþ](https://esolangs.org/wiki/For%C3%BE)
- [LaserFuck](https://esolangs.org/wiki/LaserFuck)
- [Painfuck](https://esolangs.org/wiki/Painfuck)
- [Unsquare](https://esolangs.org/wiki/Unsquare)

<!-- EXTRA:END -->

</details>

Two further bodies of work live under `extra/` without being cross-check
interpreters, so they are not listed above:

- **Lean 4 proofs** (`extra/lean/esolangs`) verify generators rather than
  run programs: that the MAMMALIAN text generator is total over the byte
  range, that the Factor encoder round-trips (`decode (encode code) = code`),
  and that the brainfuck minterm boolean generator computes its truth table.
  `lake build` checks them, and CI runs them on Linux.
- **Line** (`extra/line`) implements
  [Line](https://esolangs.org/wiki/Line), whose spec is a set of hand-drawn
  curve images with no text format.  Its programs are PNGs rather than text,
  so it cannot go through the registry's pipeline; it keeps its own renderer,
  pixel extractor, and interpreter, plus brainfuck and boolean generators
  that target it.  `just test-line` runs its suites.

## Compilers

<details>
<!-- COMPILERS:START -->

<summary>Show all 12 compilers</summary>

Compilers that translate esoteric languages to other target languages.

### RISC-V Assembly Compilers

- [AddSubJump](https://esolangs.org/wiki/AddSubJump)
- [BF-PDA](https://esolangs.org/wiki/BF-PDA)
- [BFStack](https://esolangs.org/wiki/BFStack)
- [Collatz Multiverse](https://esolangs.org/wiki/Collatz_Multiverse)
- [Decleq](https://esolangs.org/wiki/Decleq)
- [Forþ](https://esolangs.org/wiki/Forþ)
- [Home Row](https://esolangs.org/wiki/Home_Row)
- [Jaune](https://esolangs.org/wiki/Jaune)
- [RAM0](https://esolangs.org/wiki/RAM0)
- [S*bleq](https://esolangs.org/wiki/S*bleq)
- [Suffolk](https://esolangs.org/wiki/Suffolk)
- [Unsquare](https://esolangs.org/wiki/Unsquare)

<!-- COMPILERS:END -->

</details>

## Transpilers

Transpilers rewrite a program in one esolang into an equivalent program in another, and are verified end-to-end: the source runs on its interpreter, the translation runs on the target interpreter, and the outputs must agree.

| Source | Direction | Target |
| --- | :---: | --- |
| Basicfuck | → | BF |
| BF | → | Circlefuck |
| BF | → | 6-5 |
| BF | → | 3D Brainfuck |
| BF | → | Painfuck |
| BFStack | → | BF |
| BIO | → | BF |
| Decleq | → | S*bleq |
| Dimensional | → | LaserFuck |

Each transpiler's supported subset and caveats are documented in `esolangs/tools/transpilers.py`.

```bash
esolangs transpile BIO BF program.txt           # rewrite a program into another esolang
esolangs transpile Decleq "S*bleq" program.txt  # instructions must be triple-aligned
```

```python
bf = esolangs.transpile("BIO", "brainfuck", source)  # or via the API
```

The BF-to-Circlefuck pair sizes its data region automatically; pass `size`
to set it explicitly:

```python
target = esolangs.transpile("brainfuck", "Circlefuck", program, size=8)
```

## Tools

Utility programs that work with the esoteric languages.

### Boolean Function Generator

The `boolean` package builds a program that computes a truth table
(most-significant input first) in each language with suitable control flow:

```python
from esolangs.tools.boolean import (
    between,
    circlefuck_byte,
    dig,
    polynomial,
    sophie,
    suffolk,
    taglate,
)

dig("0110")  # 2-input XOR in Dig
between("0110")  # the same truth table in Between
suffolk("0110")  # and in Suffolk
sophie("0110")  # and in Sophie
polynomial("0110")  # in Polynomial (up to n = 4)
taglate("0110")  # 2-input XOR in Taglate (up to n = 2)
circlefuck_byte(table)  # arbitrary byte-valued functions
```

The truth table is a binary string of length `2**n`, indexed by the inputs
with the most significant first; its length implies the input count, so `n`
is not passed separately.  54 of the languages in the suite have such a
generator, some covering only a documented subset of tables.

### Program Generator

The `text` package builds a program that prints a given string in each
language with a text generator:

```bash
python -m esolangs.tools.text "Hello, World!"
```

Every generator is also available through `esolangs list` and
`esolangs generate` (see above); run `esolangs list` for the full set.

### Single-Interpreter Install

Want one interpreter without cloning the repo or installing the package?
`scripts/install_one.sh` fetches that language's interpreter and inlines the
shared `io` and `exceptions` modules (plus any interpreter it imports, e.g.
Factor's brainfuck) into one self-contained file:

```bash
curl -fsSL https://raw.githubusercontent.com/bangyen/esolangs/main/scripts/install_one.sh | sh -s Suffolk
python esolangs_suffolk.py program.txt
```

The language name matches `esolangs list` (e.g. `Suffolk`, `Nevermind`,
`Forþ`).  Factor and Polynomial need `pip install sympy`; the bundled file
notes this.  `scripts/bundle_one.py` does the same from a local checkout:

```bash
python scripts/bundle_one.py Nevermind
```

## Contributing

Contributions are welcome!  If you find a bug or want to add a language,
check the [roadmap](docs/roadmap.md) and [limitations](docs/limitations.md)
first, and read [CONTRIBUTING.md](CONTRIBUTING.md) — including whether the
language is worth adding — before proposing one.  New languages are
registered in `src/esolangs/registry.py`.  Run `just test` (the full local
check: lint, pytest, bandit, cargo, and the Python verify scripts) to verify
a change.

To run that check automatically on every push:

```sh
python scripts/verify.py       # run it once
git config core.hooksPath .githooks   # or run it automatically on every push
```

## License

This project is licensed under the GPL v3 License - see the [LICENSE](LICENSE) file for details.
