Packages
shiny_wheat
1.0.0
Interpreter for the Wheat esoteric programming language written in Gleam.
Current section
Files
Jump to
Current section
Files
shiny_wheat
README.md
README.md
# Shiny Wheat
[](https://hex.pm/packages/shiny_wheat)
[](https://hexdocs.pm/shiny_wheat/)
An interpreter for the Wheat esoteric programming language. Written in Gleam.
## Wheat Language
Wheat is a Turing-complete esoteric language created by KeyMaker.
Keymaker has a page describing it [here](https://yiap.nfshost.com/esoteric/wheat/wheat.html), and Esolang Wiki has a page on it [here](https://esolangs.org/wiki/Wheat).
Every Wheat program runs in a loop, outputting characters and reading in characters from the previous iteration. There is no external input. Variables are named using a digit or lowercase letter, and are either empty or hold one character. Instructions are written one per line, and grouped into blocks by indentation (one space per level). String literals are wrapped in double-quotes, and there is no escape character. Q and N are also considered string literals, and represent a double-quote and newline. Empty lines and trailing whitespace are not allowed.
The language is made up of six elements:
- Comments are written as `-a comment`. They must not be indented.
- `input z` will store the next character from the previous cycles's output into the variable z.
- `output z` or `output "foo"` will output the content of a variable or a string literal.
- `if z "h":` / `if not z "h":` will execute the following block only if the variable z does / doesn't contain the letter h.
- `for-input z:` will execute the following block in a loop, taking a character from input and storing it in the variable z each time.
- `terminate` will stop execution of the program.
## Usage
By default, Shiny Wheat takes the name of the file to execute as an argument and writes output to standard out. Errors are sent to standard error. A "cycles" argument can optionally be provided, which stops the interpreter after executing a given number of loops of the program.
### Building a stand-alone executable
Gleam is required to run this project, and can be found [here](https://gleam.run).
This project uses [Gleepack](https://github.com/yoshi-monster/gleepack) to build to an executable. Run `gleam run -m gleepack build` to build for your current system. The executable will be placed in `build/shiny_wheat`.
To build for a different target: Use `gleam run -m gleepack targets available` to list the names of the available targets, then run (e.g.) `gleam run -m gleepack build --target=amd64-win32-otp-29.0.2`.
### Using as a library
The `parse_program` function can be used to create an interpreter that yields the output from each cycle. This can then be used directly (it's a `Yielder(String)`) or passed to the `run_collecting` function.
`run_collecting` takes the interpreter and a maximum number of cycles (-1 for unlimited), and produces a single string containing all output. An example is below:
```gleam
import shiny_wheat
const program = "-example program
output \" \"
input a
input b
input c
if not a \" \":
output \"-|\"
if a \" \":
output c
output b
output b
for-input d:
output d
"
pub fn main() {
let assert Ok(interpreter) = shiny_wheat.parse_program(program)
let output = shiny_wheat.run_collecting(interpreter, 8)
assert output == " -| |-- -||- |--|- -||-|- |--|-|- -||-|-|- |--|-|-|-"
}
```
## Motivation
I found Keymaker's implementation difficult to read, and wanted to try creating my own. Keymaker's implementation is also written in Python2, which is slowly becoming less accessible. I picked Gleam for novelty and legibility.
## Differences from official implementation
I tried to make this implementation match Keymaker's Python2 script, differing only in the text of error messages. However I added two small changes for convenience:
- Any whitespace after the end of the Wheat program is ignored. This means that a trailing newline (which is added automatically by many editors) is not an error.
- Lowercase "z" is a valid register. Keymaker's own description makes it pretty clear this is the intended behaviour. However the official interpreter will crash if this variable is read or written to, due to an off-by-one error.