BrainRust banner

BrainRust

11 devlogs
23h 47m 14s

This is Brainfuck interpreter written in Rust. It contains all vanilla Brainfuck commands and new added ones. I know that they are not exactly in spirit of Brainfuck, but it’s just for fun.
It is just funny project, not really for real usage.

This project uses AI

Used ChatGPT to generate ideas for few command (around 1/4) and a little for debugging.

Demo Repository

Loading README...

Q1000Q

I rewrote Readme with better wording for clarification, I made sure that the instructions how to run my project on Windows as well as on Linux are clear, also provided instruction how to build project from source, in case of the pre-built executables failure or wanting to run it on macos. Made sure to point out that comments don’t work when vanilla mode is enabled (so the // [] will hang the program for example).


I also added indicator that the input is needed from the user in terminal, that disappears when input is provided, as shown on GIF below.

Attachment
0
Q1000Q

Fixed a bug where nested brackets (for example temporary relative pointer operations command ($dist{ops}) in macro definition (@(name){ops})) was causing stack overflow.

Also made other small fixes, that went unnoticed before.

I think I’m happy with current state of the project, I’m releasing version 0.2.1 and shipping it.

Attachment
0
Q1000Q

I added:

Debug print

D command prints current pointer value, current cell and 3 before and after values in such format:

[2] 1 170 123 0 2 5
          ^

It’s main use is as the name suggests, for debugging.

If blocks

They are defined as (operations) and operations exactly once only if current cell value is other than 0.
They are basically vanilla brainfuck loops, that execute once.

Temporary relative pointer operations

They look like this: $distance{operations}. They basically move the pointer temporarily by distance and execute operations there, after that, pointer will return to its original position, no matter the additional pointer moves inside {operations} block.
The distance can also be negative.

Attachment
0
Q1000Q

First of all, I added few little extra commands:
‘:’ - Copies current cell value to the next one
‘R’ - Inserts random number to current cell
‘S’ - Sleeps the current cell value seconds

But most important, I added extended support for multiple tapes for file operations, so you can read and write from/to files that have more than 30000 characters. It was really pain in the ass to implement, all this handling empty tapes, trimming all 0’s where they can be trimmed without destroying content and tape separations, even making sure that tapes are written in order wasn’t that trivial as it seemed so, as well as making sure that it starts at tape ‘0’.

Only the f(file_path){operations} work with multiple tapes, you can of course also use a(file_path), switch tape and use it again to write multiple tapes to one file, but reading or changing can be only achieved with f command.

Attachment
0
Q1000Q

I added another maybe useful big feature: multiple tapes support and switching between them.
Every tape has its own pointer bound to it, so if you switch between, pointers stay when you last left them (by default on position 0).
There are 256 tapes available (as they are of a u8 type), you can switch between them by using Tx command where ‘x’ is any character that decodes to number 0-255 (eg. 1, a, _).

Adding this feature required from me to do little redesign of code and adding handling multiple tapes and pointers everywhere, which was little bit annoying.

Next thing to do is probably add extended support for multiple tapes in file handling and some extra small, mostly QoL features and probably ship the project.

0
Q1000Q

I added few more file operation commands:
r(file_path) - reads the content of the file, saves it to current tape, starting from current pointer location
w(file_path) - wrties the tape to file, starting from cell 0
a(file_path) - appends tape to file, starting from cell 0

While earlier added file operation command (the f(file_path){operations} format) is nice, it required all operations be done in itself, so new operations are just more convenient and they give more options.

I changed, so the paths in all file operations are relative to code file path, not user’s CWD, if you want to use CWD, just put ‘@’ before path like: f(@./CWDFile.txt){s"This is CWD relative"} and it will treat path as relative to current working directory.

I also fixed some things (mostly caused by not checking if the the code reached the end in multi character commands or moving pointer forward in number input operation when it wasn’t used correctly)

0
Q1000Q

I added macros (functions), which required me (due to the structure of my code) to learn how the lifetimes work in Rust (I still don’t know fully, but it works and that’s important).
You can define them like this: @(name){operations}
And then run them like this: #(name)

I also learnt how to use iters, because I had to rewrite some multi characters commands (they were panicking if syntax wasn’t right and they were at the end of the code).

Attachment
0
Q1000Q

Added some QoL features:
^ zeroing current cell (better than doing [-])
p printing decimal value of cell
; swapping current cell’s value with the next one’s
A printing address of current cell (value of a pointer)
// proper comments
>x / <x moving forward/backward x distance (eg. >10 goes 10 forward)

Also refactored the code, so I can make macros and tape swapping in the future with ease.

Attachment
0
Q1000Q

Added operations on files: you can use f(file_path){operations}, where operations are executed on separate tape (so the limitation is that you cannot operate on file larger than 30000 characters long, or everything after that will be deleted).
You can for example do f(file.txt){s"Hello World!"} to save “Hello World!” to file, as shown on the video.

0
Q1000Q

Added commands to set hex (0xAA), decimal (0d123) and binary (0b11001010) numbers to cells, as well as single characters (with b'x') or whole strings (s"xyz") also added command to set cell value to LFeed (\) for convenient brake line. I also added --vanilla option, to run code as vanilla Brainfuck.

Attachment
0
Q1000Q

I added all the commands from vanilla Brainfuck, written in Rust of course. It’s just a start and nothing exciting, but I need something to build from.
Now it’s time to add new commands (probably inputs like binary/decimal/hex and others), which will probably destroy spirit of Brainfuck, but I don’t care, it isn’t the point, I’m making this just for fun and to learn Rust, cuz I didn’t have a occasion to write in it before.

Attachment
0